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


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

模塊概覽

這個模塊的重要性,基本不用強調了。在網絡安全問題日益嚴峻的今天,網站采用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);
});

相關鏈接

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 證書類型 證書擴展名


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM