2014-11-27 7 views
5

Ich versuche, einige langsame Antworten zu debuggen, die von einer auf Tomcat bereitgestellten App bereitgestellt werden. Im Moment konzentriere ich mich auf SecureRandom und /dev/random (einige der anderen möglichen Ursachen wurden untersucht und ausgeschlossen). Das Muster ist wie folgt:Langsame Serviceantwort Zeiten: Java SecureRandom &/dev/random

  • Der erste Anruf dauert genau 30,0 xy Sekunden nach Tomcat Neustart (auch wenn die Anforderung ankommt 4 Minuten nach dem Start)
  • Später nehmen einige Anrufe genau 15,0 pq Sekunden (es keine spezifische Muster, die ich aufbauen konnte, pq die Zeit ungefähre Zeit in TP99 genommen wird)

Der Service-Aufruf beinhaltet Verschlüsselung und Entschlüsselung (AES/ECB/PKCS5Padding).

Ist es möglich, dass SecureRandom init/repopulating zu diesem führt?

(Obwohl es ein Protokoll in catalina.log geschrieben ist, die "Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [28,760] milliseconds." sagt)

Auch, um zu prüfen, ob /dev/random oder /dev/urandom verwendet wird, habe ich den Test von this question. Zu meiner Überraschung sah ich im Gegensatz zu der verknüpften Frage keine Lesungen von beiden. Dies sind die letzten Zeilen aus dem strace log:

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 

Was wird dann für die Aussaat Secure verwendet?

FYI, java -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

Sie könnten versuchen, eine kleine Anwendung, die eine neue zufällige Gen erstellt (mit 'neuen SecureRandom') und lesen Sie dann einige Bytes davon, sehen, ob das liest von' Urandom'. Stellen Sie jedoch sicher, dass Sie dieselbe Java-Laufzeitumgebung als Ziel haben, und prüfen Sie, ob die Eigenschaft 'java.security.egd' nicht mit' java -D' für Tomcat festgelegt ist. –

+0

Ich habe ein Beispielprogramm (Code aus der Frage auf den Link) ausgeführt. Es wurde weder von/dev/random noch/dev/urandom gelesen, wie es in den Strate-Logs der Frage angegeben ist. –

+1

Könnten Sie auch 'jre/lib/security/java.security' überprüfen und prüfen, wie' securemandom.source' definiert ist? –

Antwort

3

Ich konnte nicht Ihre OpenJDK konkrete Version überprüfen, aber ich konnte jdk6-b33 überprüfen.

SecureRandom verwendet SeedGenerator den Samen Bytes zu erhalten

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

SeedGenerator die seedSource (String) aus SunEntries

String egdSource = SunEntries.getSeedSource(); 

SunEntries versucht wird, die Quelle von der Systemeigenschaft java.security.egd zuerst zu erhalten, wenn ist nicht gefunden dann versucht, die Eigenschaft aus der java.security Eigenschaftendatei zu erhalten, wenn die Eigenschaft ist nicht gefunden gibt eine leere Zeichenfolge zurück.

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

die SeedGenerator Prüfung dieser Wert die Instanz

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

zu initialisieren, wenn die Quelle

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

oder

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

verwendet der NativeSeedGenerator, auf Fenster s versucht, den nativen CryptoAPI auf Linux zu verwenden, die Klasse einfach die 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(); 
    } 

} 

und rufen zum Oberklassenkonstruktors erstreckt, die /dev/random standardmäßig lädt

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

so verwendet OpenJDK /dev/random standardmäßig, bis Sie tun Setzen Sie keinen anderen Wert in der Systemeigenschaft java.security.egd oder in der Eigenschaft der Sicherheitseigenschaftendatei.

Wenn Sie die Leseergebnisse mit strace sehen möchten, können Sie die Befehlszeile ändern und fügen Sie den trace=open,read Ausdruck

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

die Sie etwas sehen kann (ich habe den Test mit Oracle 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 
.... 
.... 

Der Tomcat Wiki Abschnitt für einen schnelleren Systemstart deuten auf eine nicht-blockierende Entropiequelle wie/dev/urandom verwenden, wenn Sie Verzögerungen bei der Inbetriebnahme

erleben 012.351.

Weitere Informationen: https://wiki.apache.org/tomcat/HowTo/FasterStartUp#Entropy_Source

Hoffe, das hilft.

+1

Danke für die 'Read' Traces, ich bestätige, dass das' \ dev \ urandom' in dieser JVM verwendet wird. Es gibt keine Egd Override und securerandom.source ist auch '\ dev \ urandom'.Das schließt die Möglichkeit von SecureRandom als Ursache aus und ich muss mir andere mögliche Ursachen ansehen. –

2

Das Problem ist nicht SecureRandom per se, aber das/dev/random blockiert, wenn es nicht genug Daten hat. Sie können stattdessen auch Urandom verwenden, aber das ist möglicherweise keine gute Idee, wenn Sie kryptographisch starke Zufallssamen benötigen. Auf kopflosen Linux-Systemen können Sie den angehängten Daemon installieren. Dies hält/dev/random mit genügend Daten aufgestockt, so dass Aufrufe nicht auf die Erzeugung der erforderlichen Entropie warten müssen. Ich habe dies auf einer Debian AWS-Instanz getan und beobachtete SecureRandom generateBytes Anrufe fallen von 25 Sekunden auf unter Millisekunde (Openjdk 1.7 etwas, kann nicht erinnern, speziell welche Version).

Verwandte Themen