前端點滴(Node.js)(四)網絡編程 ---- 側重(下)

網絡服務與安全

一、瞭解

   在網絡世界中,數據在服務器段和客戶端之間傳輸,由於是明文傳輸的的內容,一旦在網絡被人監控,數據就可能一覽無餘地展示在中間的竊聽者面前,所以我們需要將數據進行加密後在進行網絡傳輸,這樣即使數據被揭去和竊聽,竊聽者也無法知道數據的真實內容是什麼。但是對於我們的應用層協議而言,比如http,ftp等,我們仍希望能夠透明地處理數據,而無需操心網絡傳輸過程中的安全問題。於是就開始推出了SSL安全協議,作爲一種安全協議,它在傳輸層提供對網絡連接加密的功能。對於應用層而言,它就是透明的,數據在傳遞到應用層前就已經完成了加密與解密的過程。最初的SSL應用在Web上,被服務器端和瀏覽器端同時支持,隨後IETF將其標準化,稱爲TLS安全傳輸協議。

  node在網絡安全上提供了3個模塊,分別是crypto,tls,https。其中crypto主要用於加密解密,SHA1、MD5等加密算法都是其中的體現。真正用於網絡的是另外兩個模塊,tls模塊提供了與net模塊類似的功能,區別在於它建立在TSL/SSL加密的TCP連接上。對於https而言,它完全與http模塊接口一致,區別也僅僅在於它建立於安全的連接之上。

二、TSL/SSL

1. 密鑰

TSL/SSL是一個公鑰與私鑰的結構,它是一個非常對稱的結構,每一服務器端和客戶端都有自己的公鑰與私鑰。公鑰用於加密傳輸的數據,私鑰用於解密接受到的數據,公鑰與私鑰是配對的,通過公鑰加密的數據,同能通過私鑰才能解密,所以在建立安全傳輸之前,客戶端與服務器端之間需要交換公鑰(協商加密)。

流程:

客戶端發送數據---->服務器端公鑰加密---->服務器端私鑰解密---->服務端接收數據、處理響應

服務端處理客戶端傳來的數據,響應數據---->客戶端公鑰加密---->客戶端私鑰解密---->客戶端接收響應數據、處理渲染頁面

在node中採用的是openssl實現TLS/SSL:

1)在項目中添加server.key以及client.key私鑰文件。

2)在項目目錄中打開終端/cmder分別輸入以下命令生成私鑰:

  • openssl genrsa -out server.key 1024
  • openssl genrsa -out client.key 1024

3)生成公鑰同上做法輸入命令:

  • openssl rsa -in server.key -pubout -out server.pem
  • openssl rsa -in client.key -pubout -out client.pem

觀察server.key與client.key中的私鑰文件,再看經過私鑰分別配出的公鑰,發現server與client的公鑰私鑰都是不同的,當時在網絡中依然可能存在被竊聽的情況,典型的例子是中間人攻擊(充當雙面間諜)客戶端和服務器端在交換公鑰的過程中,中間人對客戶端扮演服務器端的角色,對服務器端扮演客戶端的角色,因此它是讓人感覺不到的,也是極爲恐怖的。爲了解決這種問題,數據傳輸的過程中還需對得到的公鑰進行認證,以確定得到公鑰的是出自目標服務器,而這種認證方式就是數字證書(CA,數字證書認證中心)。

區別於公鑰,數字證書中包含服務器名稱和主機名、服務器的公鑰、簽名頒發機構的名稱、來自簽名頒發機構的簽名。在連接建立前,會通過證書中的簽名確認收到公鑰是來自目標服務器的,從而產生信任關係避免中間人攻擊。

2. 數字證書

爲了保證我們的數據安全,現在我們引入了一個第三方:CA(數字證書認證中心),認證中心的作用就是爲站點頒發證書,且這個證書中具有CA通過自己的公鑰和私鑰實現的簽名。

不過通過CA機構頒發的證書通常是一個繁瑣的過程,還需要花費時間與金錢。面對這種情況很多人會選擇自簽名證書,也就是自己來扮演CA機構,給自己的服務器端頒發簽名證書。

2.1 自簽證

流程:

1)製作證書,同樣在項目目錄中打開終端/cmder,輸入命令:

  • openssl genrsa -out ca.key 1024
  • openssl req -new -key ca.key -out ca.csr

注意:此過程需要填寫相關的參數:

例子:

Country Name (2 letter code) [AU]:cn    
State or Province Name (full name) [Some-State]:china  
Locality Name (eg, city) []:guangdong
Organization Name (eg, company) [Internet Widgits Pty Ltd]:test
Organizational Unit Name (eg, section) []:test
Common Name (e.g. server FQDN or YOUR name) []:root   /* 此處關鍵,表示此ca證書爲根證書 */
Email Address []:[email protected]

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:123456
An optional company name []:test
  • openssl x509 -req -in ca.csr -signkey ca.key -out ca.crt

 

上述步驟過後,就完成了扮演CA角色需要的文件。

2)服務器端向CA機構申請簽名證書,在申請簽名證書之前依然是要創建自己的CSR文件。

注意在這過程中Common Name要配置服務器域名,否則在後續的認證過程中會出現錯誤。

同樣在項目目錄中打開終端/cmder,輸入命令:

  •  openssl req -new -key server.key -out server.csr

注意:

同樣這個過程也需要填寫信息:

例子:

Country Name (2 letter code) [AU]:cn
State or Province Name (full name) [Some-State]:china
Locality Name (eg, city) []:guangdong
Organization Name (eg, company) [Internet Widgits Pty Ltd]:test
Organizational Unit Name (eg, section) []:test
Common Name (e.g. server FQDN or YOUR name) []:www.jstest.com  /* 此處填寫一個域名,注意如果是localhost填localhost即可,筆者此處的域名爲wampserver配置出來的域名站點,目的爲了更加清晰操作 */
Email Address []:[email protected]

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:123456
An optional company name []:test

3)簽名

簽名過程需要CA的證書以及私鑰參與,最終頒發一個帶有CA簽名的證書

同樣在項目目錄中打開終端/cmder,輸入命令:

  • openssl x509 -req -CA ca.crt -CAkey ca.key -CAcreateserial -in server.csr -out server.crt

最終流程

圖示:

解釋:

服務端在發起安全連接前會去獲取服務端的證書,並通過CA的證書驗證服務器端證書的真僞。

CA機構將證書頒發給服務端後,證書在請求的過程中會被髮送給客戶端,客戶端需要通過CA的的證書驗證真僞,如果是知名的CA機構,它的證書一般裝在瀏覽器中,如果是自己扮演CA機構,頒發自簽名證書則不能享有這個福利,也就是說客戶端需要發送請求獲取CA證書才能進行驗證。

3. TSL 服務

(1)創建服務器端

將所有的證書備齊後,通過Node中的tls模塊來創建一個安全的TCP服務,來一個簡單的echo服務:

/* server.js */
var tls = require('tls');
var fs = require('fs');

var options = {
    key: fs.readFileSync('./server.key'),
    cert: fs.readFileSync('./server.crt'),
    request: true,
    ca: [fs.readFileSync('./ca.crt')]
}
var server = tls.createServer(options,function(stream){
    console.log('server connected',stream.authorized?'authorized':'unauthorized');
    stream.write('welcome!\n');
    stream.setEncoding('utf8');
    stream.pipe(stream);
})
server.listen(8000,function(){
    console.log('server is created')
})

啓動上述的服務器,通過另外的後臺窗口輸入命令,可觀察證書是否正常:

輸入:openssl s_client -connect 127.0.0.1:8000

(2)TSL 客戶端

完整體系,使用Node來模擬客戶端,如net模塊一樣,tls模塊也提供了connect()方法來構建客戶端。在構建客戶端前,需要爲客戶端生成屬於自己的私鑰與簽名:

  •  openssl req -new -key server.key -out server.csr

注意:

同樣這個過程也需要填寫信息:

例子:

Country Name (2 letter code) [AU]:cn
State or Province Name (full name) [Some-State]:china
Locality Name (eg, city) []:guangdong
Organization Name (eg, company) [Internet Widgits Pty Ltd]:test
Organizational Unit Name (eg, section) []:test
Common Name (e.g. server FQDN or YOUR name) []: *****   /* 此處填寫本機客戶端,即計算機名稱 */
Email Address []:[email protected]

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:123456
An optional company name []:test
  • openssl x509 -req -CA ca.crt -CAkey ca.key -CAcreateserial -in server.csr -out server.crt
/* client.js */
var tls = require('tls');
var fs = require('fs');
var options = {
    host:'www.jstest.com',
    key: fs.readFileSync('./client.key'),
    cert: fs.readFileSync('./client.crt'),
    ca: [fs.readFileSync('./ca.crt')]
};
var stream = tls.connect(8000, options, function () {
    console.log('client connected', stream.authorized ? 'authorized' : 'unauthorized');
    process.stdin.pipe(stream);
});
stream.setEncoding('utf8');
stream.on('data', function (data) {
    console.log(data);
});
stream.on('end', function () {
    server.close();
});

啓動服務器以及客戶端,觀察結果:

成功!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

三、https 服務

https服務就是工作在TLS/SSL上的http,創建一個https服務已是一個簡單不過的事情。

1. 準備證書

https服務需要用到的私鑰以及簽名證書,我麼可以直接用上面的私鑰以及證書進行實例。

2. 創建 https服務器端

區別於http,創建一個https服務只比創建一個http多一個選項配置options,其餘地方非常類似。

var https = require('https');
var fs = require('fs');
/* 配置私鑰以及證書 */
var options = {
    key: fs.readFileSync('./server.key'),
    cert: fs.readFileSync('./server.crt')
};
https.createServer(options, function (req, res) {
    res.writeHead(200);
    res.end("hello world\n");
}).listen(8000);

3. 創建 https 客戶端

var https = require('https');
var fs = require('fs');
var options = {
    host: 'www.jstest.com',  /* 一定要書寫正確,否則 Game Over */
    port: 8000,
    path: '/',
    method: 'GET',
    key: fs.readFileSync('./client.key'),
    cert: fs.readFileSync('./client.crt'),
    ca: [fs.readFileSync('./ca.crt')]
};
options.agent = new https.Agent(options);
var req = https.request(options, function (res) {
    res.setEncoding('utf-8');
    res.on('data', function (d) {
        console.log(d);
    });
});
req.end();
req.on('error', function (e) {
    console.log(e);
});

啓動服務器以及客戶端,觀察結果:

到瀏覽器搜索:https://www.jstest.com:8000,查看結果:

成功!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

至於如何配置Chrome信任自籤CA,在此不作論述.........

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章