做为一个喜欢折腾的人,我的搞了不少东西放在本身的服务器上,可是为了方便,可以在世界各地随时随地的打开查看和使用,我将服务器暴露到了公网中,固然了有些在公有云上的原本就暴露出来的。html
那么这里就有一个问题,我如何保护个人信息只能我来查看呢?git
我想了许久,有没有一种不须要输入密码,就能够验证安全的呢?由于是我一我的使用的,因此我根本不须要多用户系统,也就是说验证方式只须要一个密码就能够了。这我忽然想起了以前在写 gRPC 的时候有一个双向验证的参数,也能够验证客户端能够不能够。当时以为只是他们基于 h2 改的协议,结果我一查发现这原来就包含在 https 里面,准确说是 SSL 规范里面。(怪本身当初上计算机网络的时候没好好学这部分,居然连这个都不知道)github
那么至此,思路就很清晰了,给个人全部我的服务都添加 https 客户端校验。只要个人证书够安全,个人页面就是安全的(反正都是我我的的东西,直接拿着 U 盘处处拷贝,手机 Pad 用数据线发送,我就不信这样谁还能盗走个人证书,傲娇脸)算法
openssl
具体的安装教程我就不讲解了,有兴趣的小伙伴自行查阅,主要有下面几个步骤:
openssl genrsa
:生成 Private Key,用于生成请求文件使用,这里用 .key
后缀。openssl req
:依赖上面生成的 Key 去生成 CSR,也就是证书请求文件。使用 .csr
后缀。这期间要填写一些信息,前面的几个大写字母是缩写,后面在命令行使用的时候会用到。
openssl x509
:根据 x509 规范,利用 CA 的证书和私钥将 CSR 文件加密成真正可使用到的证书。使用 .crt
后缀-sha-256
参数。CRT
和 PEM
的关系,你们能够简单的认为 PEM
是将证书 base64 以后的文件,而 CRT
是既能 base64 也能 binary 的一种文件格式。可是一般 openssl
产出的是 base64 的文件,你能够经过 -outform
参数控制产出的类型。有了 CA 咱们才能去给其余的证书签名,生成 CA 的过程很简单api
这个秘钥很是重要,任何得到了这个秘钥的人在知道密码的状况下均可以生成证书。因此请当心保存浏览器
openssl genrsa -des3 -out root.key 4096
复制代码
-des3
标明了私钥的加密方式,也就是带有密码。建议添加密码保护,这样即便私钥被窃取了,依旧没法对其余证书签名。你也能够更换其余的加密方式,具体的请自行 help。4096
表示秘钥的长度。由于是 CA 证书,因此无法让别人去签名,只能自签名。这里能够认为是生成 CSR 和签名两部合成一步走。安全
openssl req -x509 -sha256 -new -key root.key -sha256 -days 1024 -out root.crt
复制代码
openssl genrsa -out your-domain.com.key 2048
复制代码
和 CA 证书不一样,这个私钥通常不须要加密,长度也能够短一些。服务器
openssl req -new -key your-domain.com.key -out your-domain.com.csr
复制代码
这期间要填入一些信息,注意 CN 的名字必定要是你的域名。网络
在 Chrome 58 以前,Chrome 会根据 CN 来检查访问的域名是否是和证书的域名一致,可是在 Chrome 58 以后,改成使用 SAN(Subject Alternative Name) 而不是 CN 检查域名的一致性。dom
而 SAN 属于 x509 扩展里面的内容,因此咱们须要经过 -extfile
参数来指定存放扩展内容的文件。
因此咱们须要额外建立一个 your-domain.com.ext
文件用来保存 SAN 信息,经过指定多个 DNS 从而能够实现多域名证书。
subjectAltName = @alt_names
[alt_names]
DNS.1 = your-domain.com
DNS.2 = *.your-domain.com
DNS.3 = *.api.your-domain.com
复制代码
以此类推,若是域名较少,还能够用另一种简写方案。
subjectAltName = DNS: your-domain.com, DNS: *.your-domain.com
复制代码
关于语法的更多内容请查看官方文档。在有了 ext 文件以后就直接能够开始签名了。
openssl x509 -req -sha256 -in your-domain.com.csr -CA root.crt -CAkey root.key -CAcreateserial -out your-domain.com.crt -days 365 -extfile your-domain.com.ext
复制代码
CAcreateserial
这个参数是比较有意思的,意思是若是证书没有 serial number 就建立一个,由于咱们是签名,因此确定会建立一个。序列号在这里的做用就是惟一标识一个证书,当有两个证书的时候,只有给这两个证书签名的 CA 和序列号都同样的状况下,咱们才认为这两个证书是一致的。除了自定生成,还能够经过 -set_serial
手动指定一个序列号。
当使用 -CAcreateserial
参数以后,会自动建立一个和 CA 文件名相同的,可是后缀是 .srl
的文件。这里存储了上一次生成的序列号,每次调用的时候都会读取并 +1 。也就是说每一次生成的证书的序列号都比上一次的加了一。
如今,只须要将 your-domain.com.crt
和 your-domain.com.key
放到服务端就可使用了。别忘了将 CA 添加系统当中,要否则浏览器访问会出现问题。
服务端有了以后,就须要生成客户端的证书,步骤和服务端基本一致,可是不须要 SAN 信息了。
openssl genrsa -out client.key 2048
# 这里也能够采用非交互形式,方便制做成命令行工具
openssl req -new \
-key client.key \
-subj "/C=CN/ST=Zhejiang/O=X/CN=*.your-domain.com" \ # 这里的缩写就是文章一开始所说的那些缩写
-out client.csr
openssl x509 -req -in client.csr -CA root.crt -CAkey root.key -out client.crt -days 365
复制代码
只不过客户端验证须要的是 PKCS#12 格式,这种格式是将证书和私钥打包在了一块儿。由于系统须要知道一个证书的私钥和公钥,而证书只包含公钥和签名,不包含私钥,因此须要这种格式的温江将私钥和公钥都包含进来。
openssl pkcs12 -export -clcerts -in client.crt -inkey client.key -out client.p12
复制代码
这期间会提示你输入密码,用于安装的时候使用。也就是说不是什么人均可以安装客户端证书的,要有密码才行,这无疑又增长了必定的安全性。固然了,我试过不输入密码,可是好像有点问题,有兴趣的同窗能够本身尝试下。
这里以 Node.js 举例。使用 https
模块,在建立的时候和普通的建立方式基本一致,可是须要额外指定 requestCert
和 ca
参数来开启客户端校验。
https.createServer({
key: fs.readFileSync('your-domain.com.key'),
cert: fs.readFileSync('your-domain.com.crt'),
requestCert: true,
ca: [fs.readFileSync('root.crt')], // 校验客户端证书的 CA
}, (req, resp) => {
// blahblah
})
复制代码
这样只要客户端没有安装合法的证书,那么整个请求就是失败的。并且根本不会进入请求处理的回调函数中,这也意味着显示的错误是浏览器的默认错误。那么这对用户来说其实不太友好。
那么咱们能够经过在参数中添加 rejectUnauthorized: false
来关闭这个功能,也就是说无论客户端证书校验是正确仍是失败,均可以进入正常的回调流程。此时咱们只须要经过 req.client.authorized
来判断这个请求是否经过了客户端证书的校验,能够给予用户更详尽的错误提示。
另外咱们还能够经过 resp.connection.getPeerCertificate()
获取客户端证书的信息,甚至能够根据不一样的信息选择给予不一样的用户权限。
这里有一个 DEMO: www.xgheaven.net.cn:3443,你们打开以后应该会看到一个证书校验失败的提示。这里要说下,我这里的 DEMO 没有使用自签名的服务端证书,只是使用了自签名的 CA 去检查客户端证书。由于用本身签名的服务端证书的话,浏览器会提示不安全,由于用户么有安装自签名的 CA。
能够点击下载客户端证书按钮,安装客户端证书。由于客户端证书是有密码保护的,请输入页面上提示的密码。
再次刷新,若是是 Mac 系统,会提示你要使用哪一个客户端证书登陆,此时就说明安装成功了。
点击确认,可能还要输入一个系统密码容许 Chrome 访问 Keychain,一劳永逸的话在输入密码以后选择 Always Allow,今后就不须要再输入密码了。
按照道理,你就能够看到这个页面了。
有了这个功能,我就能够将个人全部内容全盘私有化并且还能直接暴露在公网中。配合以前毕设搞的微服务化,简直不要美滋滋。若是以前是使用帐号密码登陆的,也能够接入这个方案。就是将登陆页面替换成证书校验就能够了。