惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
The Exploit Database - CXSecurity.com
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Spread Privacy
Spread Privacy
Hacker News - Newest:
Hacker News - Newest: "LLM"
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Google Online Security Blog
Google Online Security Blog
S
Security Affairs
Help Net Security
Help Net Security
Simon Willison's Weblog
Simon Willison's Weblog
N
News and Events Feed by Topic
P
Palo Alto Networks Blog
P
Privacy International News Feed
T
Threat Research - Cisco Blogs
P
Proofpoint News Feed
N
News and Events Feed by Topic
C
Cyber Attacks, Cyber Crime and Cyber Security
TaoSecurity Blog
TaoSecurity Blog
T
Tor Project blog
Schneier on Security
Schneier on Security
WordPress大学
WordPress大学
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
V
Visual Studio Blog
F
Fortinet All Blogs
大猫的无限游戏
大猫的无限游戏
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
Tenable Blog
M
MIT News - Artificial intelligence
T
Threatpost
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
N
News | PayPal Newsroom
P
Privacy & Cybersecurity Law Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
Microsoft Azure Blog
Microsoft Azure Blog
小众软件
小众软件
Cyberwarzone
Cyberwarzone
雷峰网
雷峰网
云风的 BLOG
云风的 BLOG
量子位
Google DeepMind News
Google DeepMind News
O
OpenAI News
爱范儿
爱范儿
H
Hackread – Cybersecurity News, Data Breaches, AI and More
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
F
Full Disclosure
B
Blog
Cloudbric
Cloudbric
MyScale Blog
MyScale Blog
阮一峰的网络日志
阮一峰的网络日志

木匣子

以 Maildir 方式备份邮件 后疫情之中国行 我的 Covid 经历 写在 2021 年末 在 macOS 上使用 eGPU 的体验 给 Apollo-Link 打补丁 II 动森二维码生成器:服装类(后篇) 动森二维码生成器:服装类(前篇) 动森二维码生成器 for Aseprite 动森图鉴+开发笔记 给 Apollo-Link 打补丁 「攻略」JetBrains Quest S1E3 「攻略」JetBrains Quest S1E2 「攻略」JetBrains Quest S1E1 助你同时维护多个项目的终端神器:Tmux 中文博客的字体选型 使用 Webpack Loader 加载 Icon Font 映射 写在 2019 年末 Edge 浏览器无法访问 VirtualBox 内的网站
创建自签名 SSL 证书
Lingjia · 2022-04-03 · via 木匣子

疫情仍然在继续,但是维州已经开始恢复生机。我大概又歇了小半年,除了工作时间,下班之余几乎没有碰与技术相关的东西。同时由于近来关注了太多社会新闻,反而让自己陷入了政治性抑郁。刷推的时候刷到一个无聊的放置类手游竟随手下载来玩了一个星期,也算放空一下自己,转移注意力,好重振旗鼓。 回顾了一下半年多以前开发的 Axidraw Web,有不少可以分享的点东西,准备挑几个记录一下。

AxiDraw 是一个双电机的二维绘图仪。可以将 SVG 绘制到纸面上。在研究完它的底层串口协议后,我尝试用 javascript 实现了一个能在网页上运行的 Web 小程序,能通过 WebUSB API 与 AxiDraw 单片机直接进行通讯,同时实现了 SVG 的绘制功能。

¶WebUSB

在开发 Axidraw Web 的时候,由于 WebUSB API 需要在安全的浏览器环境下(Secure Contexts)才能使用。在较早的 Chrome 浏览器上(version 83 之前),localhost 是否属于 Secure Contexts 尚未确定。而这类 API 默认只对 https://localhost 开放。在我写这篇文章的时候,文档中已经明确将 localhost 定义为安全环境。如果在开发环境中使用了较老的浏览器或者其它的自定域名,还是需要自行提供 TLS 支持。主要工作就是提供一个自签名证书,然后在 web server 中使用:

import express from 'express';
import https from 'https';
import fs from 'fs';

const app = express();
app.use(express.static('dist'));

const options = {};

try {
  options.key = fs.readFileSync('server/cert/dev.key');
  options.cert = fs.readFileSync('server/cert/dev.crt');
} catch (e) {
  console.error('Please create and install the SSL cert first.');
  process.exit(1);
}

const server = https.createServer(options, app).listen(8443);

¶Webpack-dev-server

AxiDraw Web 项目使用 Webpack 打包,很自然的想到 Webpack-dev-server 的 https 配置项。可以简单将其设置为 true 即可启用 https 协议。

module.exports = {
  //...
  devServer: {
    https: true,
  },
};

运行后 Webpack-dev-server 会自动生成一个有效期 30 天的临时根证书。储存在 node_modules/webpack-dev-server/ssl/server.pem 手动将该文件导入 Keychain 并认 SSL 项目即可获得浏览器绿锁。

trust-ssl-in-keychain

不过这个方法几个缺点:该根证书的有效期只有 30 天,过期后要重新信任证书;证书内只签发了 localhost、127.0.0.1 以及一个奇怪的内部域名 lvh.me,无法满足一些 LAN 跨设备调试的需要。

¶OpenSSL

于是我又想,能不能根据自己的需求手动创建自签名证书来使用。经过一番研究,最终搞定了基于 OpenSSL 的证书生成过程。

首先我们需要定义如下文件:

  • ca.cnf: Certificate Authority 的配置文件
  • ca.key: Certificate Authority 的密钥,用于签名根证书
  • ca.cert: Certificate Authority 的根证书
  • localhost.cnf: localhost 的配置文件
  • localhost.key: localhost 的密钥,用于签名项目书
  • localhost.csr: localhost 证书请求文件,用于向 CA 申请 SSL 证书
  • localhost.ext: localhost 证书的扩展配置,用来描述证书涵盖的 DNS
  • localhost.crt: localhost 的 SSL 证书文件

在 shell 脚本中定义好变量名,之后使用:

FILENAME_CA_CNF=ca.cnf
FILENAME_CA_KEY=ca.key
FILENAME_CA_CERT=ca.pem
FILENAME_CERT_CNF=localhost.cnf
FILENAME_CERT_KEY=localhost.key
FILENAME_CERT_CSR=localhost.csr
FILENAME_CERT_EXT=localhost.ext
FILENAME_CERT_CERT=localhost.crt

创建一个 CA 配置文件,描述 CA 的所有权,其中字段描述如下:

  • C: Country 国家
  • ST: State 州/省
  • L: Locality 地区
  • O: Organization 企业/公司名
  • OU: Organization Unit 项目名
  • CN: Common Name 证书的唯一标识名
cat >> $FILENAME_CA_CNF <<EOF
[req]
prompt = no
distinguished_name = req_distinguished_name

[req_distinguished_name]
C=AU
ST=Victoria
L=Melbourne
O=mutoo.im
OU=ca
CN=ca.mutoo.im
EOF

然后使用 OpenSSL 生成一个 CA 用的钥匙,并创建根证书:

# generate ca key
openssl genrsa -out $FILENAME_CA_KEY 2048
# create ca root cert
openssl req -x509 \
  -config $FILENAME_CA_CNF \
  -new \
  -nodes \
  -key $FILENAME_CA_KEY \
  -sha256 \
  -days 365 \
  -out $FILENAME_CA_CERT

接下来创建一个项目用的证书配置文件,字段描述同上,稍微调整一下项目名即可:

cat >> $FILENAME_CERT_CNF <<EOF
[req]
prompt = no
distinguished_name = req_distinguished_name

[req_distinguished_name]
C=AU
ST=Victoria
L=Melbourne
O=mutoo.im
OU=axidraw-web
CN=axidraw-web.mutoo.im
EOF

然后我们需要生成一个「证书签名请求文件」用来向 CA 申请项目证书:

openssl req \
  -config $FILENAME_CERT_CNF \
  -new \
  -nodes \
  -key $FILENAME_CERT_KEY \
  -out $FILENAME_CERT_CSR

请求文件的主体只有项目标识名,我们还需要一个扩展文件来描述证书相关的 DNS 信息,其中 alt-names 段可以放上几个你需要绑定的域名:

# create ext config
cat >> $FILENAME_CERT_EXT <<EOF
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names
[alt_names] 
DNS.1 = localhost
DNS.2 = $(hostname)
DNS.3 = $(ipconfig getifaddr en0).nip.io
EOF

在这里我除了绑定 localhost,还绑定了 hostname 主机名(在 macOS 下形如 macbook-pro.local 可经由 mDNS 可以在 LAN 中直接访问而无须使用内网 IP 访问),以及一个泛 DNS 解析的域名,方便当 mDNS 被禁用时使用。如果需要,这里还可以使用通配符,例如:DNS.4 = *.mutoo.im

有了证书签名请求文件和扩展信息,我们就可以用 CA 的名义签发项目证书:

# signed cert
openssl x509 -req \
  -in $FILENAME_CERT_CSR \
  -CA $FILENAME_CA_CERT \
  -CAkey $FILENAME_CA_KEY \
  -CAcreateserial \
  -out $FILENAME_CERT_CERT \
  -days 30 \
  -sha256 \
  -extfile $FILENAME_CERT_EXT

通过以上脚本,我们生成了一个有效期 365 天的根证书和一个有效期 30 天的项目证书。最后只需要将 ca.cert 导入系统的证书管理器,并信任 SSL 项目,然后在项目的 Web Server 中使用 localhost.crtlocalhost.key 即可。

如果有多个项目,可以重复使用 CA 根证书来签发不同的项目证书。由于根证书已经被系统信认,在有效期内,所以的项目证书都可以通过系统检测,十分简单。

如果需要在局域网中的设备访问开发中的网站,可以将证书文件放在静态资源中供下载,然后添加到信任列表:

// provide CA cert for client to download
app.use('/get-ca', express.static('server/cert/ca.pem'));

最后要注意保管好 CA 和项目证书的密钥,不要泄漏到 git 和 web server 上。