Nodejs進階:核心模塊https 之 如何優雅的訪問12306

本文摘錄自《Nodejs學習筆記》,更多章節及更新,請訪問 github主頁地址。歡迎加羣交流,羣號 197339705node

模塊概覽

這個模塊的重要性,基本不用強調了。在網絡安全問題日益嚴峻的今天,網站採用HTTPS是個必然的趨勢。git

在nodejs中,提供了 https 這個模塊來完成 HTTPS 相關功能。從官方文檔來看,跟 http 模塊用法很是類似。github

本文主要包含兩部分:web

  1. 經過客戶端、服務端的例子,對https模塊進行入門講解。算法

  2. 如何訪問安全證書不受信任的網站。(以 12306 爲例子)chrome

篇幅所限,本文沒法對 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證書,那麼能夠跳過證書生成的環節。若是沒有,能夠參考以下步驟bash

生成證書

一、建立個目錄存放證書。

mkdir cert
cd cert

二、生成私鑰。

openssl genrsa -out chyingp-key.pem 2048

三、生成證書籤名請求(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"

四、生成證書。

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/reg... 時,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的配置

一、下載 12306 的CA證書

在12306的官網上,提供了CA證書的下載地址,將它保存到本地,命名爲 srca.cer。

二、將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

三、修改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 證書類型 證書擴展名

相關文章
相關標籤/搜索