前端点滴(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 []:1131260522@qq.com

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 []:1131260522@qq.com

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 []:1131260522@qq.com

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,在此不作论述.........

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值