node 网络(二)

构建websocket服务

websocket的优势:

  • 客户端与服务器只需要一个tcp连接
  • 服务器可以推送到客户端
  • 轻量化的协议头,提高传输效率

node使用websocket的优势:

  • WebSocket客户端基于事件的编程模式和node的自定义事件类似
  • websocket需要客户端与服务器之间的长连接,node事件驱动的方式擅长与量大的客户端保持高并发连接

WebSocket握手

客户端发起升级协议请求:

GET / chat HTTP / 1.1
Host: server.example.com
Upgrade: websocket //升级协议为websocket
Connection: Upgrade
Sec - WebSocket - Key: dGhlIHNhbXBsZSBub25jZQ == 
Sec - WebSocket - Protocol: chat, superchat //子协议
Sec - WebSocket - Version: 13 //版本号

Sec-WebSocket-Key用于安全校验,值是随机生成的Base64编码的字符串。服务端将其与字符串258EAFA5-E914-47DA-95CA-C5AB0DC85B11拼接,然后再用sha1计算再Base64编码

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

//服务端响应b报文
HTTP / 1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade 
Sec - WebSocket - Accept: s3pPLMBiTxaQ9kYGzzhZRbK + xOo =
Sec - WebSocket - Protocol: chat

客户端校验Sec-WebSocket-Accept,正确的话就开始数据传输

WebSocket数据传输

在握手后就开始websocket数据帧协议, 握手完成客户端onopen()被触发

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

服务端没有onopen()方法,想完成tcp套接字事件到websocket事件的封装,需要在收发数据时处理,Websocket的数据帧是在底层data事件上封装的

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

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

当一端调用send()发送时,另一端会触发onmessage,协议可能将数据封装为多帧发送。客户端需要对发送的数据帧做掩码处理,服务端收到无掩码帧会断开连接,而服务端发送时不需要

websocket数据帧定义

Smaller icon
Smaller icon

  • fin 如果这数据帧是最后一帧时为1(如果数据就一帧,它也是1),其余为0
  • rsv1、rsv2、rsv3:1位长 用于标识拓展,当有拓展时为1
  • opcode: 4位(0~15) 0:附加数据帧 ,1:文本数据帧 ,2:二进制数据帧,8:发送一个连接关闭帧,9:ping数据帧 ,10:pong数据帧 ping,pong用于心跳检测,一端发ping、一端发pong
  • masked 是否进行掩码处理 客户端发送时是1 服务端是0
  • payload 标识数据长度
  • masking key 当masked为1时存在 长度32位 用于解密
  • payload data 目标数据 位数为8的倍数

网络服务和安全

  • ssl(Secure Sockets Layer,安全套接层),应用在传输层
  • TLS(Transport Layer Security,安全传输层协议),由IETF标准化

node提供crypto,tls,https。crypto用于加解密,tls与net功能类似,区别是它建立在TLS/SSL加密的tcp.https和http接口也一致,也是区别在建立于安全的连接

TLS/SSL

  • 非对称加密,公钥用于加密传输数据,私钥解密
Smaller icon
Smaller icon

node的tls/ssl是用openssl实现的,公、私钥生成参照:

// 生成服务器端私 
$ openssl genrsa -out server.key 1024 // 生成客户端私 
$ openssl genrsa -out client.key 1024

//利用上面的1024位长的RSA私钥生成公钥
$ openssl rsa -in server.key -pubout -out server.pem
$ openssl rsa -in client.key -pubout -out client.pem

数字证书
  • 由CA颁发,并提供验证
  • 防止中间人攻击

中间人攻击:在服务端和客户端交换密钥时,伪装成其中一方发送公钥,如对客户端就伪装成服务端。所以需要对公钥认证,确认来自目标服务器

服务端通过私钥生成CSR(Certificate Signing Request,证书签名请求),ca通过它颁发属于该服务器的签名证书

自签名证书流程:

\\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
\\服务器生成csr,向ca申请签名,获取证书
$ 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

客户端发起安全连接会获取服务端证书,然后用ca的证书验证服务器证书,包括真伪、服务器名称、ip等。对于知名ca,它的证书一般预装在浏览器,自签的ca需要客户端安装才能验证

创建tcl服务

  • 通过node的tls创建安全的tcp服务
//服务端
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');
});

//测试: $ 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服务

  • 使用node的https,比http多了一个配置
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);

//验证 $ curl https://localhost:8000/ -k, 忽略证书验证 -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代理另设
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);
});

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容