自签发SSL证书-解决本地开发跨域调试问题

1,128 阅读3分钟

背景

当我们启动一个egg应用,或者用webpack启动react应用后,访问的地址一般都是http://127.0.0.1:${port}。如下图所示,出现的是不安全的请求。

image.png

此时在页面中用 https 请求访问,就会出现跨域请求错误。我们应该将服务用 https 启动,如下图所示。

image.png

那么此时的证书该如何生成才是对的呢?

步骤

依赖: openssl

第一步:终端执行命令

//生成rsa私钥,des3算法,1024位强度,ssl.key是秘钥文件名。 
openssl genrsa -des3 -out ssl.key 1024

第二步:输入密码。这里会输入两次,填写一样即可,随意填写一个,下一步就会删除这个密码。

image.png 通过上面这一步,就会在当前文件夹下生成一个 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 - 它的安全证书没有指定主题备用名称。这可能是因为某项配置有误或某个攻击者拦截了您的连接。 image.png

解决方案

新建文件 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'),
    },
  };