背景
当我们启动一个egg应用,或者用webpack启动react应用后,访问的地址一般都是http://127.0.0.1:${port}
。如下图所示,出现的是不安全的请求。
此时在页面中用 https 请求访问,就会出现跨域请求错误。我们应该将服务用 https 启动,如下图所示。
那么此时的证书该如何生成才是对的呢?
步骤
依赖: openssl
第一步:终端执行命令
//生成rsa私钥,des3算法,1024位强度,ssl.key是秘钥文件名。
openssl genrsa -des3 -out ssl.key 1024
第二步:输入密码。这里会输入两次,填写一样即可,随意填写一个,下一步就会删除这个密码。
通过上面这一步,就会在当前文件夹下生成一个 ssl.key
文件。
第三步:删除密码
//终端执行删除密码命令
//这里目录和生成私钥的目录一致
openssl rsa -in ssl.key -out ssl.key
第四步:生成 CSR(证书签名请求)。我们根据根据刚刚生成的 key 文件来生成证书请求文件,终端执行如下命令:
openssl req -new -key ssl.key -out ssl.csr
执行以上命令后,需要依次输入国家、地区、城市、组织、组织单位、Common Name、Email 和密码。其中 Common Name 应该与域名保持一致。密码我们已经删掉了,直接回车即可。
注意:Common Name 就是证书对应的域名地址。 例如:我启动的本地地址是 dev.1688.com:7001
,那我填写的域名是 dev.1688.com
。
第五步:生成自签名证书。根据以上 2 个文件生成 crt 证书文件,终端执行下面命令
//这里3650是证书有效期(单位:天)。这个大家随意。最后使用到的文件是key和crt文件。
openssl x509 -req -days 3650 -in ssl.csr -signkey ssl.key -out ssl.crt
到这里我们的证书(ssl.key
和 ssl.crt
) 就已经创建成功了可以直接用到 https 的 server 中了。
第六步:测试下证书是否生效
curl https://dev.1688.com:7001
如果出现次错误,说明证书生成不正确。
curl: (60) SSL certificate problem: self signed certificate
More details here: https://curl.haxx.se/docs/sslcerts.html
curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.
ERR:CERT_COMMON_NAME_INVALID
通过浏览器访问,https://dev.1688.com:7001
出现“错误证书公用名无效”。 点击 ERR:CERT_COMMON_NAME_INVALID
出现提示:此服务器无法证实它就是 dev.1688.com - 它的安全证书没有指定主题备用名称。这可能是因为某项配置有误或某个攻击者拦截了您的连接。
解决方案
新建文件 ext.ini,或者 ext.ext 都可以,写入以下内容
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1 = dev.1688.com
DNS.2 = *.maqian.xin
[alt_names]
下面填写上所有的域名即可,然后在以上第五步签发证书的时候带上参数:
openssl x509 ... -extfile ext.ini
具体代码如下:
openssl x509 -req -days 3650 -in ssl.csr -signkey ssl.key -out ssl.crt -extfile ext.ini
测试
node 应用
'use strict';
const https = require('https');
const fs = require('fs');
const options = {
key: fs.readFileSync('./key.pem'),
cert: fs.readFileSync('./cert.pem'),
};
https.createServer(options, (req, res) => {
console.log(req.url);
res.end('hello world\n');
}).listen(443, () => {
console.log('server listen at 443');
});
egg 应用
// config.local.js中配置
config.cluster = {
https: {
key: path.join(appInfo.baseDir, 'httpskey/ssl.key'),
cert: path.join(appInfo.baseDir, 'httpskey/ssl.crt'),
},
};