sslhttps代理应用场景介绍 (ssl与https协议)

httpsssl技术实现方案详解,了解ssl与https协议

关于ssl(https)客户端配置

最近接触到银行的接口,对于安全方面非常严格,发到银行的报文需要加签、加密,接口也是ssl双向认证,只接受OVSSL以上的证书,这里记录下作为客户端ssl认证的两种方式。

银行会给一个他们的ssl公钥,这个公钥是用来验证他们返回报文的

因为银行测试环境还没有申请下来,所以也写了个本地的https服务端作为认证测试

客户端ssl证书生成

傻瓜式界面操作,需要软件KeyStore Explorer。

*载下**后新建-选择JKS(其他也可以)

httpsssl技术实现方案详解,了解ssl与https协议

Tools->Generate Key Pair,生成密匙对

httpsssl技术实现方案详解,了解ssl与https协议

选择RSA(2048),点击Name输入网站信息

httpsssl技术实现方案详解,了解ssl与https协议

这里需要注意,Common Name 要对应接口域名或者ip。

httpsssl技术实现方案详解,了解ssl与https协议

接下去就是下一步下一步,遇到密码就输入密码,然后保存到本地一个文件,比如127.0.0.1-ssl-client.jks。这里会有两次输入密码,第一次是密钥的密码,第二次是jks文件的密码,一般用一样的就行。

导出公钥:KeyStoreExplorer里面双击密钥对,点击pem,export,导出公钥pem文件,比如命名为127.0.0.1-ssl-client-pub.pem

httpsssl技术实现方案详解,了解ssl与https协议

然后把这个127.0.0.1-ssl-client-pub.pem文件给银行,银行加入到他们的信任列表里面,我们就可以调用他们的接口了。(当然这里只是为了测试,真实情况需要把证书发给CA认证才行)

客户端把银行的公钥加入信任列表

银行给的公钥是pem格式的,假设叫citi-ssl-pub.pem,需要把这个公钥加入信任密钥对(KeyStore)。

打开KeyStore Explorer,新建->选择JKS->Tools->Import Trusted Certificate,选择银行的公钥citi-ssl-pub.pem

httpsssl技术实现方案详解,了解ssl与https协议

保存,填写密码,这个也是jks文件的密码,保存文件可以叫127.0.0.1-ssl-client-trust.jks

客户端代码直接请求https接口

上面我们有了客户端ssl证书、也把公钥给了银行、银行把公钥给我们,我们也生成了信任jks。可以开始写代码了。这里用hutool的httpUtil工具类请求银行接口,直接上代码

httpsssl技术实现方案详解,了解ssl与https协议

这里代码写好了,当然运行肯定回报错,银行的测试环境没有,我们这里再模拟写一个https的服务,作为测试。

https服务端ssl证书生成

同客户端一模一样,也需要导出公钥,假设叫127.0.0.1-ssl-server-pub.pem。把这个也加入到127.0.0.1-client-trust.jks作为信任证书,方法同加入citi-ssl-pub.pem一样。这样127.0.0.1-client-trust.jks里面就有两个信任证书了

https服务端把客户端ssl证书加入信任列表

这里的步骤也和客户端一样,生成一个jks密钥对,加入客户端的ssl公钥证书(127.0.0.1-ssl-client-pub.pem)。这里是模拟银行把我们的公钥拿过去后的操作。服务端的信任jks文件名:127.0.0.1-ssl-server-trust.jks

整理下所有的测试证书文件

ssl                                        ssl文件夹
|---client                                客户端ssl文件夹
|---|---127.0.0.1-ssl-client.jks        客户端ssl密钥对,包含私钥
|---|---127.0.0.1-ssl-client-pub.pem    客户端ssl公钥证书
|---|---127.0.0.1-ssl-client-trust.jks    客户端信任证书(包含两个公钥证书)
|---server                                服务端ssl文件夹
|---|---127.0.0.1-ssl-server.jks        服务端ssl密钥对,包含密钥
|---|---127.0.0.1-ssl-server-pub.pem    服务端ssl公钥证书
|---|---127.0.0.1-ssl-server-trust.jks    服务端信任证书列表
|---|---citi-ssl-pub.pem                银行ssl公钥证书

本地模拟https服务端代码

springboot 项目,在配置文件中增加ssl

server:
  port: 4000
  ssl:
    key-store-type: JKS
    key-store: classpath:ssl/server/127.0.0.1-ssl-server.jks
    key-store-password: 127
    key-password: 127
    trust-store-type: JKS
    trust-store: classpath:ssl/server/127.0.0.1-ssl-server-trust.jks
    trust-store-password: 127
    client-auth: need

服务端接口代码,非常简单

@RestController
public class SslServer {
    @RequestMapping("/ssl")
    public String hello(@RequestParam("host") String host) {
        return "hello " + host;
    }
}

启动服务端项目

测试客户端直接请求服务端

运行客户端main方法,直接请求,正常返回

httpsssl技术实现方案详解,了解ssl与https协议

服务端没有加入客户端信任证书测试

修改服务端的信任证书列表,将127.0.0.1-ssl-client-pub.pem证书删掉

httpsssl技术实现方案详解,了解ssl与https协议

增加citi-ssl-pub.pem(不能为空),再次请求

httpsssl技术实现方案详解,了解ssl与https协议

如果没有把客户端证书加入到服务端信任列表,请求就会报错。还原服务端的信任证书列表

把客户端的信任列表去掉

客户端代码改为

httpsssl技术实现方案详解,了解ssl与https协议

再次请求,发现还是能正常访问,那么客户端的信任列表有什么用呢?我的理解是为了验证服务端的响应是否为银行,防止返回的报文被他人篡改

客户端http请求nginx,nginx转发银行

这种情况是为了应付如果项目部署服务机器不能访问外网,可以通过nginx转发。如果是这种方式代码就不需要配置任何东西,请求nginx的端口就行这种情况nginx配置文件

http{
    server{
        listen    80;
        server_name    localhost;
        location /bank {
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_redirect    off; 
            proxy_ssl_certificate        127.0.0.1-ssl-client-pub.pem;
            proxy_ssl_certificate_key    127.0.0.1-ssl-client-pri.pem;
            proxy_ssl_trusted_certificate     127.0.0.1-ssl-server-pub.pem;
            proxy_ssl_verify     on;
            proxy_ssl_server_name on;
            proxy_ssl_verify_depth 2;
            proxy_pass   https://127.0.0.1:4000/ssl;
        }
    }
}

这里的127.0.0.1-ssl-client-pub.pem 和127.0.0.1-ssl-server-pub.pem 和原来的一样,但是需要一个客户端ssl证书密钥,也可以通过keyStore Explorer导出

右键选择密钥对->View Details->Private Key Details->输入密码->点击pem->Export

httpsssl技术实现方案详解,了解ssl与https协议

还存在一个疑问没解决:127.0.0.1-ssl-server-pub.pem 这个公钥如果Common Name不是域名,nginx转发会报错,upstream SSL certificate does not match "127.0.0.1" while SSL handshaking to upstream

代码可以在Github上找到