Ein Modul, das ich zu unserer großen Java-Anwendung hinzufüge, muss sich mit der SSL-gesicherten Website eines anderen Unternehmens unterhalten. Das Problem besteht darin, dass die Site ein selbstsigniertes Zertifikat verwendet. Ich habe eine Kopie des Zertifikats, um zu verifizieren, dass ich keinen Man-in-the-Middle-Angriff erlebe, und ich muss dieses Zertifikat so in unseren Code einbinden, dass die Verbindung zum Server erfolgreich ist.Wie kann ich verschiedene Zertifikate für bestimmte Verbindungen verwenden?
Hier ist der Grundcode:
void sendRequest(String dataPacket) {
String urlStr = "https://host.example.com/";
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setMethod("POST");
conn.setRequestProperty("Content-Length", data.length());
conn.setDoOutput(true);
OutputStreamWriter o = new OutputStreamWriter(conn.getOutputStream());
o.write(data);
o.flush();
}
Ohne zusätzliche Behandlung an Ort und Stelle für das selbst signiertes Zertifikat, das bei conn.getOutputStream stirbt() mit folgenden Ausnahme:
Exception in thread "main" javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
....
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
....
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
Idealer Mein Code muss Java beibringen, dieses selbstsignierte Zertifikat zu akzeptieren, für diesen einen Punkt in der Anwendung und nirgendwo sonst.
Ich weiß, dass ich das Zertifikat in den Zertifikatsautoritätsspeicher der JRE importieren kann, und das erlaubt Java, es zu akzeptieren. Das ist kein Ansatz, den ich machen möchte, wenn ich helfen kann. es scheint sehr invasiv zu sein, auf allen Maschinen unserer Kunden für ein Modul zu arbeiten, das sie nicht benutzen können; Es würde alle anderen Java-Anwendungen betreffen, die dieselbe JRE verwenden, und das mag ich nicht, obwohl die Wahrscheinlichkeit, dass eine andere Java-Anwendung jemals auf diese Site zugreift, gleich Null ist. Es ist auch keine triviale Operation: Unter UNIX muss ich Zugriffsrechte erhalten, um die JRE auf diese Weise zu modifizieren.
Ich habe auch gesehen, dass ich eine TrustManager-Instanz erstellen kann, die einige benutzerdefinierte Überprüfung durchführt. Es sieht so aus, als könnte ich sogar einen TrustManager erstellen, der in allen Instanzen mit Ausnahme dieses einen Zertifikats an den echten TrustManager delegiert. Aber es sieht so aus, als ob TrustManager global installiert wird, und ich nehme an, dass dies Auswirkungen auf alle anderen Verbindungen unserer Anwendung haben würde, und das riecht auch nicht richtig für mich.
Was ist der bevorzugte, standardmäßige oder beste Weg, eine Java-Anwendung so einzurichten, dass ein selbstsigniertes Zertifikat akzeptiert wird? Kann ich alle oben genannten Ziele erreichen, oder muss ich Kompromisse eingehen? Gibt es eine Option für Dateien und Verzeichnisse und Konfigurationseinstellungen und wenig bis gar keinen Code?
kleine, Arbeitsfix: http://www.rgagnon.com/javadetails/java-fix-certificate-problem-in-HTTPS.html –
@Hasenpriester: bitte nicht diese Seite vorschlagen. Es deaktiviert die Vertrauensverifizierung. Sie akzeptieren nicht nur das selbstsignierte Zertifikat, das Sie möchten, sondern Sie akzeptieren auch jedes Zertifikat, das ein MITM-Angreifer Ihnen präsentiert. – Bruno