2014-11-27 5 views
5

Tomcat에 배포 된 응용 프로그램에서 제공하는 느린 응답을 디버깅하려고합니다. 지금 나는 SecureRandom/dev/random에 초점을 맞추고 있습니다 (다른 가능한 원인 중 일부가 조사되어 배제되었습니다). 다음과 같이 패턴은 다음과 같습니다 느린 서비스 응답 시간 : Java SecureRandom &/dev/random

  • 나중에 (요청이 시작 이후에 5 분에 도착하더라도)

    • 첫 번째 호출은 30.0 XY 초 Tomcat을 다시 시작한 후 정확히 소요, 일부 통화는 정확히 15.0 받아 PQ 초 (TP99에 걸리는 시간 대략적인 시간 인 나는 확립 할 수없는 특정 패턴, PQ이 없었다)

    서비스 요청 암호화를 포함하고 암호 해독 (AES/ECB/PKCS5Padding).

    SecureRandom 초기화/재개발로 인해이 문제가 발생할 수 있습니까?

    /dev/random 또는 /dev/urandom가 사용되고 있는지 여부를 확인하기 위해,

    또한 (비록, "Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [28,760] milliseconds." 말한다 catalina.log 작성된 로그있어), I는 this question에서 테스트를 사용 하였다. 놀랍게도, 나는 링크 된 질문에서 일어나는 것과는 달리 그들 중 어느 쪽에서도 읽는 것을 보지 못했습니다. 다음 SecureRandom의 시드 무엇을

    3561 lstat("/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/jre/lib/jsse.jar", {st_mode=S_IFREG|0644, st_size=258525, ...}) = 0 
    3561 open("/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/jre/lib/jsse.jar", O_RDONLY) = 6 
    3561 stat("/dev/random", {st_mode=S_IFCHR|0666, st_rdev=makedev(1, 8), ...}) = 0 
    3561 stat("/dev/urandom", {st_mode=S_IFCHR|0666, st_rdev=makedev(1, 9), ...}) = 0 
    3561 open("/dev/random", O_RDONLY)  = 7 
    3561 open("/dev/urandom", O_RDONLY) = 8 
    3561 unlink("/tmp/hsperfdata_xxxx/3560") = 0 
    

    을 사용하고 있습니다 : 다음은 strace 로그에서 마지막 몇 줄은?

    참고로, 자바 -version

    java version "1.6.0_32" 
    OpenJDK Runtime Environment (IcedTea6 1.13.4) (rhel-7.1.13.4.el6_5-x86_64) 
    OpenJDK 64-Bit Server VM (build 23.25-b01, mixed mode) 
    
  • +0

    'new SecureRandom'을 사용하여 새로운 랜덤 gen을 생성 한 작은 응용 프로그램을 시도해 볼 수 있습니다. 그리고 나서'urandom'에서 읽었는지 확인하십시오. 그래도 동일한 자바 런타임을 대상으로하고 Tomcat에'java -D'를 사용하여 java.security.egd 속성이 설정되어 있지 않은지 확인하십시오. –

    +0

    샘플 프로그램 (링크의 질문에서 가져온 코드)을 실행했습니다. 질문에 첨부 된 strace 로그에 표시된대로/dev/random이나/dev/urandom에서 읽지 않습니다. –

    +1

    ''jre/lib/security/java.security'를 확인하고'securerandom.source'가 어떻게 정의되어 있는지 확인할 수 있습니까? –

    답변

    3

    나는 당신의 오픈 JDK 구체적인 버전을 확인할 수없는,하지만 난 jdk6-b33을 확인할 수 있습니다. 경우

    SecureRandom

    , 시스템 속성에서 소스 java.security.egd 첫째을 얻을 수 SunEntries

    String egdSource = SunEntries.getSeedSource(); 
    

    SunEntries 시도에서 SeedGenerator가 seedSource (String)를 얻을 수

    public byte[] engineGenerateSeed(int numBytes) { 
        byte[] b = new byte[numBytes]; 
        SeedGenerator.generateSeed(b); 
        return b; 
    } 
    

    씨앗 바이트를 얻을 수 SeedGenerator를 사용 속성이없는 경우 속성 파일 을 java.security 속성 파일에서 가져 오려고합니다. 찾을 수 없습니다 빈 문자열을 반환합니다.소스

    final static String URL_DEV_RANDOM = "file:/dev/random"; 
    

    또는

    final static String URL_DEV_URANDOM = "file:/dev/urandom" 
    

    NativeSeedGenerator 사용하는 경우

    // name of the *System* property, takes precedence over PROP_RNDSOURCE 
    private final static String PROP_EGD = "java.security.egd"; 
    // name of the *Security* property 
    private final static String PROP_RNDSOURCE = "securerandom.source"; 
    
    final static String URL_DEV_RANDOM = "file:/dev/random"; 
    final static String URL_DEV_URANDOM = "file:/dev/urandom"; 
    
    private static final String seedSource; 
    
    static { 
        seedSource = AccessController.doPrivileged(
          new PrivilegedAction<String>() { 
    
         public String run() { 
          String egdSource = System.getProperty(PROP_EGD, ""); 
          if (egdSource.length() != 0) { 
           return egdSource; 
          } 
          egdSource = Security.getProperty(PROP_RNDSOURCE); 
          if (egdSource == null) { 
           return ""; 
          } 
          return egdSource; 
         } 
        }); 
    } 
    

    SeedGenerator 확인이 값은 윈도우에

    // Static instance is created at link time 
    private static SeedGenerator instance; 
    
    private static final Debug debug = Debug.getInstance("provider"); 
    
    final static String URL_DEV_RANDOM = SunEntries.URL_DEV_RANDOM; 
    final static String URL_DEV_URANDOM = SunEntries.URL_DEV_URANDOM; 
    
    // Static initializer to hook in selected or best performing generator 
    static { 
        String egdSource = SunEntries.getSeedSource(); 
    
        // Try the URL specifying the source 
        // e.g. file:/dev/random 
        // 
        // The URL file:/dev/random or file:/dev/urandom is used to indicate 
        // the SeedGenerator using OS support, if available. 
        // On Windows, the causes MS CryptoAPI to be used. 
        // On Solaris and Linux, this is the identical to using 
        // URLSeedGenerator to read from /dev/random 
    
        if (egdSource.equals(URL_DEV_RANDOM) || egdSource.equals(URL_DEV_URANDOM)) { 
         try { 
          instance = new NativeSeedGenerator(); 
          if (debug != null) { 
           debug.println("Using operating system seed generator"); 
          } 
         } catch (IOException e) { 
          if (debug != null) { 
           debug.println("Failed to use operating system seed " 
               + "generator: " + e.toString()); 
          } 
         } 
        } else if (egdSource.length() != 0) { 
         try { 
          instance = new URLSeedGenerator(egdSource); 
          if (debug != null) { 
           debug.println("Using URL seed generator reading from " 
               + egdSource); 
          } 
         } catch (IOException e) { 
          if (debug != null) 
           debug.println("Failed to create seed generator with " 
               + egdSource + ": " + e.toString()); 
         } 
        } 
    
        // Fall back to ThreadedSeedGenerator 
        if (instance == null) { 
         if (debug != null) { 
          debug.println("Using default threaded seed generator"); 
         } 
         instance = new ThreadedSeedGenerator(); 
        } 
    } 
    

    을 인스턴스를 초기화 당신이 할 때까지의 기본 그래서

    URLSeedGenerator() throws IOException { 
        this(SeedGenerator.URL_DEV_RANDOM); 
    } 
    

    에 의해 /dev/random을로드하는 슈퍼 클래스 생성자에 클래스가 단순히 SeedGenerator.URLSeedGenerator

    package sun.security.provider; 
    
    import java.io.IOException; 
    
    /** 
    * Native seed generator for Unix systems. Inherit everything from 
    * URLSeedGenerator. 
    * 
    */ 
    class NativeSeedGenerator extends SeedGenerator.URLSeedGenerator { 
    
        NativeSeedGenerator() throws IOException { 
         super(); 
        } 
    
    } 
    

    를 확장 리눅스에 기본 CryptoAPI를 사용하여 호출하려고, 오픈 JDK는 기본적으로 /dev/random를 사용 시스템 속성 java.security.egd 또는 보안 등록 정보 파일의 등록 정보 securerandom.source에 다른 값을 설정하지 마십시오.

    당신이이 같은 것을 볼 수 있습니다

    sudo strace -o a.strace -f -e trace=open,read java class 
    

    trace=open,read 표현 당신이 명령 줄을 변경할 수 있습니다 strace를 사용하여 읽기 결과를보고 추가 할 경우 (내가 그랬어 오라클 JDK 6 테스트)

    13225 open("/dev/random", O_RDONLY)  = 8 
    13225 read(8, "@", 1)     = 1 
    13225 read(3, "PK\3\4\n\0\0\0\0\0RyzB\36\320\267\325u\4\0\0u\4\0\0 \0\0\0", 30) = 30 
    .... 
    .... 
    
    빠른 시작을위한

    톰캣 위키 섹션이 시작하는 동안 지연이 발생하는 경우는/dev/urandom을 같은 비 차단 엔트로피 소스를 사용하는 것이 좋습니다

    자세한 정보 : https://wiki.apache.org/tomcat/HowTo/FasterStartUp#Entropy_Source

    희망이 있습니다.

    +1

    'read '추적을 주셔서 감사 드리며,이 JVM에서'\ dev \ urandom'이 사용되고 있음을 확인합니다. egd override는 없으며 securerandom.source 또한'\ dev \ urandom'입니다.따라서 SecureRandom이 원인이 될 가능성을 배제하고 다른 가능한 원인을 조사해야합니다. –

    2

    문제는 SecureRandom 그 자체가 아니고 충분한 데이터가없는 경우/dev/random 블록입니다. 대신에 urandom을 사용할 수는 있지만 암호 학적으로 강력한 임의의 시드가 필요한 경우에는 좋은 생각이 아닐 수도 있습니다. 헤드리스 Linux 시스템에서는 hadged 데몬을 설치할 수 있습니다. 이렇게하면/dev/random이 충분한 데이터로 꽉 차 있기 때문에 호출이 필요한 엔트로피가 생성 될 때까지 기다릴 필요가 없습니다. 데비안 Aws 인스턴스에서이 작업을 수행했으며 SecureRandom generateBytes 호출이 25 초에서 3 밀리 초 (Openjdk 1.7 이상, 특정 버전 기억이 안됨)로 떨어지는 것을 보았습니다.