https一方向認証と双方向認証のデモ(SpringBoot + okhttp3 + keytool自己署名)

目次

 

I.はじめに

2.ソフトウェアバージョン

3つの一方向認証

4つの双方向認証


I.はじめに

HTTPS(フルネーム:SecureSocketレイヤーを介したハイパーテキスト転送プロトコル)は、セキュリティを目標としたHTTPチャネルです。HTTPに基づいて、送信暗号化とID認証により送信プロセスのセキュリティが確保されます[1]。HTTPSはHTTPに基づいてSSLレイヤーを追加します。HTTPSのセキュリティ基盤はSSLであるため、暗号化の詳細にはSSLが必要です。HTTPSには、HTTPとは異なるデフォルトのポートと、暗号化/認証レイヤー(HTTPとTCPの間)があります。このシステムは、認証と暗号化された通信方法を提供します。

この記事では、okhttp3を使用して、SpringBootによって作成されたhttpsインターフェースにアクセスします。

2.ソフトウェアバージョン

SpringBoot:2.1.2

okhttp3:3.2.0

keytool:jdk1.8.0_77

3つの一方向認証

1サーバー証明書を生成する

keytool -genkey -alias server -keypass 123456 -keyalg RSA -keysize 1024 -validity 365 -storepass 123456 -storetype PKCS12 -keystore C:\ Users \ admin \ Desktop \ server.p12

キーストアのパスワードを覚えておいて、SpringBoot構成で使用してください

2サーバーのcer証明書をエクスポートします

keytool -export -alias server -keystore C:\ Users \ admin \ Desktop \ server.p12 -storetype PKCS12 -keypass 123456 -file C:\ Users \ admin \ Desktop \ server.cer

3SpringBootを構成します

server.p12をSpringBootのリソースディレクトリにコピーします

#ssl配置
server.ssl.enabled=true
server.ssl.key-store=classpath:server.p12
server.ssl.key-store-password=123456
server.ssl.key-store-type=JKS
# 证书别名
server.ssl.key-alias=server

4ブラウザテスト

https:// localhost:8080 / demoにアクセスします

5okhttp3テスト

パス:server.cerのパスを指定します

package com.asyf.demo.other_api.okhttp3;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

import javax.net.ssl.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;

/**
 * https单向认证
 */
public class Test2 {

    //安全传输层协议
    private static final String PROTOCOL = "TLS";

    // JKS/PKCS12
    private static final String KEY_KEYSTORE_TYPE = "PKCS12";

    private static SSLSocketFactory getSocketFactory(String cerPath) throws Exception {
        SSLSocketFactory socketFactory = null;
        try (InputStream cerInputStream = new FileInputStream(new File(cerPath))) {
            TrustManager[] trustManagers = getTrustManagers(cerInputStream);
            SSLContext sslContext = getSslContext(trustManagers);
            socketFactory = sslContext.getSocketFactory();
        }
        return socketFactory;
    }

    private static SSLContext getSslContext(TrustManager[] trustManagers) throws Exception {
        SSLContext sslContext = SSLContext.getInstance(PROTOCOL);
        sslContext.init(null, trustManagers, new SecureRandom());
        return sslContext;
    }

    private static TrustManager[] getTrustManagers(InputStream inputStream) throws Exception {
        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        KeyStore keyStore = KeyStore.getInstance(KEY_KEYSTORE_TYPE);
        //加载证书
        CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
        Certificate ca = certificateFactory.generateCertificate(inputStream);
        keyStore.load(null, null);
        //设置公钥
        keyStore.setCertificateEntry("server", ca);
        trustManagerFactory.init(keyStore);
        TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
        return trustManagers;
    }

    public static void main(String[] args) throws Exception {
        //获取SSLSocketFactory
        String certPath = "D:\\workspace\\asyf_demo\\demo\\src\\main\\java\\com\\asyf\\demo\\other_api\\okhttp3\\server.cer";//服务端公钥
        SSLSocketFactory socketFactory = getSocketFactory(certPath);
        //发送请求
        String url = "https://127.0.0.1:8080/demo";
        OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
        clientBuilder.sslSocketFactory(socketFactory);
        //解决报错javax.net.ssl.SSLPeerUnverifiedException: Hostname 127.0.0.1 not verified
        clientBuilder.hostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String s, SSLSession sslSession) {
                System.out.println("主机:" + s);
                return true;
            }
        });
        OkHttpClient client = clientBuilder.build();

        Request.Builder builder = new Request.Builder().url(url);
        Request request = builder.build();

        Response response = client.newCall(request).execute();
        String result = response.body().string();
        //打印请求结果
        System.out.println(result);
    }

}

 コンソール:

4つの双方向認証

1クライアント証明書を生成する

keytool -genkey -alias client -keypass 123456 -keyalg RSA -keysize 1024 -validity 365 -storepass 123456 -storetype PKCS12 -keystore C:\ Users \ admin \ Desktop \ client.p12

2クライアントのcer証明書をエクスポートします

keytool -export -alias client -keystore C:\ Users \ admin \ Desktop \ client.p12 -storetype PKCS12 -keypass 123456 -file C:\ Users \ admin \ Desktop \ client.cer

3Springbootによって信頼された証明書を格納するためのキーストアを生成します

keytool -genkey -alias springboot_keystore -keypass 123456 -keyalg RSA -keysize 1024 -validity 365 -storepass 123456 -storetype PKCS12 -keystore C:\ Users \ admin \ Desktop \ springboot_keystore.keystore

4クライアントの公開鍵をspringboot_keystore.keystoreにインポートします

keytool -import -v -file  C:\ Users \ admin \ Desktop \ client.cer  -keystore  C:\ Users \ admin \ Desktop \ springboot_keystore.keystore  -storepass 123456

5のconfigure SpringBoot

springboot_keystore.keystoreをSpringBootプロジェクトにコピーし、次の構成を追加します

#双向认证配置
server.ssl.trust-store=classpath:springboot_keystore.keystore
server.ssl.trust-store-password=123456
server.ssl.client-auth=need
server.ssl.trust-store-type=JKS
server.ssl.trust-store-provider=SUN

6ブラウザテスト

直接アクセスすると、次のエラーが発生します

コンピューターに証明書をインストールする必要があります

client.p12をダブルクリックし、証明書をインストールします(デモはwin10環境です)

インストールが成功したら、ブラウザを更新し、証明書を選択するように求めます。「OK」をクリックします。

次に、httpsインターフェースにアクセスして、次の図に示すような結果を確認し、構成が成功したことを示します。

7okhttp3テスト

path:client.p12のパスを指定します

一方向認証でメイン機能に引き続きアクセスすると、コンソールは例外メッセージを出力します。

Exception in thread "main" javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate

テストコード:

package com.asyf.demo.other_api.okhttp3;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

import javax.net.ssl.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;

/**
 * https双向认证
 */
public class Test {

    //安全传输层协议
    private static final String PROTOCOL = "TLS";

    // JKS/PKCS12
    private static final String KEY_KEYSTORE_TYPE = "PKCS12";

    public static SSLSocketFactory getSocketFactory(String cerPath, String p12Path, String password) throws Exception {
        InputStream cerInputStream = null;
        InputStream p12InputStream = null;
        SSLSocketFactory socketFactory = null;
        try {
            cerInputStream = new FileInputStream(new File(cerPath));
            p12InputStream = new FileInputStream(new File(p12Path));
            KeyManager[] keyManagers = getKeyManagers(p12InputStream, password);
            TrustManager[] trustManagers = getTrustManagers(cerInputStream);
            SSLContext sslContext = getSslContext(keyManagers, trustManagers);
            socketFactory = sslContext.getSocketFactory();
        } finally {
            if (cerInputStream != null) {
                cerInputStream.close();
            }
            if (p12InputStream != null) {
                p12InputStream.close();
            }
        }
        return socketFactory;
    }

    private static SSLContext getSslContext(KeyManager[] keyManagers, TrustManager[] trustManagers) throws Exception {
        SSLContext sslContext = SSLContext.getInstance(PROTOCOL);
        sslContext.init(keyManagers, trustManagers, new SecureRandom());
        return sslContext;
    }

    private static KeyManager[] getKeyManagers(InputStream inputStream, String password) throws Exception {
        KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        KeyStore keyStore = KeyStore.getInstance(KEY_KEYSTORE_TYPE);
        //加载证书
        keyStore.load(inputStream, password.toCharArray());
        keyManagerFactory.init(keyStore, password.toCharArray());
        KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();
        return keyManagers;
    }

    private static TrustManager[] getTrustManagers(InputStream inputStream) throws Exception {
        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        KeyStore keyStore = KeyStore.getInstance(KEY_KEYSTORE_TYPE);
        //加载证书
        CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
        Certificate ca = certificateFactory.generateCertificate(inputStream);
        keyStore.load(null, null);
        //设置公钥
        keyStore.setCertificateEntry("server", ca);
        trustManagerFactory.init(keyStore);
        TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
        return trustManagers;
    }

    public static void main(String[] args) throws Exception {
        //获取SSLSocketFactory
        String certPath = "D:\\workspace\\asyf_demo\\demo\\src\\main\\java\\com\\asyf\\demo\\other_api\\okhttp3\\server.cer";//服务端公钥
        String p12Path = "D:\\workspace\\asyf_demo\\demo\\src\\main\\java\\com\\asyf\\demo\\other_api\\okhttp3\\client.p12";//客户端私钥
        SSLSocketFactory socketFactory = getSocketFactory(certPath, p12Path, "123456");
        //发送请求
        String url = "https://127.0.0.1:8080/demo";
        OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
        clientBuilder.sslSocketFactory(socketFactory);
        //解决报错javax.net.ssl.SSLPeerUnverifiedException: Hostname 127.0.0.1 not verified
        clientBuilder.hostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String s, SSLSession sslSession) {
                System.out.println("主机:" + s);
                return true;
            }
        });
        OkHttpClient client = clientBuilder.build();

        Request.Builder builder = new Request.Builder().url(url);
        Request request = builder.build();

        Response response = client.newCall(request).execute();
        String result = response.body().string();
        //打印结果返回数据
        System.out.println(result);
    }

}

コンソール:

おすすめ

転載: blog.csdn.net/cs373616511/article/details/105628692