windows 使用openssl生成CA文件,tomact nginx 配置https及android https的ssl认证添加

为君一笑 提交于 2019-12-07 11:40:16

前言

该篇博文为工作总结,暂时记录的知识点有 :鄙人对https的拙见, windows 使用openssl 生成没有获取认证的证书(主要适用于平时练习)tomact 及nginx 对https的配合部分转发的配置,以及android请求后台添加ssl认证等小白知识点。本篇文章 大约需要耗时 20分钟。

1.https拙见

HTTPS相当于HTTP的安全版本,在HTTP的基础上添加SSL(Secure Socket Layer),SSL主要负责安全。

SSL 主要作用
1. 认证用户和服务器,确保数据发送到正确的客户机和服务器;(验证证书)
2. 加密数据以防止数据中途被窃取;(加密)
3. 维护数据的完整性,确保数据在传输过程中不被改变。(摘要算法)

HTTPS流程

HTTPS在传输数据之前需要客户端(浏览器)与服务端(网站)之间进行一次握手,在握手过程中将确立双方加密传输数据的密码信息。

这里写图片描述

  1. 老大掏钱 我要数字证书(公司没钱,自己想办法。。。)
  2. 权威机构发放 数字证书 (本地使用openssl 生成证书)
  3. 服务端部署 数字证书 (本地配置在nginx 中)
  4. 客户端请求
  5. 服务端 生成一对非对称加密的密钥对,然后把公钥发给客户端
  6. 客户端 收到公钥,生成一个随机数,作为上图中那一把密钥,用刚才收到的公钥加密这个密钥
  7. 客户端 发给 服务器。(儿子接着 我的密钥)
  8. 服务端 收到加密后的密钥,用本地的第一步自己生成的非对称加密的私钥解密,得到真正的密钥。(我丢你 得到密钥了 来来)
  9. 然后 客户端 和服务端 带着这个棒子 不对 ..密钥 在一起搞基. -,-

    以上内容为本人的一点拙见 如果有不对还望指出,多谢。(我的刀呢…)

2.openSSL生成数字证书

2.1 安装Openssl

下载地址:http://slproweb.com/products/Win32OpenSSL.html (根据系统选择32位或者64位版本下载安装)。

2.2 配置环境变量

变量名: OPENSSL_HOME 变量值:C:\OpenSSL-Win64\bin; (变量值为openssl安装位置)
在path变量结尾添加如下 : %OPENSSL_HOME%;

2.3 创建私钥

首先我们先在nginx 安装目录下 创建一个 ssl文件夹用于存放 数字证书相关文件,在当前文件夹右键打开命令行。

在命令行中执行命令: openssl genrsa -des3 -out ds.key 1024 (ds文件名可以自定义),如下图所示:
这里写图片描述

之后你就发现文件夹中已经出现了 后缀名为 .key 的文件

2.4 创建csr证书

在命令行中执行命令: openssl req -new -key ds.key -out ds.csr (key文件为刚才生成的文件,ds为自定义文件名)
这里写图片描述
其中key文件为刚才生成的文件。
执行上述命令后,需要输入一系列的信息。输入的信息中最重要的为Common Name,比如我输入的是localhost。其它的内容随便填。

2.5 去除密码

在加载SSL支持的Nginx并使用上述私钥时除去必须的口令,否则会在启动nginx的时候需要输入密码。
复制ds.key并重命名为ds.copy.key。
在命令行中执行如下命令以去除口令:openssl rsa -in ds.copy.key -out ds.key
这里写图片描述

2.6 生成crt证书

openssl x509 -req -days 365 -in ds.csr -signkey ds.key -out ds.crt

这里写图片描述

经过上边几个步骤,我们可以得到4个文件,我们主要使用到将会是key 和 crt文件。

到这里 openSSL 生成我们需要的数字证书已经说完,

3. tomact nginx 配置https

网上搜索到的很多文章在描述 Nginx + Tomcat 启用 HTTPS 支持的时候,都必须在 Nginx 和 Tomcat 两边同时配置 SSL 支持。但是我提供 配置的方案是浏览器和 Nginx 之间走的 HTTPS 通讯,而 Nginx 到 Tomcat 通过 proxy_pass 走的是普通 HTTP 连接

3.1 nginx 配置修改

我的这个文件在C:\nginx\conf目录下。用任意一个编辑器(如Sublime Text之类)打开这个nginx.conf文件

server {
        # http 默认端口为80 , https 默认端口为443
        listen       443 ssl;
        server_name  localhost;

        #这里地址是我服务器地址,你们按照自己文件路径填写注意//符号
        ssl_certificate      C://dsPulse//ssl//test.crt;
        ssl_certificate_key  C://dsPulse//ssl//test.key;

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

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

        location / {
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $http_host;
            proxy_set_header X-Forwarded-Proto https;
            proxy_redirect off;
            proxy_connect_timeout      240;
            proxy_send_timeout         240;
            proxy_read_timeout         240;
            # 我这里 转的地址是我的 tomact地址
            proxy_pass http://127.0.0.1:8080;

        }
    }

其中最为关键的就是 ssl_certificate 和 ssl_certificate_key 这两项配置,其他的按正常配置。不过多了一个 proxy_set_header X-Forwarded-Proto https; 配置

3.2 tomact修改

找到 tomact 安装路径,找到配置文件 server 文件


<?xml version='1.0' encoding='utf-8'?>
<Server port="8005" shutdown="SHUTDOWN">
  <Service name="Catalina">
    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="443"
               proxyPort="443"/>

    <Engine name="Catalina" defaultHost="localhost">

      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">

        <!-- SingleSignOn valve, share authentication between web applications
             Documentation at: /docs/config/valve.html -->
        <!--
        <Valve className="org.apache.catalina.authenticator.SingleSignOn" />
        -->

        <!-- Access log processes all example.
             Documentation at: /docs/config/valve.html
             Note: The pattern used is equivalent to using pattern="common" -->
    `   <Valve className="org.apache.catalina.valves.RemoteIpValve"
                  remoteIpHeader="x-forwarded-for"
                  remoteIpProxiesHeader="x-forwarded-by"
                  protocolHeader="x-forwarded-proto"
            />
      </Host>
    </Engine>
    </Engine>
  </Service>

但是特别特别注意的是必须有proxyPort=”443″,这是整篇文章的关键,当然 redirectPort 也必须是 443。同时 节点的配置也非常重要

修改完 tomact 后启动tomact ,启动 nginx 。建议使用 nginx 命令

常用的 nginx 命令
start nginx # 启动Nginx
nginx.exe -s stop # 快速停止Nginx,可能并不保存相关信息
nginx.exe -s quit # 完整有序的停止Nginx,并保存相关信息
nginx.exe -s reload # 重新载入Nginx,当配置信息修改,需要重新载入这些配置时使用此命令。
nginx.exe -s reopen # 重新打开日志文件
nginx -v # 查看Nginx版本

至于启动成功或者失败,则要看下 nginx/ log /log 文件查看是否有报错,如果成功 log包下会有一个 nginx.pid 文件。当然 也可以使用 postman 模拟访问测试 配置是否成功。

4 android 端代码修改

首先我这边 android 使用的 网络插件为 okhttp 当然如果您使用的是 retofit 道理是一样的 。

android 端需要key 文件来作为公钥,我们将服务器的 文件 下载到本地,将crt 文件转变为 cer文件,并且使用 编辑文件打开获取到 加密串,当然如果你不想将数据拿出来,也可以直接 在 android 工程下新建 raw 文件夹,详细操作 请查看 弘扬博客:弘扬 https

下图便是我项目中 okhttp util 部分代码

private OkHttpClient.Builder builder;
    private OkHttpClient client;
    private static MyOkHttp instance;

    private static final String SSL_KEY = "自己的key字符串";

    public MyOkHttp() {
        builder = new OkHttpClient.Builder().readTimeout(5, TimeUnit.SECONDS)
                .connectTimeout(8, TimeUnit.SECONDS)
                .writeTimeout(8, TimeUnit.SECONDS);
        SSLSocketFactory sslSocketFactory = getSSLSocketFactory(new Buffer().writeUtf8(SSL_KEY).inputStream());
        if (sslSocketFactory != null) {
            builder.sslSocketFactory(sslSocketFactory);
        };
        builder.hostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                // 强行设置证书 安全(其实是降低安全性了)
                return true;
            }
        });
        client = builder.build();
    }

/**
     *  ssl 工厂类
     * @param certificates certificates
     * @return SSLSocketFactory
     */
    private static SSLSocketFactory getSSLSocketFactory(InputStream... certificates) {
        try {
            CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null);
            int index = 0;
            for (InputStream certificate : certificates) {
                String certificateAlias = Integer.toString(index++);
                keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate));

                try {
                    if (certificate != null){
                        certificate.close();
                    }
                } catch (IOException e) {
                }
            }

            SSLContext sslContext = SSLContext.getInstance("TLS");

            TrustManagerFactory trustManagerFactory =
                    TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());

            trustManagerFactory.init(keyStore);
            sslContext.init
                    (
                            null,
                            trustManagerFactory.getTrustManagers(),
                            new SecureRandom()
                    );
            return sslContext.getSocketFactory();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

主要添加的东西就在 SSLSocketFactory sslSocketFactory = getSSLSocketFactory(new Buffer().writeUtf8(SSL_KEY).inputStream());这一行,buffer 为 okio中的,通过工厂类 获取到 SSLSocketFactory 。然后builder.sslSocketFactory(sslSocketFactory); 当然 这些设置完基本就可以了,但是由于 我的 ssl是自己生成的,所以如果 有跟我的情况是一样的 就需要添加 HostnameVerifier ,强制将证书 设置为 安全的,如果你的 ssl 是 权威机构发布的 则不用这样麻烦。

另外 由于项目 使用的混编,所以通过 webview 加载 https界面的时候出现了白屏的问题,这里也提一下 解决方案(截止 2018年7月26日 17:41:15):

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            // 允许其加载混合网络协议内容 (http https)
            webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
        }
webview.setWebViewClient(new WebViewClient() {
            @Override
            public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
                // 接收证书 (openssl 自己生成证书)
                handler.proceed();
            }
   }

上边代码 已经注释的很清楚 了,饿死了 加会班 溜了 ,该篇文章 比较初级,只用于记录自己的开发经历 和 知识点分享,如果您发现 鄙人 那里写的不对,麻烦指正 ,我会积极听取的 当然 我会带着我的刀 (:зゝ∠) 。。。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!