iOS 访问使用自签名证书服务

起因

最近被一位前端同事咨询怎么通过 iOS 微信浏览器访问本地使用自签名证书服务,略微折腾了下,有不少小坑,感觉还是值得记录一下。需要注意的是,我们是在类似微信浏览器这种非我们可控的浏览器环境下,而不是原生应用下访问 https 服务 —— 原生应用可以通过重写证书链信任流程来实现,详见Customising HTTPS Server Trust Evaluation

服务架设

本地服务使用 node 搭建,具体流程可以参考 《Painless Self Signed Certificates in node.js 》,其他语言/环境大体配置相差不大。

步骤如下

  • 签发 CA 证书和私钥
  • 通过 CA 证书签发下一级的证书,即后续需要用到的服务端证书和私钥
  • node 配置使用对应的证书和私钥

iOS 设置

由于证书一般是签发给域名,所以后续只能通过域名进行访问:理论上证书也是可以签发给 IP,但我并没有做相应尝试,主要考虑到本地 IP 有可能经常变动,反倒是域名更加方便。

但由于 iOS 设备无法直接设置 Host,所以这个流程相对会比较曲折。

  • mac 中修改 Host,将 127.0.0.1 指向上一步中签发证书对应的域名
  • 通过 Charles 之类的工具开启本地代理
  • iOS 端设置代理为 macIP 地址
  • CA 证书导入至 iOS 设备
  • 通过 设置 - 通用 - 关于本机 - 证书信任设置 设置信任当前导入 CA 证书
  • 通过 iOS 中的微信浏览器直接访问 https 地址

备注

  • 必须通过 CA 证书签发下一级证书,而 不能直接使用自签名证书,否则后续证书链校验将失败。一般会出现类似 DEPTH_ZERO_SELF_SIGNED_CERT 错误

  • wiki 代码中会有注入证书私钥的过程,在实际操作中并不需要

  • mac 中使用 Chrome 访问时,即使系统选择信任当前 CA 证书也是无用,建议在配置时使用 Safari 做测试 (神坑)

  • 现在 Let's Encrypt 已然非常成熟,且由他们签发的证书已经被绝大部分系统和浏览器所信任,所以最方便的路径是通过他们进行证书签发,而不再需要往 iOS 设备导入 CA 证书

  • iOS 方面关于 HTTPS 认证的技术细节,推荐阅读 Technical Q&A QA1948Technical Note TN2232