Java가 DNS 캐싱 시간 초과를 준수하도록하는 방법은 무엇입니까?


102

우리는 지리 분산 및로드 밸런싱을 위해 GSLB를 사용합니다. 각 서비스에는 고정 도메인 이름이 할당됩니다. DNS 마술을 통해 도메인 이름은 최소한의 부하로 서버에 가장 가까운 IP로 확인됩니다. 로드 밸런싱이 작동하려면 애플리케이션 서버가 DNS 응답의 TTL을 준수하고 캐시 시간 초과시 도메인 이름을 다시 확인해야합니다. 그러나 Java에서 이것을 수행하는 방법을 찾지 못했습니다.

이 애플리케이션은 Linux (Centos 5)에서 실행되는 Java 5에 있습니다.

답변:


76

Byron의 대답에 따라 플래그 또는 호출 을 사용하여 networkaddress.cache.ttl또는 networkaddress.cache.negative.ttl시스템 속성으로 설정할 수 없습니다. 이는 시스템 속성이 아니기 때문에 보안 속성입니다.-DSystem.setProperty

System 속성을 사용하여이 동작을 트리거하려면 ( -D플래그를 사용 하거나를 호출 할 수 있습니다 System.setProperty) 다음 System 속성 을 설정해야 합니다.

-Dsun.net.inetaddr.ttl=0

이 시스템 속성은 원하는 효과를 활성화합니다.

그러나 유의하십시오 : -DJVM 프로세스를 시작할 때 플래그를 사용하지 않고 대신 코드에서 이것을 호출하도록 선택하는 경우 :

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

이 코드 JVM의 다른 코드가 네트워킹 작업을 수행하기 전에 실행 되어야합니다 .

예를 들어 Security.setProperty.war 파일 을 호출 하고 해당 .war을 Tomcat에 배포 한 경우 작동하지 않기 때문에 이는 중요 합니다. Tomcat은 Java 네트워킹 스택을 사용하여 .war의 코드가 실행되는 것보다 훨씬 일찍 자체적으로 초기화됩니다. 이 '경쟁 조건'때문에 일반적으로 -DJVM 프로세스를 시작할 때 플래그 를 사용하는 것이 더 편리합니다 .

을 사용 -Dsun.net.inetaddr.ttl=0하거나 호출 하지 않으면 해당 파일에서 보안 속성 Security.setProperty을 편집 $JRE_HOME/lib/security/java.security하고 설정 해야합니다.

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

그러나 해당 속성을 둘러싼 의견의 보안 경고에주의하십시오. DNS 스푸핑 공격에 취약하지 않다고 합리적으로 확신하는 경우에만이 작업을 수행하십시오 .


2
FQN는 java.security.Security(적어도 jdk7에서)
파블로 페르난데스

1
한마디로, 이러한 보안 경고는 대부분 보안 관리자 및 원격로드와 관련이 있습니다. DNS를 신뢰하는 일반 서버 응용 프로그램의 경우 TTL을 줄이는 것이 좋습니다. (그러나 나는 0이 좋은 최소값이고 비보안 관리자의 기본값 인 30은 대부분의 경우 괜찮다고 생각하지 않습니다.)
eckes

3
시스템 속성이 OpenJDK에서도 작동합니까 아니면 Oracle에만 적용됩니까?
mhlz 2016

첫 번째 조회 후 DNS를 다시 확인하지 않아도 스푸핑 공격으로부터 보호되지 않으며 일시적인 대신 영구적 인 스푸핑 공격을 만듭니다.
kbolino

67

Java에는 심각하게 이상한 DNS 캐싱 동작이 있습니다. 가장 좋은 방법은 DNS 캐싱을 끄거나 5 초와 같이 낮은 숫자로 설정하는 것입니다.

networkaddress.cache.ttl (기본값 : -1)
이름 서비스에서 성공적인 이름 조회를위한 캐싱 정책을 나타냅니다. 값은 성공적인 조회를 캐시하는 시간 (초)을 나타내는 정수로 지정됩니다. 값 -1은 "영구 캐시"를 나타냅니다.

networkaddress.cache.negative.ttl (기본값 : 10)
이름 서비스에서 실패한 이름 조회에 대한 캐싱 정책을 나타냅니다. 이 값은 실패한 조회에 대한 실패를 캐시하는 시간 (초)을 나타내는 정수로 지정됩니다. 0 값은 "캐시 안함"을 나타냅니다. 값 -1은 "영구 캐시"를 나타냅니다.


7
참고 : 이렇게해도 OS의 모든 DNS 캐싱이 비활성화되는 것은 아닙니다. 라이브러리에서 Java 자체의 깨진 메모리 내 캐싱을 비활성화합니다. JVM을 호출 할 때 명령 줄에서 이러한 속성을 간단히 설정할 수 있습니다.
Nelson

2
"broken"이 유효한지 모르겠습니다. Java (보안상의 이유로)는 DNS 항목을 영원히 또는 JVM이 다시 시작될 때까지 캐시합니다. 이것은 (내가 말할 수있는) 의도적으로 설계된 것입니다. 설정은 java.security 정책 파일 또는 명령 줄에서 수행 할 수 있습니다. 설정은 각각 다릅니다. 참조 : rgagnon.com/javadetails/java-0445.html
Milner

4
시스템 속성이 아니기 때문에 시스템 속성 (즉, -D 플래그 또는 System.setProperty 사용)으로 설정할 수 없습니다. 보안 속성입니다.
Les Hazlewood 2013-06-20

6
이 문서는 1.7에서 약간 다릅니다. 특히, 영구 캐시는 보안 관리자가있는 경우에만 발생합니다. "기본 동작은 보안 관리자가 설치 될 때 영구 캐시하고 보안 관리자가 설치되지 않은 경우 구현 특정 기간 동안 캐시하는 것입니다." docs.oracle.com/javase/7/docs/technotes/guides/net/…
Brett Okken 2014-06-12

1
@Michael 참조 System.getSecurityManager(). Java 8 용 문서 : docs.oracle.com/javase/8/docs/api/java/lang/…
gesellix

22

이것은 최신 릴리스 (SE 6 및 7)에서 분명히 수정되었습니다. tcpdump를 사용하여 포트 53 활동을 보면서 다음 코드 스 니펫을 실행할 때 최대 30 초의 캐싱 시간이 발생합니다.

/**
 * 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();
        }
    }
}

16
예, Java 1.5의 기본값은 무한 캐싱입니다. Java 1.6 및 1.7의 기본값은 30 초입니다.
Michael

7
1.7에 대한 문서는 보안 관리자가없는 경우에만 해당 될 수 있음을 나타냅니다. "기본 동작은 보안 관리자가 설치 될 때 영구적으로 캐시하고 보안이 실행될 때 구현 특정 기간 동안 캐시하는 것입니다. 관리자가 설치되어 있지 않습니다. " docs.oracle.com/javase/7/docs/technotes/guides/net/…
Brett Okken 2014-06-12

1
@Michael이 해당 정보의 출처를 공유하고 싶으십니까?
rustyx 2014 년

4
@rustyx Oracle의 1.6 및 1.7 JDK에는 networkaddress.cache.ttl에 대한 jre / lib / security / java.security에 다음이 있습니다. "# 기본값은 영원히 (FOREVER)입니다. 보안상의 이유로이 # 캐싱은 보안 관리자가 보안 # 관리자가 설정되지 않은 경우 기본 동작은 30 초 동안 캐시하는 것입니다. " 따라서 Java Web Start를 통해 배포 된 애플릿과 앱은 계속 캐시됩니다. 그렇지 않으면 30 초가 걸립니다.
Michael

1
다음은 OpenJDK 8의 java.security에 대한 코드 포인터입니다. 보안 관리자가 없으면 TTL이 30 초라고 말합니다. hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/f940e7a48b72/src/share/… . Mac OS X 및 Ubuntu 14.04에서 테스트했습니다.
tro

18

Byron의 답변을 확장하려면 이 변경 사항을 적용 java.security하려면 %JRE_HOME%\lib\security디렉토리 의 파일을 편집해야합니다 .

관련 섹션은 다음과 같습니다.

#
# 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 

여기java.security파일 에 대한 문서가 있습니다 .


5
여기에 추가하려면 tomcat6을 사용할 때 내 lib / security 파일을 수정해야했습니다. networkaddress.cache.ttl 또는 sun.net.inetaddr.ttl을 프로그래밍 방식으로 설정하거나 JAVA_OPTS 변수를 통해 설정하는 것이 작동하지 않았기 때문입니다.
bramp 2011-07-20

1
@bramp 감사합니다 형제 님, 저도 같은 문제에 직면하고 있으며 댓글과 답변에 대해 귀하의 댓글과 답변 +1을 사용하여 해결되었습니다.
Bhavik Ambani 2015 년

7

다른 답변을 요약하면 <jre-path>/lib/security/java.security에서 속성 값을 설정하여 networkaddress.cache.ttlDNS 조회가 캐시되는 방식을 조정할 수 있습니다. 이 유의 하지 시스템 프로퍼티하지만 보안 속성입니다. 나는 이것을 사용하여 설정할 수 있었다.

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

-Dsun.net.inetaddr.ttl다른 곳에 설정되어있는 경우 보안 속성을 재정의하지 않지만 시스템 속성 으로도 설정할 수 있습니다.

또한 저와 마찬가지로 WebSphere의 웹 서비스에서이 문제가 발생하면 설정 networkaddress.cache.ttl만으로는 충분하지 않다는 점을 추가하고 싶습니다 . 시스템 속성 disableWSAddressCaching을 로 설정해야합니다 true. TTL (Time-to-Live) 속성과 달리 이것은 JVM 인수 또는를 통해 설정할 수 있습니다 System.setProperty.

IBM은 여기에 WebSphere가 DNS 캐싱을 처리하는 방법에 대한 자세한 게시물을 가지고 있습니다 . 위의 관련 부분은 다음과 같습니다.

웹 서비스에 대한 주소 캐싱을 사용하지 않으려면 추가 JVM 사용자 정의 특성 disableWSAddressCaching을 true로 설정해야합니다. 이 속성을 사용하여 웹 서비스에 대한 주소 캐싱을 비활성화합니다. 시스템이 일반적으로 많은 클라이언트 스레드로 실행되고 wsAddrCache 캐시에서 잠금 경합이 발생하는 경우이 사용자 정의 특성을 true로 설정하여 웹 서비스 데이터의 캐싱을 방지 할 수 있습니다.


2

에 따르면 공식 오라클 자바 속성 , sun.net.inetaddr.ttl"향후 릴리스에서 지원되지 않을 수 있습니다"일 구현 고유의 속성이다. "선호하는 방법은 보안 속성을 사용하는 것입니다" networkaddress.cache.ttl.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.