Contents
  1. 1. 前言
  2. 2. 正文
    1. 2.1. 简介
    2. 2.2. 要求
    3. 2.3. 基本步骤
    4. 2.4. 具体过程

前言

做了很久的实验,一直没能成功,最后还是down的大佬的源码,侵删。

正文

简介

MQTT协议是物联网应用中重要的应用层协议,上一次实验开展了MQTT协议的分析,对MQTT协议的长连接机制、发布/订阅工作模式交互机制进行了分析。但如果MQTT协议不进行安全实现,黑客可以恶意发布信息给服务器,特别是在工业、交通等物联网应用场合后果不堪设想。本实验旨构建MQTT协议安全通信。

要求

(1)掌握MQTT的安全通信的基本原理。

(2)设计MQTT安全通信的安全措施。

(3)实现基于TLS的MQTT通信。

基本步骤

(1)应用层:MQTT协议提供了客户标识以及用户名密码,以便验证设备。基于ACL对主题的订阅和发布权限设置基本的授权。

(2)传输层:传输层可使用TLS加密、验证证书机制,防止中间人攻击。

(3)网络层:可以通过专线或者使用VPN来连接设备与MQTT代理,以提高网络传输的安全性。可以通过防火墙保护MQTT代理端,比如限制端口、限制协议、限制IP段。

注意构建一个局域网,模拟MQTT服务端(代理端)、客户端(分订阅和发布),运用Wireshark抓包分析安全通信过程。

Z1QfoT.png

具体过程

服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
var mosca = require('mosca')
var SECURE_KEY = __dirname + '/tls-key.pem';
var SECURE_CERT = __dirname + '/tls-cert.pem';
var settings = {
logger: {
name: "secureExample",
level: 40,
},
secure : {
port: 9090,
keyPath: SECURE_KEY,
certPath: SECURE_CERT,
}
};
var server = new mosca.Server(settings);
server.on('published', function(packet, client) {
//当客户端有连接发布主题消息
var topic = packet.topic;
console.log(packet);
switch (topic) {
case 'test':
console.log('收到消息:', packet.payload.toString());
//MQTT转发主题消息
//MqttServer.publish({ topic: 'other', payload: 'sssss' });
break;
case 'other':
console.log('message-123', packet.payload.toString());
break;
}
});
server.on('ready', setup);
//若用户名与密码有效,接受链接
var authenticate = function(client, username, password, callback) {
var authorized = (username === 'alice' && password.toString() === 'secret');
if (authorized) {
client.user = username;
console.log('通过认证登录的用户:', username);
}
callback(null, authorized);
}

// 授权为alice的客户端可以发布/users/alice,
// 从主题中取得用户名,并校验与授权用户一致
var authorizePublish = function(client, topic, payload, callback) {
callback(null, client.user == topic);
}

// 授权为alice的客户端可以订阅/users/alice,
// 从主题中取得用户名,并校验与授权用户一致
var authorizeSubscribe = function(client, topic, callback) {
callback(null, client.user == topic);
}
//mosca配置
function setup() {
console.log('Mosca secure server is up and running')
server.authenticate = authenticate;
server.authorizePublish = authorizePublish;
server.authorizeSubscribe = authorizeSubscribe;
}

Z1lg9e.png

订阅方**

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var mqtt = require('mqtt');
var fs = require('fs')
var path = require('path')
var KEY = fs.readFileSync(path.join(__dirname, '/tls-key.pem'))
var CERT = fs.readFileSync(path.join(__dirname, '/tls-cert.pem'))
var TRUSTED_CA_LIST = fs.readFileSync(path.join(__dirname, '/crt.ca.cg.pem'))
var PORT = 9090
var HOST = "127.0.0.1"
var options = {
port: PORT,
host: HOST,
key: KEY,
cert: CERT,
rejectUnauthorized: false,
ca: TRUSTED_CA_LIST,
protocol: 'mqtts',
//订阅者实现认证的参数
username:"alice",
password:"secret"
}
var client2 = mqtt.connect(options)
client2.subscribe('alice',{qos:0});//订阅主题为alice的消息
client2.on('message',function(top,message) {
console.log('收到消息:', message.toString());
});

Z1lxH0.png

发布方**

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
var mqtt = require('mqtt');
var fs = require('fs')
var path = require('path')
var KEY = fs.readFileSync(path.join(__dirname, '/tls-key.pem'))
var CERT = fs.readFileSync(path.join(__dirname, '/tls-cert.pem'))
var TRUSTED_CA_LIST = fs.readFileSync(path.join(__dirname, '/crt.ca.cg.pem'))
var PORT = 9090
var HOST = "127.0.0.1"
var options = {
port: PORT,
host: HOST,
key: KEY,
cert: CERT,
rejectUnauthorized: false,
ca: TRUSTED_CA_LIST,
protocol: 'mqtts',
//发布者实现认证的参数
username:"alice",
password:"secret"
}
var client = mqtt.connect(options)
var num = 0;
var qtt = {}; //定义消息
qtt = 'hello world';
//一秒钟发送一次消息setr=xxxxxxx1xx
setInterval(function() {
client.publish('alice', qtt, { qos: 0, retain: true });
}, 10000);

Z11PCF.png

抓包分析

Z11VD1.png

1 客户端发出请求(ClientHello)

Z111vd.png

(1) 客户端与服务端通过tcp三次握手建立tcp连接后,客户端首先向服务器发出建立加密通信的请求,发送ClientHello请求,从消息体结构看,tls/ssl是基于tcp连接之上,应用层之下的协议。

2 服务器响应(SeverHello)

Z11WPU.png

Z11fGF.png

服务器收到客户端请求后,向客户端发出响应,叫做Sever Hello。

从消息体中,可以看到服务器的响应包含以下内容:

(1) 确认使用的加密通信协议版本,这里确认使用tls1.2,而不是client hello中的tls1.1。响应握手协议消息 server hello。如果浏览器与服务器支持的版本不一致,服务器关闭加密通信。

(2) 一个服务器生成的随机数,稍后用于生成”对话密钥”。

(3) 确认使用的加密套件,这里为rsa+aes128+sha256

(4) 压缩方法为空。

(5) 一些列扩展信息

3 服务端发送服务端电子证书(CA),密钥交换(server key exchange),及server hello done三个握手消息

Z13pqI.png

客户端接收到server hello握手消息后,及时反馈ack消息。服务端接收客户端ack消息后,发送服务端电子证书,密钥交换,及server hello done三个握手消息

从封装内容看,包含两层ssl协议体信息,头一个为服务端证书,后面跟着公共密钥交换和hello done消息体,具体如下:

(1)详细的电子证书信息和CA认证机构信息

(2)密钥交换信息,包括DH算法计算出的pubkey公钥,电子签名的hash算法值

(3)server hello done消息体

4 客户端发送密钥交换信息(client key exchange)、编码改变协议消息(change cipher spec)

Z13mss.png

客户端发送ack消息给服务端,确认收到server hello done消息,然后发送客户端的密钥交换信息和修改密钥的协议消息

主要内容如下:

(1) 发送DH算法计算的pubkey,用于服务端计算生成解密私钥

(2) 发送编码改变通知,表示随后的信息都将用双方商定的加密方法和密钥发送。

(3) 发送加密后的握手消息,一个随机数。该随机数用服务器公钥加密,防止被窃听

(4) 客户端握手结束通知,表示客户端的握手阶段已经结束。这一项同时也是前面发送的所有内容的hash值,用来供服务器校验。(可能在加密消息中,未确认)

客户端收到服务器所有响应消息后,首先验证服务器证书。如果证书不是可信机构颁布、或者证书中的域名与实际域名不一致、或者证书已经过期,就会向访问者显示一个警告,由其选择是否还要继续通信。

如果证书没有问题,客户端就会从证书中取出服务器的公钥,即server key exchange消息中携带的pubkey值。然后,根据根据已经收到的三个随机数计算书加密密钥,对握手信息进行加密通信,然后向服务器发送上面抓包中三项信息内容。

​ 至此,整个握手阶段全部结束。接下来,客户端与服务器进入加密通信,就完全是使用普通的HTTP协议,只不过用”会话密钥”加密数据内容。

五 实验体会(不少于300字)

​ TLS(Transport Layer Security,安全传输层),TLS是建立在传输层TCP协议之上的协议,服务于应用层,它的前身是SSL(Secure Socket Layer,安全套接字层),它实现了将应用层的报文进行加密后再交由TCP进行传输的功能。

​ TLS协议主要解决如下三个网络安全问题。

1、保密(message privacy),保密通过加密encryption实现,所有信息都加密传输,第三方无法嗅探;

2、完整性(message integrity),通过MAC校验机制,一旦被篡改,通信双方会立刻发现;

3、认证(mutual authentication),双方认证,双方都可以配备证书,防止身份被冒充;

下面是TLS的握手过程。详细步骤上面也说过了。

Z13Gz4.png

Client1:TLS版本号 + 所支持加密套件列表 + 希望使用的TLS选项

Server1:选择一个客户端的加密套件 + 自己的公钥 + 自己的证书 + 希望使用的TLS选项 +(要求客户端证书)

Client2:(自己的证书) + 使用服务器公钥和协商的加密套件加密一个对称密钥

Server2:使用私钥解密出对称密钥后,发送的加密的Finish消息,表明完成握手

任何事物都是有利有弊,引入TLS机制固然是能够保证安全,但却在TCP握手和HTTP通信之间,多加了两个往返的TLS握手过程。

安全问题:

​ 可能存在中间人攻击。

Contents
  1. 1. 前言
  2. 2. 正文
    1. 2.1. 简介
    2. 2.2. 要求
    3. 2.3. 基本步骤
    4. 2.4. 具体过程