HTTPSの証明書の問題を優雅に処理する方法

12379 ワード

JavaでHTTPSが遭遇する問題
  • 自己署名HTTPSサイト
  • にアクセス
  • 高バージョンJREアクセスSSLv 3/SSLv 2サイト
  • 一部の銀行インタフェースはkeystoreをロードする必要があるシーン
  • *SSLの歴史を知るにはこの記事もご覧ください.
    1自己署名のHTTPSサイトへのアクセス
    よく見られる答えは、すべてを信頼することで支持されているが、これは優雅ではない.エレガントな操作:
  • サービス側CA証明書
  • をダウンロード
    #   1:   DER     
    #         servername               
    openssl s_client -showcerts -connect self-signed.badssl.com:443 -servername self-signed.badssl.com /dev/null|openssl x509 -outform der >self-signed.badssl.com.der
    
  • コードでサービス側証明書をロードした後、カスタムSSLContextでターゲットサーバにアクセスする:
  • private SSLContext sslContext(File certificateFile, String certificateType) {
    
        InputStream inputStream = null;
        try {
            inputStream = new FileInputStream(certificateFile);
            CertificateFactory cf = CertificateFactory.getInstance(certificateType);
            Certificate certificate = cf.generateCertificate(inputStream);
            System.out.println("ca=" + ((X509Certificate) certificate).getSubjectDN());
            String alias = ((X509Certificate) certificate).getSubjectDN().toString();
    
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null, null);
            keyStore.setCertificateEntry(alias, certificate);
    
            // Create a KeyStore containing our trusted CAs
            SSLContext sslcontext = SSLContexts.custom()
                    .loadTrustMaterial(keyStore, new TrustSelfSignedStrategy())
                    .build();
            return sslcontext;
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (CertificateException e) {
            throw new RuntimeException(e);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        } catch (KeyStoreException e) {
            throw new RuntimeException(e);
        } catch (KeyManagementException e) {
            throw new RuntimeException(e);
        } finally {
            if (inputStream != null) try { inputStream.close(); } catch (IOException e) { }
        }
    }
    
    @Test
    public void testSelfSign() throws IOException {
        File certFile = ResourceUtils.getFile(this.getClass().getResource("/root.cer"));
    
        CloseableHttpClient httpclient = HttpClients.custom()
                .setSSLContext(sslContext(certFile, "X.509"))  //
                .build();
    
        String body = Executor.newInstance(httpclient).execute(Request
                .Get("https://self-signed.badssl.com/"))
                .returnContent()
                .asString();
        System.out.println(body);
    }
    

    2高バージョンJRE SSLv 3/SSLv 2サイトへのアクセス
    通常、あなたが得た答えは、${JRE_HOME}/lib/security/java.securityディレクトリの下のいくつかの構成項目を変更することによって、いくつかの不安全なSSLプロトコルバージョンまたはアルゴリズムに対する高バージョンSDKの制限を解除することです.
    各バージョンのSSLに対するサポート状況
    JDK8
    JDK7
    JDK6
    TLS Protocols
    TLSv1.2 (default)TLSv1.1TLSv1SSLv3
    TLSv1.2TLSv1.1TLSv1 (default)SSLv3
    TLS v1.1 (JDK 6 update 111 and above)TLSv1 (default)SSLv3
    JSSE Ciphers:
    Ciphers in JDK 8
    Ciphers in JDK 7
    Ciphers in JDK 6
    Reference:
    JDK 8 JSSE
    JDK 7 JSSE
    JDK 6 JSSE
    Java Cryptography Extension, Unlimited Strength (explained later)
    JCE for JDK 8
    JCE for JDK 7
    JCE for JDK 6
    *SSLv 3のサポートは、2015年1月にリリースされたアップグレードパッチでも無効になっています.
    そのため、いくつかのバージョンでHTTPSサイトにアクセスできない理由は、次の可能性があります.
  • サービス・エンド・サポートは、ローカルJREでSSLバージョンが無効になっています.たとえば、サービス・エンド・サポートはSSLv 3のみをサポートし、JDKはSSLv 3のサポートをデフォルトでオフにしています.
  • サービス側で使用されるJSSE Ciphersと、ローカルでサポートされているJSSE Ciphersとの共通項がないため、暗号化アルゴリズムが正常に選択できません.

  • 2.1現在のJREでSSLプロトコルが有効であることを確認する
    @Test
    public void sslSupport() throws IOException {
        SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory.getDefault();
        SSLSocket soc = (SSLSocket) factory.createSocket();
    
        // Returns the names of the protocol versions which are
        // currently enabled for use on this connection.
        String[] protocols = soc.getEnabledProtocols();
    
        System.out.println("Enabled protocols:");
        for (String s : protocols) {
            System.out.println(s);
        }
    }
    

    出力:
    Enabled protocols:
    TLSv1
    TLSv1.1
    TLSv1.2
    

    2.2現在のJREがCipherSutesを有効にしていることを確認する
    String[] cipers = soc.getEnabledCipherSuites();
    System.out.println("Enabled CipherSutes:");
    for (String s : cipers) {
        System.out.println(s);
    }
    

    しゅつりょく
    Enabled CipherSutes:
    TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
    TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
    TLS_RSA_WITH_AES_256_CBC_SHA256
    TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
    TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
    TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
    TLS_DHE_DSS_WITH_AES_256_CBC_SHA256
    TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
    TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
    TLS_RSA_WITH_AES_256_CBC_SHA
    TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
    TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
    TLS_DHE_RSA_WITH_AES_256_CBC_SHA
    TLS_DHE_DSS_WITH_AES_256_CBC_SHA
    TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
    TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
    TLS_RSA_WITH_AES_128_CBC_SHA256
    TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
    TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
    TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
    TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
    TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
    TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
    TLS_RSA_WITH_AES_128_CBC_SHA
    TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
    TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
    TLS_DHE_RSA_WITH_AES_128_CBC_SHA
    TLS_DHE_DSS_WITH_AES_128_CBC_SHA
    TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
    TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
    TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
    TLS_RSA_WITH_AES_256_GCM_SHA384
    TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
    TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
    TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
    TLS_DHE_DSS_WITH_AES_256_GCM_SHA384
    TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
    TLS_RSA_WITH_AES_128_GCM_SHA256
    TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
    TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
    TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
    TLS_DHE_DSS_WITH_AES_128_GCM_SHA256
    TLS_EMPTY_RENEGOTIATION_INFO_SCSV
    

    2.3サーバがサポートするSSLプロトコルを確認する
    ここではnmap検査をお勧めします.
    nmap --script ssl-enum-ciphers -p 443 badssl.com
    

    サーバが正常であるにもかかわらず、Nmap done: 1 IP address (0 hosts up) scanned-Pnのパラメータを使用するように要求された場合:
    nmap -Pn --script ssl-enum-ciphers -p 443 badssl.com
    

    出力:
    Starting Nmap 7.70 ( https://nmap.org ) at 2019-01-01 22:26 CST
    Nmap scan report for badssl.com (104.154.89.105)
    Host is up (0.32s latency).
    rDNS record for 104.154.89.105: 105.89.154.104.bc.googleusercontent.com
    
    PORT    STATE SERVICE
    443/tcp open  https
    | ssl-enum-ciphers:
    |   TLSv1.0:
    |     ciphers:
    |       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (secp256r1) - A
    |       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (secp256r1) - A
    |       TLS_DHE_RSA_WITH_AES_128_CBC_SHA (dh 2048) - A
    |       TLS_DHE_RSA_WITH_AES_256_CBC_SHA (dh 2048) - A
    |       TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA (secp256r1) - C
    |       TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A
    |       TLS_RSA_WITH_AES_256_CBC_SHA (rsa 2048) - A
    |       TLS_RSA_WITH_3DES_EDE_CBC_SHA (rsa 2048) - C
    |       TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA (dh 2048) - A
    |       TLS_RSA_WITH_CAMELLIA_256_CBC_SHA (rsa 2048) - A
    |       TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA (dh 2048) - A
    |       TLS_RSA_WITH_CAMELLIA_128_CBC_SHA (rsa 2048) - A
    |     compressors:
    |       NULL
    |     cipher preference: server
    |     warnings:
    |       64-bit block cipher 3DES vulnerable to SWEET32 attack
    |   TLSv1.1:
    |     ciphers:
    |       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (secp256r1) - A
    |       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (secp256r1) - A
    |       TLS_DHE_RSA_WITH_AES_128_CBC_SHA (dh 2048) - A
    |       TLS_DHE_RSA_WITH_AES_256_CBC_SHA (dh 2048) - A
    |       TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA (secp256r1) - C
    |       TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A
    |       TLS_RSA_WITH_AES_256_CBC_SHA (rsa 2048) - A
    |       TLS_RSA_WITH_3DES_EDE_CBC_SHA (rsa 2048) - C
    |       TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA (dh 2048) - A
    |       TLS_RSA_WITH_CAMELLIA_256_CBC_SHA (rsa 2048) - A
    |       TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA (dh 2048) - A
    |       TLS_RSA_WITH_CAMELLIA_128_CBC_SHA (rsa 2048) - A
    |     compressors:
    |       NULL
    |     cipher preference: server
    |     warnings:
    |       64-bit block cipher 3DES vulnerable to SWEET32 attack
    |   TLSv1.2:
    |     ciphers:
    |       TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (secp256r1) - A
    |       TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (secp256r1) - A
    |       TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 (dh 2048) - A
    |       TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 (dh 2048) - A
    |       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (secp256r1) - A
    |       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (secp256r1) - A
    |       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (secp256r1) - A
    |       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (secp256r1) - A
    |       TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 (dh 2048) - A
    |       TLS_DHE_RSA_WITH_AES_128_CBC_SHA (dh 2048) - A
    |       TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 (dh 2048) - A
    |       TLS_DHE_RSA_WITH_AES_256_CBC_SHA (dh 2048) - A
    |       TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA (secp256r1) - C
    |       TLS_RSA_WITH_AES_128_GCM_SHA256 (rsa 2048) - A
    |       TLS_RSA_WITH_AES_256_GCM_SHA384 (rsa 2048) - A
    |       TLS_RSA_WITH_AES_128_CBC_SHA256 (rsa 2048) - A
    |       TLS_RSA_WITH_AES_256_CBC_SHA256 (rsa 2048) - A
    |       TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A
    |       TLS_RSA_WITH_AES_256_CBC_SHA (rsa 2048) - A
    |       TLS_RSA_WITH_3DES_EDE_CBC_SHA (rsa 2048) - C
    |       TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA (dh 2048) - A
    |       TLS_RSA_WITH_CAMELLIA_256_CBC_SHA (rsa 2048) - A
    |       TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA (dh 2048) - A
    |       TLS_RSA_WITH_CAMELLIA_128_CBC_SHA (rsa 2048) - A
    |     compressors:
    |       NULL
    |     cipher preference: server
    |     warnings:
    |       64-bit block cipher 3DES vulnerable to SWEET32 attack
    |_  least strength: C
    
    Nmap done: 1 IP address (1 host up) scanned in 39.91 seconds
    

    出力によれば、badssl.comTLSv1.0TLSv1.1、およびTLSv1.2を同時にサポートし、現在対応するプロトコルがサポートしている暗号化アルゴリズムも見ることができる.
    2.4ソリューション
    JREは${JRE_HOME}/lib/security/java.securityでいくつかのアルゴリズムの構成を構成しています.例えば、ローカルの私の${JRE_HOME}/lib/security/java.securityの構成内容は次のとおりです.
    jdk.tls.disabledAlgorithms=SSLv3, RC4, DES, MD5withRSA, DH keySize < 1024, \
        EC keySize < 224, 3DES_EDE_CBC
    

    現在のJREがSSLv3プロトコルおよびRC4DESなどのアルゴリズムを無効にすることを示す.
    もちろん、手動でファイルを変更することで、これらの制限を取り消すことができますが、プログラムが新しい環境に配備されると、正常に動作しない可能性があります.優雅ではありません.優雅な操作は以下の通りです.
  • プロトコルバージョンに従ってJREペアの設定を動的にキャンセルし、JREで関連するSSLプロトコルおよびアルゴリズムの構成項目を管理するのは主にjdk.tls.disabledAlgorithmsである.
  • //          SSLv3、RC4、DES  3DES_EDE_CBC     
    static {
        String disabledAlgorithms = Security.getProperty("jdk.tls.disabledAlgorithms");
        HashSet keys = Sets.newHashSet(disabledAlgorithms.split(", +"));
        if (keys.contains("SSLv3")) keys.remove("SSLv3");
        if (keys.contains("RC4")) keys.remove("RC4");
        if (keys.contains("DES")) keys.remove("DES");
        if (keys.contains("3DES_EDE_CBC")) keys.remove("3DES_EDE_CBC");
    
        Security.setProperty("jdk.tls.disabledAlgorithms", StringUtils.join(keys, ", "));
        log.debug("SECURITY PROPERTY UPDATED \"jdk.tls.disabledAlgorithms\" = " + Security.getProperty("jdk.tls.disabledAlgorithms"));
    }
    
  • カスタムSSLConnectionSocketFactoryは、低バージョンプロトコルのサポートと互換性があり、JREのデフォルトの制限を突破します.
  • // Allow SSLv3, TLSv1, TLSv1.2 protocol only
    SSLConnectionSocketFactory sslConnectionSocketFactory =  new SSLConnectionSocketFactory(
            sslContext,
            new String[] { "SSLv3", "TLSv1", "TLSv1.2"},
            null,
            NoopHostnameVerifier.INSTANCE);
    

    これであなたは完璧で優雅にこの問題を解決することができます.
    ふろく
    [1] HTTPS https://en.wikipedia.org/wiki/HTTPS [2] Obtain a Certificate from Server https://ldapwiki.com/wiki/Obtain%20a%20Certificate%20from%20Server [3] Transport Level Security (TLS) and Java http://www.ateam-oracle.com/tls-and-java/[4] Diagnosing TLS, SSL, and HTTPS https://blogs.oracle.com/java-platform-group/diagnosing-tls,-ssl,-and-https