SSL工作原理简介

需要知道的知识

  1. CA是什么?
    CA证书授权中心(Certificate Center),也就是证书签发机构,比如Godaddy、WoSign,如果自己给自己签发证书,那我们自己就是CA,只不过别人不认可。他有两个重要属性,即:一、本身受信任,国际认可;二、给他受信任的申请对象签发证书。
  2. 什么是对称加密非对称加密,什么是公钥私钥?
    通俗一点讲对称加密就是:用密钥加密明文得到的密文,使用该密钥解密得到明文。非对称加密:用密钥A加密明文得到的密文,使用密钥B解密得到明文,加密和解密的密钥不是同一个,我们称密钥A为私钥,密钥B为公钥。

因此要记住的一点常识:私钥用于加密,公钥用于解密。

  1. CA.key CA.crt Server.key Server.crt Client.key Client.crt等都是什么?
    一般来说他们两个一组分别表示私钥和证书如下:

【CA.key  CA.crt】
【Server.key Server.crt】
【Client.key  Client.crt】
上面我们说了私钥和公钥的关系,那和证书的关系呢?证书简单来说就是带签名的身份信息。具体构成如下:

SSL证书构成.jpg | center | 457x347

  1. 证书是如何签发的

SSL证书签发流程.jpg | center | 486x527

服务器生成请求文件Server.csr,该文件内容主要是Server.key、组织信息、个人信息。提交给CA,CA审核之后签发给Server证书即Server.crt。该证书包括签名和明文信息两部分,其中签名使用ca.key即ca的私钥加密,到这里我们就能明白通过ca.pub也就是CA的公钥就能解密该签名信息,后面会提到为什么要解密该段签名。

  1. 单向SSL工作流程

SSL工作流程 (1).jpg | center | 654x503

(1) 申请证书:服务器生成请求文件Server.csr提交给CA
(2) 审核:CA审核服务器真实性
(3) 签发证书:证书内容就是上面提到的全部内容。到这里已经完成了整个SSL应用的部署,后面的步骤是具体的SSL工作流。
(4) TCP请求:当客户端要和服务器端通信,需要客户端发起一个TCP请求
(5) 返回证书:Server接收到Client的请求后会将证书Server.crt发送给Client。
(6) 验证证书:Client收到服务器证书Server.crt之后会对证书的签名解密,因此要用到对应的公钥,也就是CA的公钥,CA的公钥在CA证书里可以找到,CA证书是提前安装在客户端的。解密签名之后就可以校验摘要信息,域名信息等正确性
(7)协商通信密钥:如果证书校验通过,Server和Client将进行秘钥协商,然后Server和Client通信过程会采用对称秘钥加密。

  1. 单向认证和双向认证是什么?
    大多情况下,尤其是web站点大多是单向认证即客户端只校验服务端真实性。双向认证在安全要求比较高的场景下需要双方都校验对方,两个过程极其类似,只是在Client认证完服务器证书后,Client会将自己的证书client.crt传给服务器,服务器验证通过后然后开始秘钥协商。

使用脚本自签证书

将 req_distingushed_name CN 192.168.10.253 和192.168.10.26 更改为自己的服务端和客户端IP或者域名,如果客户端不提供CN,直接将客户端的该项目删除即可。

#!/bin/bash

# * Redistributions in binary form must reproduce the above copyright
#   notice, this list of conditions and the following disclaimer in the
#   documentation and/or other materials provided with the distribution.
# * Neither the name of the axTLS project nor the names of its
#   contributors may be used to endorse or promote products derived
#   from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#

#
# Generate the certificates and keys for testing.
#


PROJECT_NAME="TLS Project"

# Generate the openssl configuration files.
cat > ca_cert.conf << EOF
[ req ]
distinguished_name     = req_distinguished_name
prompt                 = no

[ req_distinguished_name ]
 O                      = $PROJECT_NAME Dodgy Certificate Authority
EOF

cat > server_cert.conf << EOF
[ req ]
distinguished_name     = req_distinguished_name
prompt                 = no

[ req_distinguished_name ]
 O                      = $PROJECT_NAME
 CN                     = 192.168.10.253
EOF

cat > client_cert.conf << EOF
[ req ]
distinguished_name     = req_distinguished_name
prompt                 = no

[ req_distinguished_name ]
 O                      = $PROJECT_NAME Device Certificate
 CN                     = 192.168.10.26
EOF

mkdir ca
mkdir server
mkdir client
mkdir certDER

# private key generation
openssl genrsa -out ca.key 1024
openssl genrsa -out server.key 1024
openssl genrsa -out client.key 1024


# cert requests
openssl req -out ca.req -key ca.key -new \
            -config ./ca_cert.conf
openssl req -out server.req -key server.key -new \
            -config ./server_cert.conf
openssl req -out client.req -key client.key -new \
            -config ./client_cert.conf

# generate the actual certs.
openssl x509 -req -in ca.req -out ca.crt \
            -sha1 -days 5000 -signkey ca.key
openssl x509 -req -in server.req -out server.crt \
            -sha1 -CAcreateserial -days 5000 \
            -CA ca.crt -CAkey ca.key
openssl x509 -req -in client.req -out client.crt \
            -sha1 -CAcreateserial -days 5000 \
            -CA ca.crt -CAkey ca.key



openssl x509 -in ca.crt -outform DER -out ca.der
openssl x509 -in server.crt -outform DER -out server.der
openssl x509 -in client.crt -outform DER -out client.der


mv ca.crt ca.key ca/
mv server.crt server.key server/
mv client.crt client.key client/

mv ca.der server.der client.der certDER/

rm *.conf
rm *.req
rm *.srl

生成证书如下:

├── ca
│   ├── ca.crt
│   └── ca.key
├── ca.zip
├── certDER
│   ├── ca.der
│   ├── client.der
│   └── server.der
├── client
│   ├── client.crt
│   └── client.key
├── server
    ├── server.crt
    └── server.key

EMQ配置用户名密码授权

进入emqttd安装目录,在etc/plugins下的emq_auth_username.conf。

image.png | left | 827x40

配置相应的用户名密码

image.png | left | 694x217

启用emq_auth_username插件:

./bin/emqttd_ctl plugins load emq_auth_username

EMQ配置单向SSL认证

listener.ssl.external.handshake_timeout = 15
listener.ssl.external.keyfile = etc/certs/server/server.key
listener.ssl.external.certfile = etc/certs/server/server.crt

EMQ配置双向SSL认证

## 开启双向认证
listener.ssl.external.cacertfile = etc/certs/ca/ca.crt
listener.ssl.external.verify = verify_peer
listener.ssl.external.fail_if_no_peer_cert = true

测试

Python写的基于Paho的双向认证测试脚本

# coding=utf8
import paho.mqtt.client as mqtt
from paho.mqtt.client import MQTT_LOG_DEBUG

def on_connect(client, userdata, flags, rc):
    print("Connected with result code " + str(rc))

client = mqtt.Client()
client.on_connect = on_connect

# 项目目录
crtPath = '/home/evenvi/workspace/project_pri/deploy'
ca_certs = "%s/ca/ca.crt"%crtPath
certfile = "%s/client/client.crt"%crtPath
keyfile = "%s/client/client.key"%crtPath



client.tls_set(ca_certs=ca_certs,
               certfile=certfile,
               keyfile=keyfile
               )
client.username_pw_set('admin', 'public')
client.connect('192.168.10.253', 8883)

client.loop_start()

msg = 'hello,world'
client.publish("tets/topic", msg, 0)
print("message published")

client.disconnect()
client.loop_stop()

print "done."

结语

MQTT是M2M的重要协议,其高效、简单、低成本的特点吸引了大批的开发者。同样MQTT的安全问题不容忽视,通过对SSL过程的梳理进一步加深对MQTT认识。

部分内容参考:
SSL/TLS 双向认证(二) -- 基于mosquittto的MQTT双向认证]

Tags: none

Related Posts:
  • [尚无相关文章]

6 Comments »

  1. guan~gege

    怎么滴 要上https了?

    1. 甲方要求哈

    2. wlj1988

      博主写的很具体,参考博主的文章实现了mqtt自己签发证书,实现ssl加密功能。赞一个。

  2. SuperMe

    This solution is very good and helps me solve the basic problems, especially when dealing with MQTT's own issuance of SSL certificates, I don't know how to operate.

  3. 海阔天空

    有个问题要请教下,那个emq好用还是mosquito好用,你们在生产环境里是如何选型的。另外ssl加密之后对速度有影响吗?

    1. emq周边做的很全,mosquito简单方便,看自己项目需求做选型吧。
      另外ssl对速度几乎没有影响

Leave a Comment