使用自签名CA证书搭建https网站,从http升级到https


声明如需转载,请通过邮箱联系本人或者注明出处,未经允许转载,必究 !!!
邮箱:zhangqihao@hnu.edu.cn

1、申请自签名证书

关于自签名证书,有两个工具,基于openssl和基于keytool,由于本次案例的开发语言是java,所以只介绍keytool,对openssl感兴趣的可以去查看官方文档以及技术大牛的博客。
Keytool 是一个Java 数据证书的管理工具 ,Keytool 将密钥(key)和证书(certificates)存在一个称为keystore的文件中。
在keystore里,包含两种数据:

  1. 密钥实体(Key entity)——密钥(secret key)又或者是私钥和配对公钥(采用非对称加密)
  2. 可信任的证书实体(trusted certificate entries)——只包含公钥
    关于keytool的命令参数,大家可以去参考官方文档,里面有非常详细的说明,比以及技术博客给出的详细多了,请认真查看,不过根据博主的步骤走,不理解也没有关系,如果只是单纯的实现项目需求而已

具体操作流程

  1. 生成服务器密钥库文件server.jks
keytool -genkey -alias server -keyalg RSA -keystore server.jks -validity 3650
输入密钥库口令:
再次输入新口令:
您的名字与姓氏是什么?
  [Unknown]:  127.0.0.1
您的组织单位名称是什么?
  [Unknown]:  cx
您的组织名称是什么?
  [Unknown]:  cx
您所在的城市或区域名称是什么?
  [Unknown]:  cx
您所在的省/市/自治区名称是什么?
  [Unknown]:  cx
该单位的双字母国家/地区代码是什么?
  [Unknown]:  CN
CN=127.0.0.1, OU=cx, O=cx, L=cx, ST=cx, C=CN是否正确?
[]:y
输入 <webserver> 的密钥口令
        (如果和密钥库口令相同, 按回车):

[解释]:生成的server.jks文件就是秘钥库,与.keystore格式的文件一样,都是秘钥库,不同格式而已
您的名字与姓名是什么?:这里一定要填写你服务器的域名,由于我是在本地测试就填写的本地IP
如果这里生成后,浏览器仍然有风险提示,使用扩展参数:

keytool -genkey -alias server -keypass [你的密码] -keyalg RSA -keysize 1024 -validity 365 -keystore server.jks -storepass [你的密码] -ext san=ip:127.0.0.1
  1. 通过server.jks导出服务器证书server.cer
C:>keytool -export -alias server -file server.cer -keystore server.jks
输入密钥库口令:
存储在文件 <server.cer> 中的证书

[解释]:此时从秘钥库server.jks中导出了server.cer证书文件,这个证书的作用就配置在浏览器或者是移动客户端(APP) ,以及这个证书就是自签名的证书,此时有的同学可能疑惑了,你可以使用命令行参数看下server.jks里面的内容是什么

 keytool   -list  -v  -keystore server.jks  
 输入秘钥库口令:
 密钥库类型: JKS
密钥库提供方: SUN

您的密钥库包含 1 个条目

别名: server
创建日期: 2018-12-29
条目类型: PrivateKeyEntry
证书链长度: 1
证书[1]:
所有者: CN=127.0.0.1, OU=cx, O=cx, L=cx, ST=cx, C=CN
发布者: CN=127.0.0.1, OU=cx, O=cx, L=cx, ST=cx, C=CN
序列号: 1f5419f8
有效期开始日期: Sat Dec 29 19:30:19 CST 2018, 截止日期: Tue Dec 26 19:30:19 CST 2028
证书指纹:
         MD5: CE:3C:70:0A:3C:8F:**:**:**:**:**:**:**:BF:B4
         SHA1: 92:6F:66:9E:A3:00:71:CC:45:07:C2:B8:05:73:DD:3B:A1:7C:E9:D3
         SHA256: 28:1F:84:06:9D:F6:37:C7:FD:**:E2:**:C1:**:**:95:F5:B7:BF:F0:EB:20:DF:26:C2:7C:1F:C9:DA:10:47:AB
         签名算法名称: SHA256withRSA
         版本: 3

扩展:

#1: ObjectId: 2.5.29.17 Criticality=false
SubjectAlternativeName [
  IPAddress: 127.0.0.1
]

#2: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 09 ** 03 42 ** 74 ** C8   DD B9 C3 2E 1A 8A D9 29  .m.B.tp........)
0010: 2E ** E4 D6                                        .,..
]
]



*******************************************
*******************************************

第二种方式-rfc输出

keytool -list  -rfc -keystore server.jks
输入密钥库口令:

密钥库类型: JKS
密钥库提供方: SUN

您的密钥库包含 1 个条目

别名: server
创建日期: 2018-12-29
条目类型: PrivateKeyEntry
证书链长度: 1
证书[1]:
-----BEGIN CERTIFICATE-----
MIIDWjCCAkKgAwIBAgIEH1QZ+DANBgkqhkiG9w0BAQsFADBVMQswCQYDVQQGEwJD
TjELMAkGA1UECBMCY3gxCzAJBgNVBAcTAmN4MQswCQYDVQQKEwJjeDELMAkGA1UE
CxMCY3gxEjAQBgNVBAMTCTEyNy4wLjAuMTAeFw0xODEyMjkxMTMwMTlaFw0yODEy
MjYxMTMwMTlaMFUxCzAJBgNVBAYTAkNOMQswCQYDVQQIEwJjeDELMAkGA1UEBxMC
Y3gxCzAJBgNVBAoTAmN4MQswCQYDVQQLEwJjeDESMBAGA1UEAxMJMTI3LjAuMC4x
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoqjg9vVN6mOj+vpsJVR8
****************************************************************
****************************************************************
oLM9iRO1PluJ59fJpZtKi4ZOxGtVk8K6GUth+EHNtin1lsT81K1NexMg/GpK5ISp
Wy/HznFLs9xbIJR3YyZcW5uABo5hgKhFHATOF+thrVYn39ABgfdtNBcmzEAJgLdx
DeiXzgtOKm5a6vycwPvAD4D6BOXJsUzkCzBXJL2sxRXcEaDBAIcsIVHWHvuPvUMn
9QIDAQABozIwMDAPBgNVHREECDAGhwR/AAABMB0GA1UdDgQWBBQJbQNC8XRwyN25
wy4aitkpLizk1jANBgkqhkiG9w0BAQsFAAOCAQEAbR8atpOtwUHpXsq57i3M5Or7
5fWDd32OWxEWkO/YPny2cEoG3GwUaJvZTieLCdtO1H1KHOg29akVgf2s6L3b4b8R
ljNt9T3eawuIa0qPh92vgKvcLFWroJ3ONLDPecJZpORnVyJ9OxzbtABlfkFqWQB+
****************************************************************
uRRn3q0iPBIQAaHEp0utxzlLh86k9Q0amNdZTHKWn7unLu5xwKh5tXaKgZc5/3yL
eMehq+iemjYRh1q7SqO9KqpnffTBSGMH5nN0nhdbFLO2aGydrfpc5zhT3lr4iQ==
-----END CERTIFICATE-----


*******************************************
*******************************************

这种输出方式直接可以查看公钥,至于私钥是什么,大家可以不必知道,只需要知道在server.jks里面就可以了,不影响你的项目进行
【注意】这里输出的公钥,是为了方便移动客户端(APP)的配置
至此,生成证书完毕,有的技术博客写的很复杂,生成了两对公私钥,让入门学者看的眼花缭乱,我在这里强调下,自签名的大可不必使用证书链,作为学习使用,本文中提出的步骤足够,不需要再生成额外的公私钥去生成客户端的证书,再导入的根证书的秘钥库中,这里可以直接使用根证书 ! ! !

2、配置服务器

把server.jks复制到项目中的根目录下面
由于博主的项目中使用的是springboot,内嵌了tomcat,所以比较简单,直接在pom文件中配置即可

server:
  #服务端口
  port: 8001
  servlet:
    # 项目contextPath
    context-path: /
  tomcat:
    # tomcat的URI编码
    uri-encoding: UTF-8
    # tomcat最大线程数,默认为200
    max-threads: 800
    # Tomcat启动初始化的线程数,默认值25
    min-spare-threads: 30
  ssl:
    key-store: server.jks
    key-store-type: JKS
    key-password: "password"
    key-alias: server

【友情提示下】:一般实际工程中都是nginx中直接配置的,但是直接这样配置也没有关系,可以使用

3配置浏览器

为了让浏览器相信我们的证书签发机构,我们必须手动导入根证书,这里以Chrome浏览器为例,打开设置选项,选择高级功能
在这里插入图片描述
点击下一步把我们要导入的server.cer证书文件安装即可~
这样打开浏览器访问主页,就不会出现此网站不安全的提示了,如图
在这里插入图片描述
而不是像这样:
在这里插入图片描述
192.168.1.106是我的网络IP,由于我的证书上填写的是本地IP是127.0.0.1,所以这里使用192.168.1.106访问就是有危险,这个浏览器与服务器的认证机制大家可以去看下文档,关于ssl的过程就理解了。我在这里不再做叙述。

到此,浏览器的配置结束~

3、移动客户端的配置

在移动端(APP)使用,大家经常要使用接口去访问一些服务器的资源,都是通过http协议去get、post,那么从http升级成了https怎么办?原来的方式肯定行不通,关于移动端服务器,大多数采用的https的都是使用自签名,那么如何让安卓系统相信我们使用的证书是安全的呢?
我们需要自己定义trustManager
Okhttp大家一定不陌生,具体介绍请访问官网,我在这里不做叙述。
网上给的资料Okhttp for https的答案各种各样,良莠不齐,大多数都是根据自己的项目来的,代码贴到自己的项目中根本不能起到作用,就算国外的Stack Overflow上回答的不是过时了,就是信任了所有的证书,直接不去验证证书的有效性,这样做配置https就没什么意义了。
我在这里给出一种方案,大家不必去了解原理怎么样,为了项目进行下去,直接使用即可,其实去了解原理,热认真看下代码就豁然开朗了,你会感叹,自己怎么写不出这么好的代码。但是能让项目进行下去,先直接用,火头再看原理,自己也是可以封装出来的。
我这里给出一个github上封装好的Okhttp for https的库,大家拿来用

Android Studio

compile 'com.zhy:okhttputils:2.6.2'

在添加代码,定义MyApplication 继承 Application,然后在manifests文件中注册MyApplication
这里只要是安卓开发入门者都懂什么意思,这里使用的myke就是我们第一步使用-rfc查看到的公钥

public class MyApplication extends Application
{
    private String mykey = "-----BEGIN CERTIFICATE-----\n" +
            "MIIDWjCCAkKgAwIBAgIEH1QZ+DANBgkqhkiG9w0BAQsFADBVMQswCQYDVQQGEwJD\n" +
            "TjELMAkGA1UECBMCY3gxCzAJBgNVBAcTAmN4MQswCQYDVQQKEwJjeDELMAkGA1UE\n" +
            "CxMCY3gxEjAQBgNVBAMTCTEyNy4wLjAuMTAeFw0xODEyMjkxMTMwMTlaFw0yODEy\n" +
            "****************************************************************\n" +
            "Y3gxCzAJBgNVBAoTAmN4MQswCQYDVQQLEwJjeDESMBAGA1UEAxMJMTI3LjAuMC4x\n" +
            "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoqjg9vVN6mOj+vpsJVR8\n" +
            "agjZaRoCRaSv+erSI0uh3aav42oSBw7C0Nn75h+oj4FbjENa6N+ObNIqw0GQHwBA\n" +
            "awc5EjRavJ8ys4mrlpbCaFhNDMUl3OX2Rg+cuZmi9E7y4IwE0abVL4FGyR3AGU2B\n" +
            "****************************************************************\n" +
            "Wy/HznFLs9xbIJR3YyZcW5uABo5hgKhFHATOF+thrVYn39ABgfdtNBcmzEAJgLdx\n" +
            "DeiXzgtOKm5a6vycwPvAD4D6BOXJsUzkCzBXJL2sxRXcEaDBAIcsIVHWHvuPvUMn\n" +
            "9QIDAQABozIwMDAPBgNVHREECDAGhwR/AAABMB0GA1UdDgQWBBQJbQNC8XRwyN25\n" +
            "****************************************************************\n" +
            "5fWDd32OWxEWkO/YPny2cEoG3GwUaJvZTieLCdtO1H1KHOg29akVgf2s6L3b4b8R\n" +
            "ljNt9T3eawuIa0qPh92vgKvcLFWroJ3ONLDPecJZpORnVyJ9OxzbtABlfkFqWQB+\n" +
            "****************************************************************\n" +
            "uRRn3q0iPBIQAaHEp0utxzlLh86k9Q0amNdZTHKWn7unLu5xwKh5tXaKgZc5/3yL\n" +
            "eMehq+iemjYRh1q7SqO9KqpnffTBSGMH5nN0nhdbFLO2aGydrfpc5zhT3lr4iQ==\n" +
            "-----END CERTIFICATE-----";
    
    @Override
    public void onCreate()
    {
        super.onCreate();

        ClearableCookieJar cookieJar1 = new PersistentCookieJar(new SetCookieCache(), new SharedPrefsCookiePersistor(getApplicationContext()));//设置缓存cookie,持久化cookie

        HttpsUtils.SSLParams sslParams = HttpsUtils.getSslSocketFactory(new InputStream[]{new Buffer().writeUtf8(mykey).inputStream()}, null, null);

//        CookieJarImpl cookieJar1 = new CookieJarImpl(new MemoryCookieStore());
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(10000L, TimeUnit.MILLISECONDS)
                .readTimeout(10000L, TimeUnit.MILLISECONDS)
                .cookieJar(cookieJar1)
                .hostnameVerifier(new HostnameVerifier()
                {
                    @Override
                    public boolean verify(String hostname, SSLSession session)
                    {
                        return true;
                    }
                })
                .sslSocketFactory(sslParams.sSLSocketFactory, sslParams.trustManager)
                .build();
        OkHttpUtils.initClient(okHttpClient);

    }

}

【关于代码我就不解释了,大家都能看懂】
接下来直接在程序中使用OkHttpUtils就可以了

自定义MyStringCallback()

 public class MyStringCallback extends StringCallback
    {
        @Override
        public void onBefore(Request request, int id)
        {
            setTitle("loading...");
        }

        @Override
        public void onAfter(int id)
        {
            setTitle("Sample-okHttp");
        }

        @Override
        public void onError(Call call, Exception e, int id)
        {
            e.printStackTrace();
            mTv.setText("onError:" + e.getMessage());
        }

        @Override
        public void onResponse(String response, int id)
        {
            try {
                mTv.setText(balance);
            } catch (JSONException e) {
                e.printStackTrace();
            }
            Log.e(TAG, "onResponse:complete");
        }

        @Override
        public void inProgress(float progress, long total, int id)
        {
            
        }
    }

这里我给出get https 的例子

String url = "https://192.168.*.*:8080/*";
        OkHttpUtils
                .get()//
                .url(url)//
                .addParams("key","value".build()//
                .execute(new MyStringCallback());

至此,移动端配置完毕。
如果按照我的步骤一步步走,是不会出错的,如果有Bug,请各位仔细检查~
如果仔细看下这位大神封装的内容,很容易就理解了~
本文所写的文章足以应对项目需求了,后期优化就根据各位的业务逻辑需求了,如有问题欢迎讨论~

邮箱:zhangqihao@hnu.edu.cn
如需转载,请通过邮箱联系本人或者注明出处,未经允许转载,必究 !!!

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值