node 網(wǎng)絡(luò)(二)

構(gòu)建websocket服務(wù)

websocket的優(yōu)勢(shì):

  • 客戶端與服務(wù)器只需要一個(gè)tcp連接
  • 服務(wù)器可以推送到客戶端
  • 輕量化的協(xié)議頭养涮,提高傳輸效率

node使用websocket的優(yōu)勢(shì):

  • WebSocket客戶端基于事件的編程模式和node的自定義事件類似
  • websocket需要客戶端與服務(wù)器之間的長(zhǎng)連接眯娱,node事件驅(qū)動(dòng)的方式擅長(zhǎng)與量大的客戶端保持高并發(fā)連接

WebSocket握手

客戶端發(fā)起升級(jí)協(xié)議請(qǐng)求:

GET / chat HTTP / 1.1
Host: server.example.com
Upgrade: websocket //升級(jí)協(xié)議為websocket
Connection: Upgrade
Sec - WebSocket - Key: dGhlIHNhbXBsZSBub25jZQ == 
Sec - WebSocket - Protocol: chat, superchat //子協(xié)議
Sec - WebSocket - Version: 13 //版本號(hào)

Sec-WebSocket-Key用于安全校驗(yàn)蕾殴,值是隨機(jī)生成的Base64編碼的字符串宇攻。服務(wù)端將其與字符串258EAFA5-E914-47DA-95CA-C5AB0DC85B11拼接八毯,然后再用sha1計(jì)算再Base64編碼

var crypto = require('crypto');
var val = crypto.createHash('sha1').update(key).digest('base64');

//服務(wù)端響應(yīng)b報(bào)文
HTTP / 1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade 
Sec - WebSocket - Accept: s3pPLMBiTxaQ9kYGzzhZRbK + xOo =
Sec - WebSocket - Protocol: chat

客戶端校驗(yàn)Sec-WebSocket-Accept翠霍,正確的話就開(kāi)始數(shù)據(jù)傳輸

WebSocket數(shù)據(jù)傳輸

在握手后就開(kāi)始websocket數(shù)據(jù)幀協(xié)議本谜, 握手完成客戶端onopen()被觸發(fā)

socket.onopen = function() { 
  // TODO: opened()
};

服務(wù)端沒(méi)有onopen()方法献酗,想完成tcp套接字事件到websocket事件的封裝寝受,需要在收發(fā)數(shù)據(jù)時(shí)處理,Websocket的數(shù)據(jù)幀是在底層data事件上封裝的

//接收
WebSocket.prototype.setSocket = function(socket) {
   this.socket = socket;
   this.socket.on('data', this.receiver);
};

//發(fā)送
WebSocket.prototype.send = function(data) {
   this._send(data);
};

當(dāng)一端調(diào)用send()發(fā)送時(shí)罕偎,另一端會(huì)觸發(fā)onmessage,協(xié)議可能將數(shù)據(jù)封裝為多幀發(fā)送很澄。客戶端需要對(duì)發(fā)送的數(shù)據(jù)幀做掩碼處理颜及,服務(wù)端收到無(wú)掩碼幀會(huì)斷開(kāi)連接甩苛,而服務(wù)端發(fā)送時(shí)不需要

websocket數(shù)據(jù)幀定義

Smaller icon
Smaller icon

  • fin 如果這數(shù)據(jù)幀是最后一幀時(shí)為1(如果數(shù)據(jù)就一幀,它也是1)俏站,其余為0
  • rsv1讯蒲、rsv2、rsv3:1位長(zhǎng) 用于標(biāo)識(shí)拓展肄扎,當(dāng)有拓展時(shí)為1
  • opcode: 4位(0~15) 0:附加數(shù)據(jù)幀 ,1:文本數(shù)據(jù)幀 ,2:二進(jìn)制數(shù)據(jù)幀,8:發(fā)送一個(gè)連接關(guān)閉幀,9:ping數(shù)據(jù)幀 ,10:pong數(shù)據(jù)幀 ping,pong用于心跳檢測(cè)墨林,一端發(fā)ping、一端發(fā)pong
  • masked 是否進(jìn)行掩碼處理 客戶端發(fā)送時(shí)是1 服務(wù)端是0
  • payload 標(biāo)識(shí)數(shù)據(jù)長(zhǎng)度
  • masking key 當(dāng)masked為1時(shí)存在 長(zhǎng)度32位 用于解密
  • payload data 目標(biāo)數(shù)據(jù) 位數(shù)為8的倍數(shù)

網(wǎng)絡(luò)服務(wù)和安全

  • ssl(Secure Sockets Layer,安全套接層)犯祠,應(yīng)用在傳輸層
  • TLS(Transport Layer Security,安全傳輸層協(xié)議)萌丈,由IETF標(biāo)準(zhǔn)化

node提供crypto,tls,https雷则。crypto用于加解密辆雾,tls與net功能類似,區(qū)別是它建立在TLS/SSL加密的tcp.https和http接口也一致月劈,也是區(qū)別在建立于安全的連接

TLS/SSL

  • 非對(duì)稱加密度迂,公鑰用于加密傳輸數(shù)據(jù)藤乙,私鑰解密
Smaller icon
Smaller icon

node的tls/ssl是用openssl實(shí)現(xiàn)的,公惭墓、私鑰生成參照:

// 生成服務(wù)器端私 
$ openssl genrsa -out server.key 1024 // 生成客戶端私 
$ openssl genrsa -out client.key 1024

//利用上面的1024位長(zhǎng)的RSA私鑰生成公鑰
$ openssl rsa -in server.key -pubout -out server.pem
$ openssl rsa -in client.key -pubout -out client.pem

數(shù)字證書
  • 由CA頒發(fā)坛梁,并提供驗(yàn)證
  • 防止中間人攻擊

中間人攻擊:在服務(wù)端和客戶端交換密鑰時(shí),偽裝成其中一方發(fā)送公鑰腊凶,如對(duì)客戶端就偽裝成服務(wù)端划咐。所以需要對(duì)公鑰認(rèn)證,確認(rèn)來(lái)自目標(biāo)服務(wù)器

服務(wù)端通過(guò)私鑰生成CSR(Certificate Signing Request钧萍,證書簽名請(qǐng)求)褐缠,ca通過(guò)它頒發(fā)屬于該服務(wù)器的簽名證書

自簽名證書流程:

\\ca生成私鑰,csr文件风瘦,和自簽名的證書
$ openssl genrsa -out ca.key 1024
$ openssl req -new -key ca.key -out ca.csr
$ openssl x509 -req -in ca.csr -signkey ca.key -out ca.crt
\\服務(wù)器生成csr,向ca申請(qǐng)簽名队魏,獲取證書
$ openssl req -new -key server.key -out server.csr
$ openssl x509 -req -CA ca.crt -CAkey ca.key -CAcreateserial -in server.csr -out server.crt

客戶端發(fā)起安全連接會(huì)獲取服務(wù)端證書,然后用ca的證書驗(yàn)證服務(wù)器證書万搔,包括真?zhèn)魏啊⒎?wù)器名稱、ip等瞬雹。對(duì)于知名ca,它的證書一般預(yù)裝在瀏覽器昧谊,自簽的ca需要客戶端安裝才能驗(yàn)證

創(chuàng)建tcl服務(wù)

  • 通過(guò)node的tls創(chuàng)建安全的tcp服務(wù)
//服務(wù)端
var tls = require('tls');
var fs = require('fs');
var options = {
    key: fs.readFileSync('./keys/server.key'),
    cert: fs.readFileSync('./keys/server.crt'),
    requestCert: true,
    ca: [fs.readFileSync('./keys/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 bound');
});

//測(cè)試: $ openssl s_client -connect 127.0.0.1:8000
//客戶端
$ openssl genrsa - out client.key 1024
$ openssl req - new - key client.key - out client.csr
$ openssl x509 - req - CA ca.crt - CAkey ca.key - CAcreateserial - in client.csr - out client.crt
var fs = require('fs');
var tls = require('tls');
var options = {
    key: fs.readFileSync('./keys/client.key'),
    cert: fs.readFileSync('./keys/client.crt'),
    ca: [fs.readFileSync('./keys/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();
});

//和tcp相比只是多了證書配置

https服務(wù)

  • 使用node的https,比http多了一個(gè)配置
var https = require('https');
var fs = require('fs');
var options = {
    key: fs.readFileSync('./keys/server.key'),
    cert: fs.readFileSync('./keys/server.crt')
};
https.createServer(options, function(req, res) {
    res.writeHead(200);
    res.end("hello world\n");
}).listen(8000);

//驗(yàn)證 $ curl https://localhost:8000/ -k, 忽略證書驗(yàn)證 -carcert ca證書地址
//客戶端

var https = require('https');
var fs = require('fs');
var options = {
    hostname: 'localhost',
    port: 8000,
    path: '/',
    method: 'GET',
    key: fs.readFileSync('./keys/client.key'),
    cert: fs.readFileSync('./keys/client.crt'),
    ca: [fs.readFileSync('./keys/ca.crt')]
};
options.agent = new https.Agent(options);//https代理另設(shè)
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);
});

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末酗捌,一起剝皮案震驚了整個(gè)濱河市呢诬,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌意敛,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,084評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件膛虫,死亡現(xiàn)場(chǎng)離奇詭異草姻,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)稍刀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門撩独,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人账月,你說(shuō)我怎么就攤上這事综膀。” “怎么了局齿?”我有些...
    開(kāi)封第一講書人閱讀 163,450評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵剧劝,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我抓歼,道長(zhǎng)讥此,這世上最難降的妖魔是什么拢锹? 我笑而不...
    開(kāi)封第一講書人閱讀 58,322評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮萄喳,結(jié)果婚禮上卒稳,老公的妹妹穿的比我還像新娘。我一直安慰自己他巨,他們只是感情好充坑,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,370評(píng)論 6 390
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著染突,像睡著了一般捻爷。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上觉痛,一...
    開(kāi)封第一講書人閱讀 51,274評(píng)論 1 300
  • 那天役衡,我揣著相機(jī)與錄音,去河邊找鬼薪棒。 笑死手蝎,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的俐芯。 我是一名探鬼主播棵介,決...
    沈念sama閱讀 40,126評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼吧史!你這毒婦竟也來(lái)了邮辽?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 38,980評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤贸营,失蹤者是張志新(化名)和其女友劉穎吨述,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體钞脂,經(jīng)...
    沈念sama閱讀 45,414評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡揣云,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,599評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了冰啃。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片邓夕。...
    茶點(diǎn)故事閱讀 39,773評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖阎毅,靈堂內(nèi)的尸體忽然破棺而出焚刚,到底是詐尸還是另有隱情,我是刑警寧澤扇调,帶...
    沈念sama閱讀 35,470評(píng)論 5 344
  • 正文 年R本政府宣布矿咕,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏痴腌。R本人自食惡果不足惜雌团,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,080評(píng)論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望士聪。 院中可真熱鬧锦援,春花似錦、人聲如沸剥悟。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,713評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)区岗。三九已至略板,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間慈缔,已是汗流浹背叮称。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,852評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留藐鹤,地道東北人瓤檐。 一個(gè)月前我還...
    沈念sama閱讀 47,865評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像娱节,于是被迫代替她去往敵國(guó)和親挠蛉。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,689評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • https://nodejs.org/api/documentation.html 工具模塊 Assert 測(cè)試 ...
    KeKeMars閱讀 6,330評(píng)論 0 6
  • CA和證書安全協(xié)議(SSL/TLS)OpenSSH 一肄满、CA和證書 (一) PKI(Public Key Infr...
    哈嘍別樣閱讀 1,391評(píng)論 0 0
  • 關(guān)于https背景知識(shí)密碼學(xué)的一些基本知識(shí) 大致上分為兩類谴古,基于key的加密算法與不基于key的加密算法。現(xiàn)在的算...
    黑手黨老k閱讀 4,004評(píng)論 0 2
  • 這兩天改用鉛筆畫稿,竟然有點(diǎn)不習(xí)慣怒炸。 不知道是心理作用還是筆的暗示带饱,用了鉛筆總是要修改一下方好。 上圖吧 用鉛筆畫...
    小衛(wèi)2013閱讀 308評(píng)論 2 1
  • 那人說(shuō):這是我骨中的骨横媚,肉中的肉纠炮,可以稱她為女人月趟,因?yàn)樗菑哪腥松砩先〕鰜?lái)的灯蝴。 因此,人要離開(kāi)父母孝宗,與妻子連合穷躁,二...
    月下joyce閱讀 273評(píng)論 0 0