HTTPS 자체 서명 된 인증서 양방향 인증

머리말

이 문서에는 OpenSSL가 자체 서명 된 인증서, HTTPS는 상호 인증을 달성 생성하는 것을 설명합니다.

첫째, CA 인증서, 클라이언트 인증서를 생성은 OpenSSL을 사용하여 리눅스에서 서버 인증서

보기에는 OpenSSL의 버전 번호 openssl version -a
에는 OpenSSL 설치할 필요가없는 경우
다운로드 : www.openssl.org/source/openssl-1.0.2p.tar.gz가

tar -zxv openssl-1.0.2p.tar.gz
cd openssl-1.0.2p/
./config
make && make install
./config shared 
make clean
make  && make install
SSL을 입력 nginx를 SSL 디렉토리 아래에 디렉토리를 작성 1. 다음 스크립트를 실행, 그리고 마지막으로 클라이언트 암호를 입력
#!/bin/bash
# function: 创建 nginx https ,双向认证证书
#
# BEGIN
#
# 网站域名
# 在签发服务(客户)端证书的时候
# 这个域名必须跟 subj 中的 CN 对应
# 否则浏览器会报不安全的链接
# 查找所有javatest.hqxapp.com替换成域名运行即可
domain="javatest.hqxapp.com"
#
# ---------- CA ----------
#
# 准备CA密钥
echo "创建CA密钥.."
openssl genrsa -out $domain.CA.key 2048
# 生成CA证书请求
# 证书请求都是根据私钥来生成的
echo "生成CA证书请求.."
openssl req -new -key $domain.CA.key -out $domain.CA.csr -days 365 -subj /C=CN/ST=GuangDong/L=GuangZhou/O=javatest.hqxapp.com/OU=javatest.hqxapp.com/CN=opcenter/emailAddress=javatest.hqxapp.com -utf8
 
# 签名CA证书请求
# 使用自己的私钥来给这个CA证书请求签名
# 经过多次测试得知: 这个时间如何设置的太长,如 3650(10年) 
# chrome浏览器会报, 该网站使用的安全设置已过期
# 所以https不会显示是绿色, 而是带一个黄色三角形的图标
# 奇怪的是: 如果设成1年,也就是365天,不会提示该网站使用的安全设置已过期
# 而且也是绿色的标识
# 但如果是2年, 也是绿色的标识,但是会提示该网站使用的安全设置已过期
# 这个应该chrome浏览器的问题
echo "创建CA证书.."
openssl x509 -req -in $domain.CA.csr -signkey $domain.CA.key -out $domain.CA.crt -days 365
 
# CA证书转换为DER格式,
# DER格式似乎更加通用
openssl x509 -in $domain.CA.crt -out $domain.CA.der -outform DER
# 现在, 终于拿到了自己做 CA 需要的几个文件了, 
# 密钥: $domain.CA.key
# 证书: $domain.CA.crt
# 系统使用的: $domain.CA.der
# 接下来, 要创建一个网站, 就需要让 CA 给他签名一个证书了
 
#
 # --------- SERVER ----------
 #
 # 准备网站密钥
 echo "创建网站(服务端)密钥.."
 openssl genrsa -out $domain.server.key 2048
 # 生成网站证书请求
 # CN 一定要是网站的域名, 否则会通不过安全验证
 echo "生成网站(服务端)证书请求.."
 openssl req -new -key $domain.server.key -out $domain.server.csr -days 365 -subj /C=CN/ST=GuangDong/L=GuangZhou/O=javatest.hqxapp.com/OU=javatest.hqxapp.com/CN=$domain/emailAddress=javatest.hqxapp.com -utf8
  
  # CA签名网站证书请求
  # 不是拿到 CA 的证书了就可以说自己是 CA 的, 最重要的是, 签名需要有 CA 密钥
  # 如果客户端(个人浏览器)信任 CA 的证书的话, 那么他也就会信任由 CA 签名的网站证书
  # 因此让浏览器信任 CA 的证书之后, 客户端就自然信任服务端了, 只要做单向认证的话, 到这一步证书这一类材料就已经准备好了
  # 但是双向认证就还要给客户端(个人的浏览器)准备一份证书
  # 让服务端可以知道客户端也是合法的。
  # 假如让服务端也信任 CA 的证书
  # 那 CA 签名的客户端证书也就能被信任了。
  echo "通过CA证书签名, 创建网站(服务端)证书.."
  openssl x509 -req -in $domain.server.csr -out $domain.server.crt -CA $domain.CA.crt -CAkey $domain.CA.key -CAcreateserial -days 365
   
#
# --------- CLIENT ----------
#
# 准备客户端私钥
echo "创建浏览器(客户端)密钥.."
openssl genrsa -out $domain.client.key 2048
# 生成客户端证书请求
echo "生成浏览器(客户端)证书请求.."
openssl req -new -key $domain.client.key -out $domain.client.csr -days 3650 -subj /C=CN/ST=GuangDong/L=GuangZhou/O=javatest.hqxapp.com/OU=javatest.hqxapp.com/CN=$domain/emailAddress=javatest.hqxapp.com -utf8
# CA签名客户端证书请求
echo "通过CA证书签名, 创建浏览器(客户端)证书.."
openssl x509 -req -in $domain.client.csr -out $domain.client.crt -CA $domain.CA.crt -CAkey $domain.CA.key -CAcreateserial -days 365 
# 客户端证书转换为DER格式
openssl x509 -in $domain.client.crt -out $domain.client.der -outform DER
# 客户端证书转换为 PKCS, 即12格式
# 全称应该叫做 Personal Information Exchange
# 通常以 p12 作为后缀
echo "转换客户端证书为p12格式.."
openssl pkcs12 -export -in $domain.client.crt -inkey $domain.client.key -out $domain.client.p12

당신은 스크립트를 실행하기 전에 권한을 부여해야합니다chmod 777 ssl.sh

인증서를 생성합니다 :

2. 구성의 nginx에서

vim nginx/conf/nginx.conf

server {
        listen       443;
        server_name  localhost;
        ssi on;
        ssi_silent_errors on;
        ssi_types text/shtml;
 
         ssl on;
         ssl_certificate ../ssl/javatest.hqxapp.com.server.crt;
         ssl_certificate_key  ../ssl/javatest.hqxapp.com.server.key;
         ssl_client_certificate ../ssl/javatest.hqxapp.com.CA.crt;
         ssl_session_timeout  5m;
         ssl_verify_client on;
         ssl_protocols  SSLv2 SSLv3 TLSv1;
         ssl_ciphers  RC4:HIGH:!aNULL:!MD5;
         ssl_prefer_server_ciphers   on;
        
     location / {
            index index.html index.htm;
            proxy_pass http://127.0.0.1:8080;
        }
    }
3. 报错의 nginx : [EMERG] /usr/local/nginx/conf/nginx.conf에서 알 수없는 지시어 "SSL"

그 이유는이 구성의 nginx SSL 인증서는 SSL에서이 모듈을 참조해야하지만 Nginx의 시작 시간의 컴파일이 오류의 결과로, 함께 SSL 모듈로 번역되지 않았기 때문에.
해결 방법 :
1 ./configure를 --with-SSL http_ssl_module // 다시 추가이 모듈
이 make 명령을하지만, 전체의 nginx 다시 커버 다음 컴파일러가 메이크업에 사용되기 때문에, 메이크업 설치 실행하지 않으며, 설치하는 설치 확인하고 가.
우리가 명령을 실행 할 후 3, 우리는, 디렉토리를 추출하기 위해 nginx를 볼 수 OBJS 폴더의 nginx 또 하나 개의 문서가이 프로그램의 새로운 버전입니다. 첫째, 우리는 조금 백업 Nginx에 전에 넣어 한 다음 새 프로그램이 과거에 전에 커버 할 수 복사합니다. (정지의 nginx 프로그램)
cp /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.bak
cp objs/nginx /usr/local/nginx/sbin/nginx
4 마지막으로이 SSL 모듈이 성공적으로 설치 있는지, Nginx의 설치 디렉토리에 해당했다. 실행은 볼 -V를 ./sbin/nginx.
마지막으로, nginx를 / sbin에 ,. / Nginx에 -s를 입력 다시로드, 다시 시작 nginx를.

둘째, (변경 인증서 (새 인증서를 생성) 재시작의 nginx에, 필요) 클라이언트 액세스 인증서 https를 사용

1. 브라우저

다음 단계가 완료 될 때까지 스크립트 생성 된 인증서, 최종 단계의 입력을 실행할 때 두 번이 클릭 javatest.hqxapp.com.client.p12 인증서를 설치, 암호가 암호 중 입력합니다. 그런 다음 브라우저를 다시 시작합니다.
인증서 액세스를 설치하지 마십시오, 그것은 다음과 같은 오류가보고됩니다

2. 우편 배달부

확인 닫기

추가 키

요청 인터페이스

3. 자바 코드
인증서 가져 오기 1. (는 server.crt는 server.bks로 변환)

키 도구 -importcert -v -trustcacerts -alias TTT -file 位置 1 -keystore 位置 2 -storetype BKS -providerClass org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath 位置 3 -storepass 位置 4

1 개 위치 : 절대 경로 인증서는 server.crt의
위치 2 : 파일의 절대 경로가 생성 될 server.bks
전환 항아리 패키지 절대 경로 3 위치
세트 인증서 암호 : 위치 4

举例 : 키 도구 -importcert -v -trustcacerts -alias TTT - 파일 C : \ 사용자 \ 20,180,030 \ 바탕 화면 \ SSL \ javatest.hqxapp.com.server.crt -keystore C : \ 사용자 \ 20,180,030 \ 바탕 화면 \ SSL \ javatest.hqxapp .com.server.bks -storetype BKS -providerClass org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath D : \ SSL \ bcprov-jdk15on-163.jar -storepass 密码

2.server.bks 인증서는 server.jks 인증서로 변환

server.jks 자바 인증서는 서버 인증서에 대한 최종 사용하는 것입니다.
프로젝트의 루트 디렉토리에 두 개의 인증서 파일은 키 폴더를 만들 수 있습니다. 열기 portecle.jar 도구를 시작합니다.

열기 server.bks 파일


의 활동을 명령 변환 할 때 암호 설정을 입력

변환 JKS 형식

으로 저장을하고, 인증서를 JKS 얻을

호출 자바 코드를

package com.hqx.util;

import com.alibaba.fastjson.JSONObject;
import org.junit.Test;

import javax.net.ssl.*;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.*;
import java.security.cert.CertificateException;
import java.util.List;
import java.util.Map;


public class HttpsClient {
    public static String KEY_STORE_FILE="key/javatest.hqxapp.com.client.p12";
    public static String KEY_STORE_PASS="密码";
    /**
     * server.crt转换bks,再转为jks格式
     */
    public static String TRUST_STORE_FILE="key/javatest.hqxapp.com.server.jks";
    public static String TRUST_STORE_PASS="密码";


    private static SSLContext sslContext;
    /**
     * 向指定URL发送GET方法的请求 
     *
     * @param url
     *            发送请求的URL 
     * @param param
     *            请求参数,请求参数应该是 name1=value1&name2=value2 的形式。 
     * @return URL 所代表远程资源的响应结果 
     *
     */
    public static String sendGet(String url, String param) {
        String result = "";
        BufferedReader in = null;
        try {
            String urlNameString = url + "?" + param;
            URL realUrl = new URL(urlNameString);
            // 打开和URL之间的连接  
            HttpURLConnection connection = (HttpURLConnection) realUrl.openConnection();
            // 打开和URL之间的连接  
            if(connection instanceof HttpsURLConnection){
                ((HttpsURLConnection)connection)
                        .setSSLSocketFactory(getSSLContext().getSocketFactory());
            }

            // 设置通用的请求属性  
            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent",
                    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            // 建立实际的连接  
            connection.connect();
            // 获取所有响应头字段  
            Map<String, List<String>> map = connection.getHeaderFields();
            // 遍历所有的响应头字段  
            for (String key : map.keySet()) {
                //System.out.println(key + "--->" + map.get(key));  
            }
            // 定义 BufferedReader输入流来读取URL的响应  

            if(connection.getResponseCode()==200){
                in = new BufferedReader(new InputStreamReader(
                        connection.getInputStream(),"utf8"));
            }else{
                in = new BufferedReader(new InputStreamReader(
                        connection.getErrorStream(),"utf8"));
            }
            String line;
            while ((line = in.readLine()) != null) {
                result += line;
            }

        } catch (Exception e) {
            System.out.println("发送GET请求出现异常!" + e);
            e.printStackTrace();
        }
        // 使用finally块来关闭输入流  
        finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
        return result;
    }

    /**
     * 向指定 URL 发送POST方法的请求  
     *
     * @param url
     *            发送请求的 URL  
     * @param param
     *            请求参数,请求参数应该是 name1=value1&name2=value2 的形式。  
     * @return 所代表远程资源的响应结果
     */
    public static String sendPost(String url, String param) {
        PrintWriter out = null;
        BufferedReader in = null;
        String result = "";
        try {
            URL realUrl = new URL(url);
            // 打开和URL之间的连接  
            HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();
            if(conn instanceof HttpsURLConnection){
                ((HttpsURLConnection)conn)
                        .setSSLSocketFactory(getSSLContext().getSocketFactory());
            }
            // 设置通用的请求属性  
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("Content-Type", "application/json");
            conn.setRequestProperty("user-agent",
                    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            // 发送POST请求必须设置如下两行  
            conn.setDoOutput(true);
            conn.setDoInput(true);
            // 获取URLConnection对象对应的输出流  
            out = new PrintWriter(conn.getOutputStream());
            // 发送请求参数  
            out.print(param);
            // flush输出流的缓冲  
            out.flush();
            // 定义BufferedReader输入流来读取URL的响应  
            if(conn.getResponseCode()==200){
                in = new BufferedReader(
                        new InputStreamReader(conn.getInputStream(),"utf8"));
            }else{
                in = new BufferedReader(
                        new InputStreamReader(conn.getErrorStream(),"utf8"));
            }
            String line="";
            while ((line = in.readLine()) != null) {
                result += line;
            }
        } catch (Exception e) {
            System.out.println("发送 POST 请求出现异常!"+e);
            e.printStackTrace();
        }
        //使用finally块来关闭输出流、输入流  
        finally{
            try{
                if(out!=null){
                    out.close();
                }
                if(in!=null){
                    in.close();
                }
            }catch(IOException ex){
                ex.printStackTrace();
            }
        }
        return result;
    }

    public static SSLContext getSSLContext(){
        long time1=System.currentTimeMillis();
        if(sslContext==null){
            try {
                KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
                kmf.init(getkeyStore(),KEY_STORE_PASS.toCharArray());
                KeyManager[] keyManagers = kmf.getKeyManagers();

                TrustManagerFactory trustManagerFactory=TrustManagerFactory.getInstance("SunX509");
                trustManagerFactory.init(getTrustStore());
                TrustManager[]  trustManagers= trustManagerFactory.getTrustManagers();

                sslContext = SSLContext.getInstance("TLS");
                sslContext.init(keyManagers, trustManagers, new SecureRandom());
                HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
                    @Override
                    public boolean verify(String hostname, SSLSession session) {
                        return true;
                    }
                });
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (UnrecoverableKeyException e) {
                e.printStackTrace();
            } catch (KeyStoreException e) {
                e.printStackTrace();
            } catch (KeyManagementException e) {
                e.printStackTrace();
            }
        }
        long time2=System.currentTimeMillis();
        System.out.println("SSLContext 初始化时间:"+(time2-time1));
        return sslContext;
    }


    public static KeyStore getkeyStore(){
        KeyStore keySotre=null;
        try {
            keySotre = KeyStore.getInstance("PKCS12");
            File file = new File(KEY_STORE_FILE);
            System.out.println(file.getAbsolutePath());
            FileInputStream fis = new FileInputStream(new File(KEY_STORE_FILE));
            keySotre.load(fis, KEY_STORE_PASS.toCharArray());
            fis.close();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (CertificateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return keySotre;
    }
    public static KeyStore getTrustStore() throws IOException{
        KeyStore trustKeyStore=null;
        FileInputStream fis=null;
        try {
            trustKeyStore=KeyStore.getInstance("JKS");
            fis = new FileInputStream(new File(TRUST_STORE_FILE));
            trustKeyStore.load(fis, TRUST_STORE_PASS.toCharArray());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (CertificateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            fis.close();
        }
        return trustKeyStore;
    }

    @Test
    public static void main(String[] args) throws UnsupportedEncodingException {
        String result=sendGet("https://javatest.hqxapp.com/demo/", "");
        System.out.println(result);
    }

    @Test
    public void t() {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("content", "111");
        String result=sendPost("https://javatest.hqxapp.com/demo/", jsonObject.toJSONString());
        System.out.println(result);
    }
}  

항아리 패키지, 스크립트 위에서 사용 된 코드는 자원 모듈에서 다운로드 할 수 있습니다.

CSDN : HTTPS : //blog.csdn.net/qq_27682773
제인 책 : HTTPS : //www.jianshu.com/u/e99381e6886e가
HTTPS : //www.cnblogs.com/lixianguo 공원 블로그
개인 블로그 : HTTPS를 : // www.lxgblog.com

추천

출처www.cnblogs.com/lixianguo/p/12522557.html