Jak sprawić, by Java przestrzegała limitu czasu buforowania DNS?

102

Używamy GSLB do dystrybucji geograficznej i równoważenia obciążenia. Każda usługa ma przypisaną stałą nazwę domeny. Dzięki magii DNS nazwa domeny jest przekształcana na adres IP, który jest najbliżej serwera z najmniejszym obciążeniem. Aby równoważenie obciążenia działało, serwer aplikacji musi uwzględniać TTL z odpowiedzi DNS i ponownie rozpoznać nazwę domeny po przekroczeniu limitu czasu pamięci podręcznej. Jednak nie mogłem znaleźć sposobu, aby to zrobić w Javie.

Aplikacja jest napisana w Javie 5, działającej na Linuksie (Centos 5).

ZZ Coder
źródło

Odpowiedzi:

76

Zgodnie z odpowiedzią Byrona nie można ustawić networkaddress.cache.ttlani networkaddress.cache.negative.ttljako właściwości systemu za pomocą -Dflagi lub wywołania, System.setPropertyponieważ nie są to właściwości systemu - są to właściwości zabezpieczeń .

Jeśli chcesz użyć właściwości System do wyzwalania tego zachowania (abyś mógł użyć -Dflagi lub wywołania System.setProperty), będziesz chciał ustawić następującą właściwość System :

-Dsun.net.inetaddr.ttl=0

Ta właściwość systemowa zapewni pożądany efekt.

Ale pamiętaj: jeśli nie użyjesz -Dflagi podczas uruchamiania procesu JVM i zamiast tego wybierzesz wywołanie tego z kodu:

java.security.Security.setProperty("networkaddress.cache.ttl" , "0")

Ten kod musi zostać wykonany, zanim jakikolwiek inny kod w maszynie JVM spróbuje wykonać operacje sieciowe.

Jest to ważne, ponieważ, na przykład, gdybyś Security.setPropertywywołał plik .war i wdrożył go na serwerze Tomcat, to nie zadziała: Tomcat używa stosu sieciowego Java do inicjalizacji znacznie wcześniej niż kod .war jest wykonywany. Z powodu tego „wyścigu” zwykle wygodniej jest używać -Dflagi podczas uruchamiania procesu JVM.

Jeśli nie używasz -Dsun.net.inetaddr.ttl=0lub nie dzwonisz Security.setProperty, będziesz musiał edytować $JRE_HOME/lib/security/java.securityi ustawić te właściwości zabezpieczeń w tym pliku, np

networkaddress.cache.ttl = 0
networkaddress.cache.negative.ttl = 0

Zwróć jednak uwagę na ostrzeżenia dotyczące bezpieczeństwa w komentarzach dotyczących tych nieruchomości. Rób to tylko wtedy, gdy masz wystarczającą pewność, że nie jesteś podatny na ataki polegające na spoofingu DNS .

Les Hazlewood
źródło
2
FQN to java.security.Security(przynajmniej w jdk7)
Pablo Fernandez
1
Tylko komentarz, te ostrzeżenia dotyczące bezpieczeństwa dotyczą głównie menedżerów bezpieczeństwa i zdalnego ładowania. Dla każdej normalnej aplikacji serwerowej, która ufa DNS do pewnego stopnia, zmniejszenie TTL jest w porządku. (Jednak nie sądzę, aby 0 to dobre minimum, a domyślne ustawienie 30 sekund dla menedżerów niebędących menedżerami zabezpieczeń jest w porządku w większości przypadków).
eckes
3
Czy właściwość systemu działa również z OpenJDK, czy też jest specyficzna dla Oracle?
mhlz
Nigdy więcej sprawdzania DNS po pierwszym wyszukiwaniu nie chroni Cię przed atakami podszywania się, sprawia, że ​​atak spoofing jest trwały, a nie tymczasowy.
kbolino
67

Java ma bardzo dziwne zachowanie buforowania DNS. Najlepiej jest wyłączyć buforowanie dns lub ustawić go na jakąś niską liczbę, na przykład 5 sekund.

networkaddress.cache.ttl (domyślnie: -1)
Wskazuje zasady buforowania dla pomyślnego wyszukiwania nazw w usłudze nazw. Wartość jest określana jako liczba całkowita, aby wskazać liczbę sekund buforowania pomyślnego wyszukiwania. Wartość -1 oznacza „pamięć podręczną na zawsze”.

networkaddress.cache.negative.ttl (domyślnie: 10)
Wskazuje strategię buforowania dla nieudanych wyszukiwań nazw w usłudze nazw. Wartość jest określana jako liczba całkowita, aby wskazać liczbę sekund buforowania niepowodzenia w przypadku niepowodzeń wyszukiwania. Wartość 0 oznacza „nigdy nie buforuj”. Wartość -1 oznacza „pamięć podręczną na zawsze”.

Byron Whitlock
źródło
7
Uwaga: to nie wyłącza całego buforowania DNS w twoim systemie operacyjnym. Po prostu wyłącza własne zepsute buforowanie pamięci w bibliotece. Możesz po prostu ustawić te właściwości w wierszu poleceń podczas wywoływania maszyny JVM.
Nelson
2
Nie wiem, czy „zepsuty” jest ważny. Java (ze względów bezpieczeństwa) buforuje wpisy DNS na zawsze lub do ponownego uruchomienia maszyny JVM, w zależności od tego, co nastąpi wcześniej. To (z tego, co wiem) było zamierzone. Ustawienia można wprowadzić w pliku strategii java.security lub w wierszu poleceń. Ustawienia są różne dla każdego. Źródła
Milner,
4
Zauważ, że nie możesz ustawić ich jako właściwości systemowych (tj. Używając flag -D lub System.setProperty), ponieważ nie są to właściwości systemowe - są to właściwości zabezpieczeń.
Les Hazlewood,
6
Ta dokumentacja jest nieco inna w wersji 1.7. W szczególności pamięć podręczna na zawsze ma miejsce tylko wtedy, gdy obecny jest menedżer zabezpieczeń: „Domyślnym zachowaniem jest buforowanie na zawsze po zainstalowaniu menedżera zabezpieczeń oraz buforowanie przez określony czas implementacji, gdy menedżer zabezpieczeń nie jest zainstalowany”. docs.oracle.com/javase/7/docs/technotes/guides/net/…
Brett Okken,
1
@Michael see System.getSecurityManager(). Dokumenty dla Java 8: docs.oracle.com/javase/8/docs/api/java/lang/…
gesellix
22

Zostało to oczywiście naprawione w nowszych wersjach (SE 6 i 7). Maksymalny czas buforowania wynosi 30 sekund podczas uruchamiania następującego fragmentu kodu podczas oglądania aktywności portu 53 przy użyciu tcpdump.

/**
 * http://stackoverflow.com/questions/1256556/any-way-to-make-java-honor-the-dns-caching-timeout-ttl
 *
 * Result: Java 6 distributed with Ubuntu 12.04 and Java 7 u15 downloaded from Oracle have
 * an expiry time for dns lookups of approx. 30 seconds.
 */

import java.util.*;
import java.text.*;
import java.security.*;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;

public class Test {
    final static String hostname = "www.google.com";
    public static void main(String[] args) {
        // only required for Java SE 5 and lower:
        //Security.setProperty("networkaddress.cache.ttl", "30");

        System.out.println(Security.getProperty("networkaddress.cache.ttl"));
        System.out.println(System.getProperty("networkaddress.cache.ttl"));
        System.out.println(Security.getProperty("networkaddress.cache.negative.ttl"));
        System.out.println(System.getProperty("networkaddress.cache.negative.ttl"));

        while(true) {
            int i = 0;
            try {
                makeRequest();
                InetAddress inetAddress = InetAddress.getLocalHost();
                System.out.println(new Date());
                inetAddress = InetAddress.getByName(hostname);
                displayStuff(hostname, inetAddress);
            } catch (UnknownHostException e) {
                e.printStackTrace();
            }
            try {
                Thread.sleep(5L*1000L);
            } catch(Exception ex) {}
            i++;
        }
    }

    public static void displayStuff(String whichHost, InetAddress inetAddress) {
        System.out.println("Which Host:" + whichHost);
        System.out.println("Canonical Host Name:" + inetAddress.getCanonicalHostName());
        System.out.println("Host Name:" + inetAddress.getHostName());
        System.out.println("Host Address:" + inetAddress.getHostAddress());
    }

    public static void makeRequest() {
        try {
            URL url = new URL("http://"+hostname+"/");
            URLConnection conn = url.openConnection();
            conn.connect();
            InputStream is = conn.getInputStream();
            InputStreamReader ird = new InputStreamReader(is);
            BufferedReader rd = new BufferedReader(ird);
            String res;
            while((res = rd.readLine()) != null) {
                System.out.println(res);
                break;
            }
            rd.close();
        } catch(Exception ex) {
            ex.printStackTrace();
        }
    }
}
user1050755
źródło
16
Tak, Java 1.5 miała domyślną wartość nieskończonego buforowania. Java 1.6 i 1.7 mają domyślnie 30 sekund.
Michael
7
Dokumentacja do wersji 1.7 wskazuje, że może to być prawdą tylko w przypadku braku menedżera bezpieczeństwa: „Domyślnym zachowaniem jest buforowanie na zawsze po zainstalowaniu menedżera bezpieczeństwa i buforowanie przez określony czas implementacji, gdy zabezpieczenia Menedżer nie jest zainstalowany ”. docs.oracle.com/javase/7/docs/technotes/guides/net/…
Brett Okken,
1
@Michael chce udostępnić źródło tych informacji?
rustyx
4
@rustyx JDK Oracle 1.6 i 1.7 ma to w jre / lib / security / java.security for networkaddress.cache.ttl: "# wartość domyślna to forever (FOREVER). Ze względów bezpieczeństwa to # buforowanie jest wykonywane na zawsze, gdy menedżer bezpieczeństwa jest ustawiona. Gdy menedżer zabezpieczeń # nie jest ustawiony, domyślnym zachowaniem jest buforowanie przez 30 sekund. " Aplety i aplikacje wdrożone za pośrednictwem Java Web Start nadal buforują pamięć na zawsze, w przeciwnym razie jest to 30 sekund.
Michael
1
Oto wskaźnik kodu do java.security OpenJDK 8, który mówi, że bez menedżera bezpieczeństwa TTL wynosi 30 sekund : hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/f940e7a48b72/src/share/… . Przetestowałem to na Mac OS X i Ubuntu 14.04.
tro
18

Aby rozwinąć odpowiedź Byrona, uważam, że musisz edytować plik java.securityw %JRE_HOME%\lib\securitykatalogu, aby wprowadzić tę zmianę.

Oto odpowiednia sekcja:

#
# The Java-level namelookup cache policy for successful lookups:
#
# any negative value: caching forever
# any positive value: the number of seconds to cache an address for
# zero: do not cache
#
# default value is forever (FOREVER). For security reasons, this
# caching is made forever when a security manager is set. When a security
# manager is not set, the default behavior is to cache for 30 seconds.
#
# NOTE: setting this to anything other than the default value can have
#       serious security implications. Do not set it unless 
#       you are sure you are not exposed to DNS spoofing attack.
#
#networkaddress.cache.ttl=-1 

Dokumentacja do java.securityakt tutaj .

matowe b
źródło
5
Aby to dodać, używając tomcat6 musiałem zmodyfikować mój plik lib / security, ponieważ ustawienie networkaddress.cache.ttl lub sun.net.inetaddr.ttl programowo lub za pośrednictwem zmiennej JAVA_OPTS nie działało.
bramp
1
@bramp Dzięki bracie, ja też mam ten sam problem i rozwiązałem go, używając twojego komentarza i odpowiedzi +1 dla komentarza i odpowiedzi.
Bhavik Ambani,
7

Podsumowując inne odpowiedzi, <jre-path>/lib/security/java.securitymożesz ustawić wartość właściwości, networkaddress.cache.ttlaby dostosować sposób buforowania wyszukiwania DNS. Należy zauważyć, że nie jest to właściwość systemowa, ale właściwość zabezpieczeń. Mogłem to ustawić za pomocą:

java.security.Security.setProperty("networkaddress.cache.ttl", "<value>");

Można to również ustawić we właściwości systemowej -Dsun.net.inetaddr.ttl chociaż nie spowoduje to zastąpienia właściwości zabezpieczeń, jeśli zostanie ustawiona w innym miejscu.

Chciałbym również dodać, że jeśli widzisz ten problem z usługami WWW w WebSphere, tak jak ja, ustawienie networkaddress.cache.ttlnie wystarczy. Musisz ustawić właściwość systemową disableWSAddressCachingna true. W przeciwieństwie do właściwości czasu wygaśnięcia można ją ustawić jako argument maszyny JVM lub za pośrednictwem System.setProperty).

IBM ma dość szczegółowe post jak WebSphere uchwyty buforowanie DNS tutaj . Odpowiedni fragment do powyższego to:

Aby wyłączyć buforowanie adresów dla usług WWW, należy ustawić dodatkową właściwość niestandardową JVM disableWSAddressCaching na wartość true. Użyj tej właściwości, aby wyłączyć buforowanie adresów dla usług internetowych. Jeśli system zazwyczaj działa z wieloma wątkami klienta i napotkasz rywalizację o blokady w pamięci podręcznej wsAddrCache, możesz ustawić tę właściwość niestandardową na wartość true, aby zapobiec buforowaniu danych usług sieci Web.

thesquaregroot
źródło
2

Zgodnie z oficjalnymi właściwościami java Oracle , sun.net.inetaddr.ttljest to właściwość specyficzna dla implementacji firmy Sun, która „może nie być obsługiwana w przyszłych wersjach”. „preferowanym sposobem jest użycie zabezpieczenia” networkaddress.cache.ttl.

CloudStax
źródło