自签名https证书生成 (附赠nginx配置文件)

在日常的工作中经常会遇到需要服务器具有HTTPS的特性。当然对于拥有域名和公网IP的正常服务器来说,使用受信机构签名的证书是最好的选择。 但对于用于内网环境,或者是没有域名的测试服务器而言,自签名证书是折中的选择。这里介绍的是采用一张CA根证书签名服务器证书的情况。 更复杂的多级CA认证的情况这边不作深入探讨。

关于CA及https证书的简单描述

https简单讲就是将原本明文传输的http协议内容通过加密的ssl进行传输。说到数据的安全通讯,必然会涉及身份认证,密钥交换等内容。其中, 身份认证是用于识别通讯双方真的是你所要通讯的那个人,而这一点是保证交换的密钥是确实能保证通讯安全的关键。而CA的作用,就是为了作为 一个可信第三方来对通讯双方的身份作认证的机构。用某宝购物的思路解释,就是CA就相当于某宝,他负责对卖家及买家的资质进行认证, 保证买家确有其人,并有能力支付货款,而卖家也能真实发货。卖家和买家过淘宝的帐号进行交流,给钱,确定交易,就相当于网站和客户端 通过CA签名的证书进行密钥交换和数据通讯一样。而自签名的CA,就类似于某东,自己的店铺自己的货自己的网站自己担保。

因此,由上可知,CA的安全和可信是保证https通讯安全很重要的一点。因此,为了更高的安全性,某些复杂的场景下,可能不只一个CA存在。 以一家集团公司为例,假设集团公司总部的安全部门有一张CA证书,那下面所有证书如果都用这张证书签名,一方面会增加安全部门的人力成本, 另一方面频繁的使用一张CA证书签名,难免会在某次签名中造成证书泄漏等类似的情况。因此,集团的CA可能会为每家子公司签发属于子公司的 CA证书,子公司自己分别用这张CA证书对自己公司内的其他证书进行签名,这样即使子公司的CA泄漏了,并不会造成集团公司CA证书的泄漏, 集团公司只要废弃掉那张泄漏的CA证书,就可以使其CA签名的证书都失效,同样的,子公司也可为不同功能证书分别签发不同的CA证书,例如, 用于邮件认证的CA证书,用于软件安装的CA证书,用于https网站的CA证书。这些三级的CA证书将在子公司中应用于不同的业务场景。而对于最终用户 而言,他们只需要对集团公司的CA信任即可。而关于CA及安全通讯更详细的信息及原理,请自行查阅其他相关的专业文章。本文所涉及的内容只有 自签名的https证书生成。

密钥文件的生成

openssl genrsa -des3 -out server.key 4096

此处会要求你输入一遍密码,并确认一遍之前的密码,用于对密钥文件的加密。命令中的4096为密钥长度,数字越大越安全,但加密所用的开销也越大。 目前为止,建议在2048及以上,这里采用4096。

如果需要将密钥文件的密码去掉,则可使用一下命令操作。一般在服务器端需要访问密钥文件进行https通讯,所以会需要去掉密钥。

openssl rsa -in server.key -out server.key

创建服务器证书申请文件

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

这条命令执行后,会要求你填写一些服务器相关的信息。一般其他内容都可以随意填写,但对于https的证书而言,Common Name必须为你网站的域名。 生成的server.csr文件,是用来递交给CA让他来认证签名的。

CA证书的生成

openssl req -new -x509 -key server.key -out ca.crt -days 3650

利用server.key生成一张有效期为10年的CA证书 (没有考虑闰年平年的问题)。当然这里,如果为了提高安全性,可以为CA单独生成一个密钥文件进行生成, 这样客户端可以将这张签发的CA证书加入授信的CA中,而即使服务器上的server.key泄漏了也不能用这张CA证书签发新的证书。但这里为了偷懒,就直接用 服务器的密钥进行生成了。

为服务器签发证书

openssl x509 -req -days 3650 -in server.csr -CA ca.crt -CAkey server.key -CAcreateserial -out server.crt

通过以上命令,采用之前生成的CA证书,对之前的服务器证书申请文件进行签名认证,生成一张有效期为10年的证书。如果你之前为CA单独生成了一个密钥, 则这里 -CAkey server.key 替换成你实际生成CA证书的密钥文件。

生成文件之后如何操作

至此,我们已经完成了证书的生成。我们将得到 server.keyserver.csrserver.crtca.crt四个文件,如果你为CA单独生成个密钥, 可能还会有一个 ca.key的文件。其中,server.keyserver.crt 文件必须放在服务器上,server.csr 只有需要再次签名是才会用到, 其他时候基本等同于没用,删了也行。ca.crt 有需要的话,可以在客户端处导入为受信的CA,防止中间人攻击。同时如果需要服务器开启双向认证的话, 根据你实际的安全策略可能需要在服务器上可能也放一份。而CA可能的密钥文件 ca.key,一定要妥善保管

额外附送的nginx配置

证书需要在服务器上配置才能生效,这里附上nginx的参考配置文件。

server {
    listen       443 ssl http2;
    server_name  localhost;

    ssl_certificate server.crt;        # 这里为服务器上server.crt的路径
    ssl_certificate_key server.key;    # 这里为服务器上server.key的路径
    #ssl_client_certificate ca.crt;    # 双向认证
    #ssl_verify_client on;             # 双向认证

    ssl_session_timeout 5m;
    ssl_protocols SSLv2 SSLv3 TLSv1.1 TLSv1.2;
    ssl_ciphers  ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
    ssl_prefer_server_ciphers   on;

    # ... 以下为nginx的其他配置,此处省略
}

其中 ssl_ciphers 为服务器支持的算法,根据你服务器上的openssl而定,可以通过一下命令查看。另外,ssl_protocols为支持的ssl协议版本, 出于安全考虑,建议选择SSLv2及以上,但考虑到兼容性,需要支持TLS1.1。

openssl ciphers

最后总结

https是为了保证浏览器与服务器间通讯安全的手段,避免传输的内容被篡改及泄漏。一般而言,网站登入时需要将用户名和密码通过表单递交至服务器, 此时如果使用http的链接,则你的用户名和密码将以明文方式在网络上传输,极有可能被人窃取,另一方面网站用来记录访问这身份的cookies信息也可能 在明文传输中被泄漏。另一方面,由于http是明文传输因此内容也可能被第三方所篡改,例如在原本的网页上注入本不属于该网页的广告之类的。因此, https是保障通讯安全的一种策略。而自签名的https证书是在特殊情况下,使用https特性的手段,但由于证书是用自己虚构的CA签发的,因此在不能保证 CA证书安全的情况下,并不能拥有完全的https安全特性,同时CA证书密钥的泄漏还可能会引入额外的安全问题。所以,从更安全的角度出发,建议有条件的, 使用受信的CA机构签名的证书,如果一定要自签名,建议在能够保证CA密钥不被泄漏的情况下,将CA证书加到自己的受信CA中,否则的话,还是不建议 添加,只使用https的数据加密和认证的特性。