Lekce 17 - HTTPS v Javě
V minulé lekci, Knihovna Jsoup v Javě - Pokročilé vyhledávání, jsme si ukázali, jak lze pracovat například s obrázky, odkazy či atributy v html dokumentu pomocí Java knihovny Jsoup.
V tomto článku si ukážeme, jak funguje ověřování serverových SSL/TLS certifikátů a kde jsou uloženy certifikáty důvěryhodných autorit.
Načtení dat z protokolu HTTPS
K práci s protokolem HTTPS (Hypertext Transfer Protocol Secure) lze podobně
jako v případě HTTP použít třídy z balíku java.net
.
Potřebujeme-li například z nějakého serveru stáhnout webovou stránku
přes HTTPS, stačí vytvořit objekt java.net.URL
s požadovanou
adresou, otevřít spojení a z příslušného objektu InputStream
přečíst data:
String address = "https://www.google.com"; URL url = new URL(address); URLConnection connection = url.openConnection(); InputStream in = null; ByteArrayOutputStream out = new ByteArrayOutputStream(); try { in = connection.getInputStream(); byte[] buffer = new byte[8192]; int size; while ((size = in.read(buffer)) != -1) { out.write(buffer, 0, size); } } finally { if (in != null) { in.close(); } } String content = out.toString("UTF-8");
Kód výše funguje za předpokladu, že je HTTPS server resp. jeho
certifikát považován za důvěryhodný. Není-li tomu tak, spojení selže a
dojde k vyhození výjimky javax.net.ssl.SSLHandshakeException
:
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
Podívejme se tedy blíže na serverové SSL/TLS certifikáty, kde jsou uloženy certifikáty důvěryhodných autorit a na možnosti ošetření této výjimky.
Certifikační cesta
Aby byl certifikát serveru považován za důvěryhodný, musí být vydán důvěryhodnou certifikační autoritou. Certifikát certifikační autority vydává buď certifikační autorita sama, v tomto případě se jedná o kořenovou certifikační autoritu, nebo její nadřízená certifikační autorita.
Certifikáty tvoří tzv. řetězec (chain) resp. certifikační cestu (certification path), kde na jednom konci stojí certifikát kořenové certifikační autority, na druhém konci certifikát serveru a mezi nimi se nachází libovolný počet certifikátů podřízených certifikačních autorit.
Truststore
Certifikáty důvěryhodných certifikačních autorit jsou v Javě uloženy v úložišti důvěryhodných certifikátů, v tzv. truststore.
Výchozím úložištěm důvěryhodných certifikátů je soubor
cacerts
v adresáři
C:\Program Files\Java\jre7\lib\security
. Umístění adresáře se
může lišit podle verze JRE. Certifikáty jsou uloženy ve formátu JKS (Java
KeyStore) a chráněny heslem. Výchozí heslo zní changeit
.
Úložiště lze spravovat pomocí nástroje keytool
, který je
součástí Java SE Development Kit. Například obsah lze vypsat
příkazem:
keytool -list -storepass changeit -keystore "C:\Program Files\Java\jre7\lib\security\cacerts"
Popis všech parametrů nástroje keytool
je k dispozici na stránkách
Oracle.
Umístění úložiště důvěryhodných certifikátů lze pro daný proces
změnit pomocí argumentu JVM javax.net.ssl.trustStore
. Argumentem
javax.net.ssl.trustStorePassword
lze specifikovat heslo.
Podívejme se na příklad spuštění aplikace s vlastním úložištěm důvěryhodných certifikátů:
java -Djavax.net.ssl.trustStore=mujtruststore.jks -Djavax.net.ssl.trustStorePassword=supertajneheslo -jar moje-aplikace.jar
Trust manager
Někdy je potřeba mít nad ověřováním SSL/TLS certifikátů větší kontrolu. Představme si například, že naše aplikace komunikuje s aplikacemi našich obchodních partnerů. Každý partner má vlastní server s vlastním SSL certifikátem. A naše aplikace potřebuje ověřit, že certifikát serveru přísluší danému partnerovi.
Dalším příkladem je situace, kdy nechceme vůbec používat file system, ale certifikáty spravujeme v rámci naší aplikace, uložené např. v databázi. Nebo si představme případ, kdy certifikáty nechceme ověřovat vůbec.
Pro všechny tyto případy můžeme použít vlastní implementaci rozhraní
javax.net.ssl.X509TrustManager
. Ověření certifikátů serveru se
děje v metodě checkServerTrusted
. Metoda vyhazuje výjimku
CertificateException
, pokud ověření selže a certifikát není
považován za důvěryhodný.
Takto lze vytvořit náš vlastní trust manager, který akceptuje libovolný certifikát serveru:
public class MyTrustManager implements X509TrustManager { @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { throw new CertificateException(); } @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { /* Ověřit řetězec certifikátů */ } @Override public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } }
Následující kód pro dané HTTPS spojení nastaví náš trust manager.
Trust manager je ukrytý v objektu třídy SSLSocketFactory
, který
nejprve vytvoříme pomocí třídy SSLContext
. Objekt
SSLSocketFactory
nastavíme pro dané připojení metodou
setSSLSocketFactory
rozhraní HttpsURLConnection
:
MyTrustManager trustManager = new MyTrustManager(); TrustManager[] tm = { trustManager }; SSLContext context = SSLContext.getInstance("TLS"); context.init(null, tm, null); SSLSocketFactory socketFactory = context.getSocketFactory(); String address = "https://localhost"; URL url = new URL(address); URLConnection connection = url.openConnection(); if (connection instanceof HttpsURLConnection) { ((HttpsURLConnection) connection).setSSLSocketFactory(socketFactory); }
Alternativně lze pomocí metody SSLContext.setDefault
nastavit
SSL kontext s vlastním trust managerem globálně pro celou aplikaci.
Možnosti řešení
SSLHandshakeException
Co tedy dělat, pokud v naší aplikaci dochází k
SSLHandshakeException
při pokusu o připojení k serveru přes
HTTPS?
Možnosti máme tyto:
- Přidat certifikát serveru resp. certifikát certifikační autority do
výchozího úložiště důvěryhodných certifikátů do souboru
cacerts
. - Uložit certifikát do vlastního úložiště a spustit aplikaci s
argumenty JVM
javax.net.ssl.trustStore
ajavax.net.ssl.trustStorePassword
. - Použít vlastní implementaci
X509TrustManager
.
V příští lekci, Síť v Javě - Práce s cookies, si vysvětlíme, jak fungují cookies a k čemu slouží. Naučíme se je také vytvořit a číst a popíšeme si jejich atributy.