前端点滴(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.js)(四)网络编程 ---- 侧重(下)

在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

注意:此过程需要填写相关的参数:

例子:


1
2
3
4
5
6
7
8
9
10
11
12
13
1Country Name (2 letter code) [AU]:cn    
2State or Province Name (full name) [Some-State]:china  
3Locality Name (eg, city) []:guangdong
4Organization Name (eg, company) [Internet Widgits Pty Ltd]:test
5Organizational Unit Name (eg, section) []:test
6Common Name (e.g. server FQDN or YOUR name) []:root   /* 此处关键,表示此ca证书为根证书 */
7Email Address []:1131260522@qq.com
8
9Please enter the following 'extra' attributes
10to be sent with your certificate request
11A challenge password []:123456
12An optional company name []:test
13
  • openssl x509 -req -in ca.csr -signkey ca.key -out ca.crt

前端点滴(Node.js)(四)网络编程 ---- 侧重(下)

 

上述步骤过后,就完成了扮演CA角色需要的文件。

2)服务器端向CA机构申请签名证书,在申请签名证书之前依然是要创建自己的CSR文件。

注意在这过程中Common Name要配置服务器域名,否则在后续的认证过程中会出现错误。

同样在项目目录中打开终端/cmder,输入命令:

  •  

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

注意:

同样这个过程也需要填写信息:

例子:


1
2
3
4
5
6
7
8
9
10
11
12
13
1Country Name (2 letter code) [AU]:cn
2State or Province Name (full name) [Some-State]:china
3Locality Name (eg, city) []:guangdong
4Organization Name (eg, company) [Internet Widgits Pty Ltd]:test
5Organizational Unit Name (eg, section) []:test
6Common Name (e.g. server FQDN or YOUR name) []:www.jstest.com  /* 此处填写一个域名,注意如果是localhost填localhost即可,笔者此处的域名为wampserver配置出来的域名站点,目的为了更加清晰操作 */
7Email Address []:1131260522@qq.com
8
9Please enter the following 'extra' attributes
10to be sent with your certificate request
11A challenge password []:123456
12An optional company name []:test
13

3)签名

签名过程需要CA的证书以及私钥参与,最终颁发一个带有CA签名的证书

同样在项目目录中打开终端/cmder,输入命令:

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

最终流程

图示:

前端点滴(Node.js)(四)网络编程 ---- 侧重(下)

解释:

服务端在发起安全连接前会去获取服务端的证书,并通过CA的证书验证服务器端证书的真伪。

CA机构将证书颁发给服务端后,证书在请求的过程中会被发送给客户端,客户端需要通过CA的的证书验证真伪,如果是知名的CA机构,它的证书一般装在浏览器中,如果是自己扮演CA机构,颁发自签名证书则不能享有这个福利,也就是说客户端需要发送请求获取CA证书才能进行验证。

3. TSL 服务

(1)创建服务器端

将所有的证书备齐后,通过Node中的tls模块来创建一个安全的TCP服务,来一个简单的echo服务:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1/* server.js */
2var tls = require('tls');
3var fs = require('fs');
4
5var options = {
6    key: fs.readFileSync('./server.key'),
7    cert: fs.readFileSync('./server.crt'),
8    request: true,
9    ca: [fs.readFileSync('./ca.crt')]
10}
11var server = tls.createServer(options,function(stream){
12    console.log('server connected',stream.authorized?'authorized':'unauthorized');
13    stream.write('welcome!\n');
14    stream.setEncoding('utf8');
15    stream.pipe(stream);
16})
17server.listen(8000,function(){
18    console.log('server is created')
19})
20

启动上述的服务器,通过另外的后台窗口输入命令,可观察证书是否正常:

输入:openssl s_client -connect 127.0.0.1:8000

(2)TSL 客户端

完整体系,使用Node来模拟客户端,如net模块一样,tls模块也提供了connect()方法来构建客户端。在构建客户端前,需要为客户端生成属于自己的私钥与签名:

  •  

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

注意:

同样这个过程也需要填写信息:

例子:


1
2
3
4
5
6
7
8
9
10
11
12
13
1Country Name (2 letter code) [AU]:cn
2State or Province Name (full name) [Some-State]:china
3Locality Name (eg, city) []:guangdong
4Organization Name (eg, company) [Internet Widgits Pty Ltd]:test
5Organizational Unit Name (eg, section) []:test
6Common Name (e.g. server FQDN or YOUR name) []: *****   /* 此处填写本机客户端,即计算机名称 */
7Email Address []:1131260522@qq.com
8
9Please enter the following 'extra' attributes
10to be sent with your certificate request
11A challenge password []:123456
12An optional company name []:test
13
  • openssl x509 -req -CA ca.crt -CAkey ca.key -CAcreateserial -in server.csr -out server.crt


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
1/* client.js */
2var tls = require('tls');
3var fs = require('fs');
4var options = {
5    host:'www.jstest.com',
6    key: fs.readFileSync('./client.key'),
7    cert: fs.readFileSync('./client.crt'),
8    ca: [fs.readFileSync('./ca.crt')]
9};
10var stream = tls.connect(8000, options, function () {
11    console.log('client connected', stream.authorized ? 'authorized' : 'unauthorized');
12    process.stdin.pipe(stream);
13});
14stream.setEncoding('utf8');
15stream.on('data', function (data) {
16    console.log(data);
17});
18stream.on('end', function () {
19    server.close();
20});
21

启动服务器以及客户端,观察结果:

前端点滴(Node.js)(四)网络编程 ---- 侧重(下)

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

三、https 服务

https服务就是工作在TLS/SSL上的http,创建一个https服务已是一个简单不过的事情。

1. 准备证书

https服务需要用到的私钥以及签名证书,我么可以直接用上面的私钥以及证书进行实例。

2. 创建 https服务器端

区别于http,创建一个https服务只比创建一个http多一个选项配置options,其余地方非常类似。


1
2
3
4
5
6
7
8
9
10
11
12
13
1var https = require('https');
2var fs = require('fs');
3/* 配置私钥以及证书 */
4var options = {
5    key: fs.readFileSync('./server.key'),
6    cert: fs.readFileSync('./server.crt')
7};
8https.createServer(options, function (req, res) {
9    res.writeHead(200);
10    res.end("hello world\n");
11}).listen(8000);
12
13

3. 创建 https 客户端


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
1var https = require('https');
2var fs = require('fs');
3var options = {
4    host: 'www.jstest.com',  /* 一定要书写正确,否则 Game Over */
5    port: 8000,
6    path: '/',
7    method: 'GET',
8    key: fs.readFileSync('./client.key'),
9    cert: fs.readFileSync('./client.crt'),
10    ca: [fs.readFileSync('./ca.crt')]
11};
12options.agent = new https.Agent(options);
13var req = https.request(options, function (res) {
14    res.setEncoding('utf-8');
15    res.on('data', function (d) {
16        console.log(d);
17    });
18});
19req.end();
20req.on('error', function (e) {
21    console.log(e);
22});
23

启动服务器以及客户端,观察结果:

前端点滴(Node.js)(四)网络编程 ---- 侧重(下)

到浏览器搜索:https://www.jstest.com:8000,查看结果:

前端点滴(Node.js)(四)网络编程 ---- 侧重(下)

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

至于如何配置Chrome信任自签CA,在此不作论述………

给TA打赏
共{{data.count}}人
人已打赏
安全技术

c# 实现MD5,SHA1,SHA256,SHA512等常用加密算法

2021-8-18 16:36:11

安全技术

C++ 高性能服务器网络框架设计细节

2022-1-11 12:36:11

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索