NodeJS 网络服务 https

发布于 2025-01-21 22:51:05 字数 6438 浏览 1 评论 0

模块概览

这个模块的重要性,基本不用强调了。在网络安全问题日益严峻的今天,网站采用 HTTPS 是个必然的趋势。

在 nodejs 中,提供了 https 这个模块来完成 HTTPS 相关功能。从官方文档来看,跟 http 模块用法非常相似。

本文主要包含两部分:

  1. 通过客户端、服务端的例子,对 https 模块进行入门讲解。
  2. 如何访问安全证书不受信任的网站。(以 12306 为例子)

篇幅所限,本文无法对 HTTPS 协议 及 相关技术体系 做过多讲解,有问题欢迎留言交流。

客户端例子

跟 http 模块的用法非常像,只不过请求的地址是 https 协议的而已,代码如下:

var https = require('https');

https.get('https://www.baidu.com', function(res){
    console.log('status code: ' + res.statusCode);
    console.log('headers: ' + JSON.stringify(res.headers));

    res.on('data', function(data){
        process.stdout.write(data);
    });
}).on('error', function(err){
    console.error(err);
});

服务端例子

对外提供 HTTPS 服务,需要有 HTTPS 证书。如果你已经有了 HTTPS 证书,那么可以跳过证书生成的环节。如果没有,可以参考如下步骤

生成证书

1、创建个目录存放证书。

mkdir cert
cd cert

2、生成私钥。

openssl genrsa -out chyingp-key.pem 2048

3、生成证书签名请求(csr 是 Certificate Signing Request 的意思)。

openssl req -new \
  -sha256
  -key chyingp-key.key.pem \
  -out chyingp-csr.pem \
  -subj "/C=CN/ST=Guandong/L=Shenzhen/O=YH Inc/CN=www.chyingp.com"

4、生成证书。

openssl x509 \
  -req -in chyingp-csr.pem \
  -signkey chyingp-key.pem \
  -out chyingp-cert.pem

HTTPS 服务端

代码如下:

var https = require('https');
var fs = require('fs');

var options = {
    key: fs.readFileSync('./cert/chyingp-key.pem'), // 私钥
    cert: fs.readFileSync('./cert/chyingp-cert.pem') // 证书
};

var server = https.createServer(options, function(req, res){
    res.end('这是来自 HTTPS 服务器的返回');
});

server.listen(3000);

由于我并没有 www.chyingp.com 这个域名,于是先配置本地 host

127.0.0.1 www.chyingp.com

启动服务,并在浏览器里访问 http://www.chyingp.com:3000 。注意,浏览器会提示你证书不可靠,点击 信任并继续访问 就行了。

进阶例子:访问安全证书不受信任的网站

这里以我们最喜爱的 12306 最为例子。当我们通过浏览器,访问 12306 的购票页面 https://kyfw.12306.cn/otn/regist/init 时,chrome 会阻止我们访问,这是因为,12306 的证书是自己颁发的,chrome 无法确认他的安全性。

对这种情况,可以有如下处理方式:

  1. 停止访问:着急抢票回家过年的老乡表示无法接受。
  2. 无视安全警告,继续访问:大部分情况下,浏览器是会放行的,不过安全提示还在。
  3. 导入 12306 的 CA 根证书:浏览器乖乖就范,认为访问是安全的。(实际上还是有安全提示,因为 12306 用的签名算法安全级别不够)

例子:触发安全限制

同样的,通过 node https client 发起请求,也会遇到同样问题。我们做下实验,代码如下:

var https = require('https');

https.get('https://kyfw.12306.cn/otn/regist/init', function(res){   
    res.on('data', function(data){
        process.stdout.write(data);
    });
}).on('error', function(err){
    console.error(err);
});

运行上面代码,得到下面的错误提示,意思是 安全证书不可靠,拒绝继续访问。

{ Error: self signed certificate in certificate chain
    at Error (native)
    at TLSSocket.<anonymous> (_tls_wrap.js:1055:38)
    at emitNone (events.js:86:13)
    at TLSSocket.emit (events.js:185:7)
    at TLSSocket._finishInit (_tls_wrap.js:580:8)
    at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:412:38) code: 'SELF_SIGNED_CERT_IN_CHAIN' }

ps:个人认为这里的错误提示有点误导人,12306 网站的证书并不是自签名的,只是对证书签名的 CA 是 12306 自家的,不在可信列表里而已。自签名证书,跟自己 CA 签名的证书还是不一样的。

类似在浏览器里访问,我们可以采取如下处理:

  1. 不建议:忽略安全警告,继续访问;
  2. 建议:将 12306 的 CA 加入受信列表;

方法 1:忽略安全警告,继续访问

非常简单,将 rejectUnauthorized 设置为 false 就行,再次运行代码,就可以愉快的返回页面了。

// 例子:忽略安全警告
var https = require('https');

var options = { 
    hostname: 'kyfw.12306.cn',
    path: '/otn/leftTicket/init',
    rejectUnauthorized: false  // 忽略安全警告
};

var req = https.get(options, function(res){ 
    res.pipe(process.stdout);   
});

req.on('error', function(err){
    console.error(err.code);
});

方法 2:将 12306 的 CA 加入受信列表

这里包含 3 个步骤:

  1. 下载 12306 的 CA 证书
  2. 将 der 格式的 CA 证书,转成 pem 格式
  3. 修改 node https 的配置

1、下载 12306 的 CA 证书

在 12306 的官网上,提供了 CA 证书的 下载地址 ,将它保存到本地,命名为 srca.cer。

2、将 der 格式的 CA 证书,转成 pem 格式

https 初始化 client 时,提供了 ca 这个配置项,可以将 12306 的 CA 证书添加进去。当你访问 12306 的网站时,client 就会用 ca 配置项里的 ca 证书,对当前的证书进行校验,于是就校验通过了。

需要注意的是,ca 配置项只支持 pem 格式,而从 12306 官网下载的是 der 格式的。需要转换下格式才能用。关于 pem、der 的区别,可参考 这里

openssl x509 -in srca.cer -inform der -outform pem -out srca.cer.pem

3、修改 node https 的配置

修改后的代码如下,现在可以愉快的访问 12306 了。

// 例子:将 12306 的 CA 证书,加入我们的信任列表里
var https = require('https');
var fs = require('fs');
var ca = fs.readFileSync('./srca.cer.pem');

var options = { 
  hostname: 'kyfw.12306.cn',
  path: '/otn/leftTicket/init',
  ca: [ ca ]
};

var req = https.get(options, function(res){ 
  res.pipe(process.stdout); 
});

req.on('error', function(err){
  console.error(err.code);
});

相关链接

Why is my node.js SSL connection failing to connect?

DER vs. CRT vs. CER vs. PEM Certificates and How To Convert Them

Painless Self Signed Certificates in node.js

利用 OpenSSL 创建自签名的 SSL 证书备忘(自建 ca)

OpenSSL 与 SSL 数字证书概念贴

自签名证书和私有 CA 签名的证书的区别 创建自签名证书 创建私有 CA 证书类型 证书扩展名

那些证书相关的玩意儿(SSL,X.509,PEM,DER,CRT,CER,KEY,CSR,P12 等)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

断舍离

暂无简介

文章
评论
26 人气
更多

推荐作者

白云不回头

文章 0 评论 0

糖粟与秋泊

文章 0 评论 0

洋豆豆

文章 0 评论 0

泛滥成性

文章 0 评论 0

mb_2YvjCLvt

文章 0 评论 0

夜光

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文