本地https/wss服务与SSL安全证书

前言

我之前在分析scratch3.0与micro:bit的通信提到https校验问题:

由于网站都逐渐过渡到https,而Scratch Link是个本地websocker server,要让Scratch Link与浏览器通信,需要使用wss协议。而本地websocker server采用openssl本地自生成的证书的话,浏览器要让用户在一个新页面里点击高级设置才行,体验很不友好.
scratch团队的解决方案十分聪明, 让device-manager.scratch.mit.edu这个域名指向127.0.0.1,websocker server就可以使用这个域名的证书。

我觉得这个机制对大多数在本地提供https/wss服务的软件都有用,于是写篇文章将讨论如何实现Scratch Link的本地证书机制

问题的一般形式

这个问题极具一般性,我们先抛开Scratch Link,来描述下它的一般形式。

你在本地写了一个软件(native application),软件内跑了一个本地的https/wss服务。https要求ssl证书,于是你使用openssl生成了本地证书。当你在浏览器中访问https/wss服务时,浏览器会阻止你访问https/wss服务,并提醒你存在安全问题,直到你点击下图的所示的地方,才能继续访问https/wss服务。

解决方案

这个问题相信大多数开发者都遇见过。社区里也出了一些解决方案:

前头的两个解决方案最具代表性,但面向的都是开发者,本质上是修改了本地的系统配置。对于普通用户并不理想。

所以我们将给出一个面向普通用户的解决方案。

思路其实很简单: 使用你的域名申请到安全证书,申请到证书后,将证书放在本地软件里,用于本地的https/wss服务,将证书对应的域名指向127.0.0.1

操作步骤

我们接着来详细描述操作细节。

我选择从Let's Encrypt获得证书

Let's Encrypt的使用方法可以参考:使用Let’s Encrypt(certbot)为你的网站生成免费的 SSL 证书

完成上文的操作我们就获得了Let’s Encrypt为我们网站颁发的证书,证书位置在形如/etc/letsencrypt/live/xxx.example.com/的目录里。接着我们将证书从服务器拷贝出来,放到本地软件里,用于本地的https/wss服务。举例来说,我使用python-socketio提供https/wss服务,我的配置为

    app.on_startup.append(start_background_tasks)
    if use_ssl:
        ssl_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
        ssl_context.set_default_verify_paths()
        ssl_context.load_cert_chain(resource_path('./cert.pem'), resource_path('./privkey.pem'))
        web.run_app(
            app,
            host=SOCKET_SERVER_HOST,
            port=SOCKET_SERVER_PORT,
            ssl_context=ssl_context,
        )
    else:
        web.run_app(app, host=SOCKET_SERVER_HOST, port=SOCKET_SERVER_PORT)

配置好后重启本地软件,可以看到Chrome已经信任本地的https/wss服务了!

接下来我们来讨论一些细节问题。

安全提醒

我不建议不要将通配符证书打包在本地软件中,万一加密过程没做好,证书泄漏,容易造成安全问题,具体可能造成的风险参考:域名的SSL证书泄漏对网站的安全性影响大吗?,主要的风险是攻击者可以利用受信任的证书发起中间人攻击,获取到用户的数据。

所以我单独为一个二级域名申请证书,只用于127.0.0.1,如此一来,即便不加密证书,也不会造成大问题。但加密总归是好的。

证书更新

Let's Encrypt颁发的证书,有效期是3个月,离过期还有30天以内可以renew证书。我们每三个月在服务器上更新证书自然不成问题,但如何同步更新用户机器上的证书呢,我的建议是在软件上做自动更新功能,定期去同步服务器上的证书。

当然也可以定期更新软件本身, 我目前使用Pyinstaller来跨平台打包应用程序。所以可以选择PyUpdater来自动更新软件。

如果你觉得太麻烦,可以考虑购买一个长期的安全证书。

如何调试

如果我们在Chrome中已经同意继续前往127.0.0.1,短期内刷新,Chrome就不会再做安全提醒,我们要确定新的安全证书是否生效,需要重新启用警告功能

参考




Fork me on GitHub