当前位置:   article > 正文

sslpinning实战_postman 导入证书

postman 导入证书

在这里插入图片描述在这里插入图片描述

1.生成服务端/客户端证书

╰─$ openssl genrsa -out server.key 1024
╰─$ openssl req -new -x509 -key server.key -out server.crt -days 3650

╰─$ openssl genrsa -out client.key 1024
╰─$ openssl req -new -x509 -key client.key -out client.crt -days 3650

将client.key和client.crt合成client.p12。p12文件可以认为是一对公私钥的合体文件,通常会有密码保护;可以通过openssl命令生成(将公私钥两个文件合成得到一个p12文件)
╰─$ openssl pkcs12 -export -clcerts -in client.crt -inkey client.key -out client.p12

╰─$ ls
client.crt client.key client.p12 server.crt server.key
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

最关键的是域名信息Common Name,这里需要填写服务器的域名地址,比如test.com;也可以填写泛域名,比如*.test.com;如果没有域名,可以直接填写服务端ip地址

2.启动flask接口

from flask import Flask
app = Flask(__name__)
from flask import request

@app.route("/")
def hello():
    print(dict(request.headers))
    print('客户端证书: ' + request.headers.get('X-SSL-Client-Cert', '').replace('\n\t', '\n'))
    print('证书序列号: ' + request.headers.get('X-SSL-serial', ''))
    print('证书主体: ' + request.headers.get('cert-subject', ''))
    return "SSLPinning Test"

if __name__ == "__main__":
    app.run(ssl_context=('/Users/wiliam/temp/certificate/server.crt', '/Users/wiliam/temp/certificate/server.key'))

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

访问https://127.0.0.1:5000
在这里插入图片描述

因为用的自签名证书,提示“不安全”是正常的,点击“红色三角形感叹号”可以查看证书
在这里插入图片描述 在这里插入图片描述

3. mac安装nginx

╰─$ brew install nginx
╰─$ nginx
  • 1
  • 2

访问http://localhost:8080/可以看到nginx的欢迎页面

在这里插入图片描述

4. 修改nginx配置文件

使用nginx的 -t 参数进行配置检查,即可知道实际调用的配置文件路径及是否调用有效
╰─$ nginx -t
nginx: the configuration file /opt/homebrew/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /opt/homebrew/etc/nginx/nginx.conf test is successful
  • 1
  • 2
  • 3
  • 4

修改/opt/homebrew/etc/nginx/nginx.conf


#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    server {
        listen       8080;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   html;
            index  index.html index.htm;
        }

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {
        #    proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;
        #}

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }


    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}


    # HTTPS server
    #
    server {
       listen       443 ssl;
       server_name  localhost;

       ssl_certificate      /Users/wiliam/temp/certificate/server.crt;
       ssl_certificate_key  /Users/wiliam/temp/certificate/server.key;

       ssl_client_certificate /Users/wiliam/temp/certificate/client.crt;
       # ssl_verify_client on/optional/optional_no_ca/off;
       ssl_verify_client optional_no_ca;

       ssl_session_cache    shared:SSL:1m;
       ssl_session_timeout  5m;

       ssl_ciphers  HIGH:!aNULL:!MD5;
       ssl_prefer_server_ciphers  on;

       location / {
           root   html;
           index  index.html index.htm;
       }

       location /flask/ {
           proxy_set_header X-Real-IP $remote_addr;
           proxy_set_header X-Real-PORT $remote_port;

           proxy_set_header X-SSL-Client-Cert $ssl_client_cert;
           proxy_set_header X-SSL-serial $ssl_client_serial;
           proxy_set_header cert-subject  $ssl_client_s_dn;
      
           proxy_pass https://127.0.0.1:5000/;
       }
    }
    include servers/*;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133

这里开启https服务器,
设置ssl_certificate、ssl_certificate_key、ssl_client_certificate、ssl_verify_client,
添加location /flask/,通过proxy_pass转发请求到flask接口,
通过proxy_set_header把证书信息$ssl_client_cert、$ssl_client_serial、$ssl_client_s_dn设置到请求头里供后端查看


# 重新启动,热启动,修改配置重启不影响线上
╰─$ nginx -s reload;
  • 1
  • 2
  • 3

此时访问https://localhost/flask/可以看到请求转发成功
在这里插入图片描述

5.postman导入客户端证书前后对比

用postman请求https://localhost/flask/
没导入客户端证书时请求,flask日志显示无客户端证书
在这里插入图片描述
postman导入客户端证书
在这里插入图片描述
postman再次请求
在这里插入图片描述

6.开启服务端校验客户端证书

nginx配置文件里设置 ssl_verify_client on;

─$ nginx -s reload
  • 1

在这里插入图片描述
此时访问https://localhost/flask/,nginx会提示“No required SSL certificate was sent”

7.okhttp携带客户端证书、校验服务端证书

在这里插入图片描述

package my.app;

import android.util.Log;

import okhttp3.CertificatePinner;
import okhttp3.OkHttpClient;

import javax.net.ssl.*;

import java.io.IOException;
import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;

public class OkHttpClintUtil {
    public static InputStream client_p12 = null;
    public static InputStream server2_crt = null;

    public static OkHttpClient getClientByAI(){
        try {
            //服务端证书
            CertificateFactory certificateFactory = CertificateFactory.getInstance("X509");
            Certificate serverCertificate = certificateFactory.generateCertificate(server2_crt);

            //keyStore存储服务端证书
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null,null); //In order to create an empty keystore, pass null as the stream argument.
            keyStore.setCertificateEntry("my_server_certificate", serverCertificate);

            // 创建 TrustManager
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(keyStore);
            TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();

            // 加载客户端证书文件
            KeyStore keyStore2 = KeyStore.getInstance("PKCS12");
            keyStore2.load(client_p12, "123456".toCharArray());

            // 创建 KeyManager
            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            keyManagerFactory.init(keyStore2, "123456".toCharArray());
            KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();

            // 创建 SSLContext
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(keyManagers, trustManagers, new SecureRandom());

            //certificatePinner验证服务端证书,可以校验证书,也可以校验证书哈希值
            CertificatePinner certificatePinner = new CertificatePinner.Builder().add("172.16.90.134", CertificatePinner.pin(serverCertificate)).build();
            CertificatePinner certificatePinner2 = new CertificatePinner.Builder().add("172.16.90.134", "sha256/Rkw2hU165pITX+5rqOJCPrgDL3Y3TRHLPbygl/wxpsY=").build();

            // 创建 OkHttpClient
            OkHttpClient client = new OkHttpClient.Builder()
                    //sslContext携带了客户端证书
                    //trustManagers[0]信任服务端自签名证书
                    .sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) trustManagers[0])
                    //可以在这里对hostname进行校验
                    .hostnameVerifier(new HostnameVerifier() {
                        @Override
                        public boolean verify(String hostname, SSLSession session) {
                            Log.d("my.app", "hostname: " + hostname);
                            try {
                                Certificate[] peerCertificates = session.getPeerCertificates();
                                for (Certificate c: peerCertificates) {
                                    Log.d("my.app", "接收到的服务端证书: \n" + c.toString());
                                }
                            } catch (SSLPeerUnverifiedException e) {
                                e.printStackTrace();
                                return false;
                            }
                            return true;
                        }
                    })
                    //服务端证书绑定
                    .certificatePinner(certificatePinner2)
                    .build();
            return client;
        } catch (CertificateException | KeyStoreException | KeyManagementException | NoSuchAlgorithmException | IOException | UnrecoverableKeyException e) {
            e.printStackTrace();
        }
        return null;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
			String url = "https://172.16.90.134/flask";
            Log.i("my.app", url);
            try {
                OkHttpClintUtil.server2_crt = getAssets().open("server2.crt");
                OkHttpClintUtil.client_p12 = getAssets().open("client.p12");
            } catch (IOException e) {
                e.printStackTrace();
            }

            OkHttpClient okHttpClient = OkHttpClintUtil.getClientByAI();
            Request request = new Request.Builder().url(url).get().build();
            Call call = okHttpClient.newCall(request);
            call.enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    Log.d("my.app", "okhttp请求失败" + e.toString());
                    //使用Looper解决在子线程中调用Toast出现异常
                    Looper.prepare();
                    Toast.makeText(getApplicationContext(),"okhttp请求失败" + e.toString(),Toast.LENGTH_SHORT).show();
                    Looper.loop();
                }
                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    //response.body().string() 获得服务器返回的数据
                    String res = response.body().string();
                    Log.d("my.app", "onResponse: " + res);
                    //使用Looper解决在子线程中调用Toast出现异常
                    Looper.prepare();
                    Toast.makeText(getApplicationContext(),"onResponse: " + res,Toast.LENGTH_SHORT).show();
                    Looper.loop();
                }
            });
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

结束

























TCP 三次握手:用于建立 TCP 连接(不论是否使用 SSL/TLS)。
SSL/TLS 握手:在 TCP 连接建立后,进行SSL/TLS握手,包括:
客户端发送 Client Hello。
服务端响应 Server Hello 并返回其证书。
客户端验证服务端证书后,发送自己的证书给服务端。
服务端验证客户端证书。
双方完成密钥交换,建立安全通道。

Flask开启https

from flask import Flask
app = Flask(__name__)


@app.route("/")
def hello():
    return "SSLPinning Test"


if __name__ == "__main__":
    # app.run(ssl_context='adhoc')  # Flask的临时证书并不是那么好,因为每次服务器运行时,都会通过pyOpenSSL动态生成不同的证书
    app.run(ssl_context=('/Users/wiliam/temp/cert.pem', '/Users/wiliam/temp/key.pem'))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

flask不支持验证客户端证书!
(好像可以???看不懂 https://stackoverflow.com/questions/23262768/two-way-ssl-authentication-for-flask

mac安装nginx

╰─$ brew install nginx

╰─$ where nginx
/opt/homebrew/bin/nginx

使用nginx的 -t 参数进行配置检查,即可知道实际调用的配置文件路径及是否调用有效
╰─$ nginx -t
nginx: the configuration file /opt/homebrew/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /opt/homebrew/etc/nginx/nginx.conf test is successful

# 重新启动,热启动,修改配置重启不影响线上
nginx -s reload;
# 关闭
nginx -s stop;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

访问http://localhost:8080/

nginx的root & index

proxy_set_header X-SSL-CERT $ssl_client_cert;
will save the client certificate (from the incoming request to nginx) into ssl_client_cert variable.
NOTE: You’d have to set the
ssl_verify_client on/optional/optional_no_ca/off;
configuration and it should be anything other than off.
on: will do the full verification on client cert, will require the cert from the client side.
optional: cert isn’t required but if cert is provided, will verify it.
optional_no_ca: cert isn’t required, and won’t be verified.
off: turning the option off. (Not asking for the certs so nothing to save in ssl_client_cert)

算出证书的sha256

╰─$ openssl x509 -in server.crt -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
Rkw2hU165pITX+5rqOJCPrgDL3Y3TRHLPbygl/wxpsY=
  • 1
  • 2

Nginx 304 Not Modify

使用缓存即可的意思
关闭缓存

            etag off;
            add_header Last-Modified "";
            add_header Cache-Control no-cache;
  • 1
  • 2
  • 3

在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/天景科技苑/article/detail/908183
推荐阅读
相关标签
  

闽ICP备14008679号