如何自签名SSL证书

2018年9月27日 0 作者 筱枫

网上许多有关自签证书的相关文章,但大多数都已经过时,或者是没有把一些细节给写上,今天绕了不少的远路,终于配好证书,现将其记录下来

SSL证书用来做什么?

通常都用来加密数据,是https的基础

多余的理论上面就不细提了,感兴趣的可以自行寻找相关资料查看,这里直接写实际步骤

首先,证书分类两种
1.自签证书
2.私有ca签名证书

主要的区别如下:
ca证书是一种特殊的自签证书,也就是通称的根证书,其主要用于给其他证书签名,如果信任了ca证书,则被其签名的所有证书,都默认被信任,且ca证书可吊销被签名的证书
自签证书…就是普通证书,没有上面那些功能,也就是如果你有多个自签证书,你就要给每台机器都安装这个自签证书才行,相反,ca证书只需要安装一次即可,其下所有被签名的证书都是可以信任的

现在开始实践,创建自签证书

工具为openssl

1、首先创建私钥

openssl genrsa -out server.key 2048

最后面的2048是加密位数,位数越大越安全,相反,加密解密时间也就会越长

2、生成 CSR

openssl req -new -key server.key -out server.csr

输入这条命令后,会让你依次输入各种信息,依次输入即可,注意其中的Common Name,这里一般填写你的域名或者ip,可以使用通配符*来匹配一级子域名

3、生成自签证书

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

其中的365表明这个证书的有效期是365天,当然你也可以写个3650来表示10年2333

ok,现在有了,接下来在nginx当中配置一下证书,再用浏览器打开,注意,这里为了方便测试,使用IE,因为chrome或者firefox,还需要做一些额外的操作
我的nginx配置如下

server {
    listen 443 ssl;
    server_name hello.test;
	root /root/temp/www;

    ssl on;
    ssl_certificate /root/temp/server.crt;
    ssl_certificate_key /root/temp/server.key;
    
    client_max_body_size 50M;
    
	location / {
    }
}

同时使用的修改hosts的方式,将hello.test指向我的ngixn服务器
接着在浏览器中输入https://hello.test
嗯…

为何会出现这个东西?
很正常,因为你的证书不被浏览器所信任
为何访问其他的,像是百度、qq、网易的https都没有任何问题呢?
难道浏览器默认信任它们所有的证书么?
其实这就是ca证书的用途,浏览器所信任的证书是windows内置的ca证书所签名的证书
而百度、网易等https都是用的被信任的大公司的ca证书所签名,所以也可以被浏览器信任
而这些大公司一般就那么几家,所以————内置完全没有什么问题

上面那是题外话,现在我们来解决自签名证书不被信任的问题
这里有两个办法,一个是把crt的证书弄到windows下面,然后双击进行安装,注意安装的时候选择将证书安装至 “受信任的根证书颁发机构”即可
另外一个方法类似,不同的是直接在ie中选择“转到此网页(不推荐)”
然后在地址栏右上角,有个红色的证书错误,点开,再点击查看证书也可以安装,注意也是要安装至“受信任的根证书颁发机构”

接着重启下浏览器,再进行访问,可以看到页面上已经没有https错误的提示了

但是,如果你用chrome来访问的话,还是会提示https错误,哪怕再怎么重启浏览器也没有用,这是为什么呢?
从chrome 58开始,不仅仅验证Common Name,还要验证SAN(Subject Alternative Name),既使用者可选名称,在现在的证书上,可以看到长这样

是不是很眼熟,跟Common Name差不多,优势在于一张证书可以被多个域名所使用,因为 *.google.com 是不能匹配到 abc.ced.google.com,如果单独为了这个域名而多弄一张证书,很不划算,所以就有这个东西
那么,如果增加这个SAN呢?
大致流程跟之前差不多,但是要稍微增加点东西
首先将 /etc/pki/tls/openssl.cnf 复制到当前目录下
然后在最末尾增加几段

[SAN]
subjectAltName=DNS:hello.test,DNS:*.hello.test

注意其中的DNS:*.hello.test不是必要的,这里写在这里只是为了说明如果有多个的话可以这么写
接着跟刚刚一样,生成server.key,然后生成CSR

openssl req -new -key server.key -reqexts SAN -config ./openssl.cnf  -out server.csr

-regexts表明使用SAN区段的内容,-config则是指定配置文件
然后再像刚刚一样填写数据对应的信息
最后,签名的时候也注意要加上配置文件参数

openssl x509 -req -days 365 -in server.csr -signkey server.key -extensions SAN -extfile ./openssl.cnf -out server.crt

接着,重启nginx服务器(或者reload配置),重新信任新的证书,然后chrome中打开网址


下面实践如何生成CA证书以及用CA证书签名

生成CA证书跟自签证书类似
输入以下两段命令

openssl genrsa -out ca.key 2048  #生成私钥
openssl req -new -x509 -days 365 -key ca.key -out ca.crt    #自签名证书

跟生成自签证书一模一样,注意这里面的ca.key这类名称可以随意更换,这里起名ca只不过是更方便说明罢了
同时这里面的Common Name可以不用填写域名,可以写一些注释之类的,例如像是CA证书的说明,我这里写的是test CA

接下来先将这个ca.crt安装到 windows 下面的 “受信任的根证书颁发机构”中,然后我们再生成一张新的证书,并用ca证书对它签名,然后来试试看效果

openssl genrsa -out server_ca_test.key 2048
openssl req -new -key server_ca_test.key -out server_ca_test.csr
openssl x509 -req -days 365 -in server_ca_test.csr -CA ca.crt -CAkey ca.key -set_serial 1 -out server_ca_test.crt   #注意这里,不再是自签名,而是使用的CA证书签名

其中的set_serial 1表明指定序号为1
这里面的Common Name不能和CA证书中的一样,这里为了方便测试,直接设置为hello.test

然后,我们不必将这个server_ca_test信任,直接放入nginx配置中,别忘了重启nginx或者重载配置!

ssl_certificate /root/temp/server_ca_test.crt;
ssl_certificate_key /root/temp/server_ca_test.key;

现在我们在IE浏览器中访问hello.test看看

注意查看证书链,很明显是用我们刚刚的test CA证书签名,隶属于CA证书下,自然而然就会被信任

当然,现在这个证书还是没有办法在chrome中访问,我们只需要像刚刚一样,带上SAN即可

openssl req -new -key server_ca_test.key -reqexts SAN -config ./openssl.cnf  -out server_ca_test.csr
openssl x509 -req -days 365 -in server_ca_test.csr -CA ca.crt -CAkey ca.key -set_serial 1 -extensions SAN -extfile ./openssl.cnf -out server_ca_test.crt

别忘了重启nginx或者重载配置
然后在浏览器中就可以看到hello.world!

证书链也没有任何问题,如此,相关的说明就讲到这里
如果你觉得签署SAN太过复杂,可以考虑用一条命令

openssl req -new -key server_ca_test.key \
-reqexts SAN \
-config <(cat /etc/pki/tls/openssl.cnf \
<(printf "[SAN]\nsubjectAltName=DNS:hello.test,DNS:*.hello.test")) \
-out server_ca_test.csr

引用参考:
1.如何创建自签名的 SSL 证书
2.OpenSSL SAN 证书