Node.js进阶之核心模块https入门


Posted in Javascript onMay 23, 2018

模块概览

这个模块的重要性,基本不用强调了。在网络安全问题日益严峻的今天,网站采用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: ' + 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 fs = require('fs');

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);
});

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jQuery 处理网页内容的实现代码
Feb 15 Javascript
js 设置选中行的样式的实现代码
May 24 Javascript
基于jquery的jqDnR拖拽溢出的修改
Feb 12 Javascript
jQuery 获取/设置/删除DOM元素的属性以a元素为例
May 23 Javascript
JavaScript基础语法、dom操作树及document对象
Dec 02 Javascript
node.js中的fs.lstatSync方法使用说明
Dec 16 Javascript
多个jQuery版本共存的处理方案
Mar 17 Javascript
JS基于面向对象实现的放烟花效果
May 07 Javascript
从零学习node.js之mysql数据库的操作(五)
Feb 24 Javascript
基于jquery日历价格、库存等设置插件
Jul 05 jQuery
r.js来合并压缩css文件的示例
Apr 26 Javascript
vant(ZanUi)结合async-validator实现表单验证的方法
Dec 06 Javascript
使用 vue-i18n 切换中英文效果
May 23 #Javascript
centos 上快速搭建ghost博客方法分享
May 23 #Javascript
20个最常见的jQuery面试问题及答案
May 23 #jQuery
AngularJS与BootStrap模仿百度分页的示例代码
May 23 #Javascript
jQuery发请求传输中文参数乱码问题的解决方案
May 22 #jQuery
vue的传参方式汇总和router使用技巧
May 22 #Javascript
Chart.js 轻量级HTML5图表绘制工具库(知识整理)
May 22 #Javascript
You might like
web站点获取用户IP的安全方法 HTTP_X_FORWARDED_FOR检验
2013/06/01 PHP
PHP使用适合阅读的格式显示文件大小的方法
2015/03/05 PHP
php使用Jpgraph绘制3D饼状图的方法
2015/06/10 PHP
PHP表单提交后引号前自动加反斜杠的原因及三种办法关闭php魔术引号
2015/09/30 PHP
PHP实现将MySQL重复ID二维数组重组为三维数组的方法
2016/08/01 PHP
PHP封装返回Ajax字符串和JSON数组的方法
2017/02/17 PHP
PDO::quote讲解
2019/01/29 PHP
JS获取屏幕,浏览器窗口大小,网页高度宽度(实现代码)
2013/12/17 Javascript
前端必备神器 Snap.svg 弹动效果
2014/11/10 Javascript
JavaScript简单遍历DOM对象所有属性的实现方法
2015/10/21 Javascript
Node.js操作mysql数据库增删改查
2016/03/30 Javascript
有关jQuery中parent()和siblings()的小问题
2016/06/01 Javascript
javascript 广告移动特效的实现代码
2016/06/25 Javascript
Bootstrap jquery.twbsPagination.js动态页码分页实例代码
2017/02/20 Javascript
Bootstrap表格制作代码
2017/03/17 Javascript
jquery 实现拖动文件上传加载进度条功能
2018/03/18 jQuery
vue单元格多列合并的实现
2020/11/26 Vue.js
[01:17]辉夜杯战队访谈宣传片—EHOME
2015/12/25 DOTA
[01:33:14]LGD vs VP Supermajor 败者组决赛 BO3 第二场 6.10
2018/07/04 DOTA
[48:00]EG vs LGD 2018国际邀请赛淘汰赛BO3 第二场 8.26
2018/08/29 DOTA
Python实现抓取城市的PM2.5浓度和排名
2015/03/19 Python
Python实现程序的单一实例用法分析
2015/06/03 Python
Python 使用requests模块发送GET和POST请求的实现代码
2016/09/21 Python
解决python matplotlib imshow无法显示的问题
2018/05/24 Python
Python设计模式之职责链模式原理与用法实例分析
2019/01/11 Python
python 监听salt job状态,并任务数据推送到redis中的方法
2019/01/14 Python
Python 线程池用法简单示例
2019/10/02 Python
实现Python与STM32通信方式
2019/12/18 Python
python时间与Unix时间戳相互转换方法详解
2020/02/13 Python
html5的websockets全双工通信详解学习示例
2014/02/26 HTML / CSS
Priority Pass机场贵宾室会籍计划:全球超过1200间机场贵宾室
2018/08/26 全球购物
香港通票:Hong Kong Pass
2019/02/26 全球购物
电钳工人个人求职信
2014/05/10 职场文书
入党积极分子考察意见
2015/06/02 职场文书
英文投诉信格式
2015/07/03 职场文书
高一数学教学反思
2016/02/18 职场文书