• ZMQ示例:使用 curve 进行加密通信


    1. ZMQ 官方文档

    ZMQ 的官方文档中关于 curve 的介绍如下:

    Client and server roles
    
    A socket using CURVE can be either client or server, at any moment, but not both. The role is independent of bind/connect direction.
    
    A socket can change roles at any point by setting new options. The role affects all zmq_connect and zmq_bind calls that follow it.
    
    To become a CURVE server, the application sets the ZMQ_CURVE_SERVER option on the socket, and then sets the ZMQ_CURVE_SECRETKEY option to provide the socket with its long-term secret key. The application does not provide the socket with its long-term public key, which is used only by clients.
    
    To become a CURVE client, the application sets the ZMQ_CURVE_SERVERKEY option with the long-term public key of the server it intends to connect to, or accept connections from, next. The application then sets the ZMQ_CURVE_PUBLICKEY and ZMQ_CURVE_SECRETKEY options with its client long-term key pair.
    
    If the server does authentication it will be based on the client's long term public key.
    

      

    官方文档中提到的几个点都很关键:

    • 一个 curve socket 既可以是服务端,也可以是客户端。但不可以既是服务端的同时又是客户端
    • 一个 socket 可以在任何 point (不知道怎么翻译 point 才合适)上通过设置新属性的方式改变角色, 改变一个 socket 角色后,会影响接下来对这个 socket 做的所有 zmq_connect() 和 zmq_bind() 调用, 也就是说需要在这两个调用之前进行 curve 属性的设置。
    • 如果要把一个 socket 作为 curve server ,需要设置 ZMQ_CURVE_SERVER 和 ZMQ_CURVE_SECRETKEY 属性
    • 如果要把一个 socket 作为 curve client,需要设置 ZMQ_CURVE_SERVERKEY 以及 ZMQ_CURVE_PUBLICKEY、ZMQ_CURVE_SECRETKEY 这三个属性

    2. 几行核心代码

    想要使用 ZMQ curve 进行加密通信,需要在 ZMQ 的 server 端和 client 端进行相应的配置, 几行需要进行的配置代码如下:

    2.1 curve server 端

    1 char szsecertkey[128] = {0};
    2 char szpublickey[128] = {0}; //需要把这个 curve 公钥发给 client
    3 zmq_curve_keypair(szpublickey, szsecertkey);
    4 
    5 int option = 1;
    6 zmq_setsockopt(sock, ZMQ_CURVE_SERVER, &option, sizeof(option));
    7 zmq_setsockopt(sock, ZMQ_CURVE_SECRETKEY, szsecertkey, strlen(szsecertkey));
    8 
    9 zmq_bind(sock, szaddr);

    2.2 curve client 端

    //这个 server_publickey 就是从 server 端拿到的 curve 公钥
    zmq_setsockopt(sock, ZMQ_CURVE_SERVERKEY, server_publickey, strlen(server_publickey));
    
    char szpubkey[128] = {0};
    char szprikey[128] = {0};
    zmq_curve_keypair(szpubkey, szprikey); 
    zmq_setsockopt(sock, ZMQ_CURVE_PUBLICKEY, szpubkey, strlen(szpubkey));
    zmq_setsockopt(sock, ZMQ_CURVE_SECRETKEY, szprikey, strlen(szprikey));
    
    zmq_connect(sock, szaddr);

    3. 完整代码及执行
    3.1 完整代码

    代码链接: https://pan.baidu.com/s/1ytJdEa2VmYWfSx6mxIKYVw 提取码: ebyv

    下载代码后,解压,执行编译命令:

    g++ -g -o server server.c -lzmq -lpthread 
    g++ -g -o client client.c -lzmq


    3.2 程序执行

    代码演示了两个模式,一个是使用 curve 加密的传输模式,另一个是不使用 curve 加密的传输模式。 如果要使用 curve 加密的传输模式,需要在执行 server 和 client 程序的时候都加上 -s 参数。

    1) 先执行 server

    1 [root@fengbo 14:46:19 curve]$ ./server -s
    2 server.c 80 : test tZMQ with curve
    3 server.c 90 : szsecertkey = [I%43ZHg-Bnls&6rZ&)<J6hwGlD&I5l7]mi]{Ch-7]
    4 server.c 91 : szpublickey = [kvIP^po{(kRL<eib#Zv=.cE%BpNom2DY#jl0-Ro[]
    5 server.c 102 : start secert comunication
    6 server.c 112 : recv msg : [I say 1]
    7 server.c 119 : send msg : [I say 1, too]

    2) 再执行 Client

    1 [root@fengbo 14:46:18 curve]$ ./client -s
    2 client.c 82 : test tZMQ with curve
    3 client.c 94 : server publickey : [kvIP^po{(kRL<eib#Zv=.cE%BpNom2DY#jl0-Ro[]
    4 client.c 102 : start secert comunication
    5 client.c 109 : send msg : [I say 1]
    6 client.c 112 : recv msg : [I say 1, too]

    4. ZMQ curve 加密效果分析
    通过对加密前与加密后的 ZMQ 消息进行 tcpdump 抓包,可以看到 ZMQ curve 的加密效果如何。

    因为使用的是 127.0.0.1 作为测试地址,所以在使用 tcpdump 抓包的时候选择 lo 网口:

    tcpdump -i lo -A -vv -X


    4.1 加密前的抓包记录

    对于不可打印的字符,tcpdump 都以点号 '.' 进行了显示

     1 14:13:49.788893 >.E.........
     2 10:53:07.333841 <.E.>.E.....
     3 14:13:49.788919 >.E.
     4 14:13:49.788990 <.E...........
     5 14:13:49.788997 >.E.
     6 14:13:49.789294 <.E............
     7 14:13:49.789303 >.E.
     8 14:13:49.789634 <.E...NULL................................................
     9 14:13:49.789875 >.E..NULL................................................
    10 14:13:49.789900 <.E..).READY.Socket-Type....DEALER.Identity....
    11 14:13:49.790309 >.E.
    12 14:13:49.790369 <.E..).READY.Socket-Type....DEALER.Identity......I.say.1
    13 14:13:49.790561 >.E...I.say.1,.too
    14 14:13:49.829945 <.E.

    上面显示的信息是经过简化后的解析数据,不过可以看到 ZMQ 的两个 socket 之间通信的细节,例如可以看到几个 ZMQ 的关键字: DEALERSocket-TypeIdentity

    以及 client 发送的数据 I say 1 ,和 server 返回的数据 I say 1, too

    很明显,数据在 ZMQ 中是以明文进行传输的。

    4.2 加密后的抓包记录

    15:05:06.178841 ....>.6/........
    09:09:44.849972 ....>.6/>.6/....
    15:05:06.178864 >.6/>.6/
    15:05:06.178975 >.6/>.6/..........
    15:05:06.178982 >.6/>.6/
    15:05:06.179369 >.6/>.6/...........
    15:05:06.179376 >.6/>.6/
    15:05:06.180410 >.60>.6/..NULL................................................
    15:05:06.180571 >.61>.60.NULL................................................
    15:05:06.180588 >.61>.60.).READY.Socket-Type....DEALER.Identity....
    15:05:06.181017 >.61>.61
    15:05:06.181064 >.61>.61.).READY.Socket-Type....DEALER.Identity......request.publickey
    15:05:06.181191 >.61>.61.((#65P{8?aJEt@lWf/DDeQo@QX@gN{4nF3:?jz<^-
    15:05:06.183369 ....>.63........
    09:10:02.029846 ....>.63>.63....
    15:05:06.183389 >.63>.63
    15:05:06.183485 >.64>.63..........
    15:05:06.183491 >.64>.64
    15:05:06.183676 >.64>.64...........
    15:05:06.183681 >.64>.64
    15:05:06.184210 >.64>.64..CURVE...............................................
    15:05:06.185457 >.66>.64.CURVE...............................................
    15:05:06.188362 >.68>.66...HELLO........................................................
                     ....................{...:H_....."R&.....w.N..r..L...........Rv(b...F...
                     -+u.w....M...j).B.!<j.'...(..j...*..Qw........G.....c.....Y....:...
    15:05:06.190931 >.6;>.68...WELCOME..6k.......,......a}.R..C.....>....|..a.z#...A[;..Yy..
                     ..F`......k.......~...k.fDa./../.A7..m..J......i.b.......<.k.....T.....
                     ..{......Y.........b..B....@w..t.MM
    15:05:06.196571 >.6A>.6;........$.INITIATEX......fXA..{J%D<...O.i?4.3$.../.../J#....ZpF
                     xZ...r...pj...C.&.k,...]`KF..|.i4.H(K..W..Fm".BU...........!...x....<..
                     ....T....Z...6a....A....P.......c.V...........[E.n...|`@.~..5.aua..p...
                     #..N.7...._.....A....!.}....^Y2=2..)5..K.(.6+.e6]..`..$;..k".g.].~.A.Hn
                     ...GS%.U.ot..whb<..>..D
    15:05:06.201254 >.6E>.6A.A.READY.........H.f.n....sS.....p.y.ZM..F........l........wY.3?G.
    15:05:06.202853 >.6G>.6E.(.MESSAGE..........t.oR..&:.SI..QI.m.....
    15:05:06.203034 >.6G>.6G.-.MESSAGE.............O]i.......9.M....to....#
    15:05:06.220452 >.6Y>.61
    15:05:06.242435 >.6o>.6G
    15:05:08.539483 >.?h>.6G.(.MESSAGE.........3n..l6~~..N.......[:T.
    15:05:08.539814 >.?h>.?h.-.MESSAGE...........<.3..A.9..Mq..=.........vs
    15:05:08.539824 >.?h>.?h

    从 tcpdump 抓取的数据可以看到 CURVE 这样的字符,这说明 ZMQ 开始建立 curve 加密链接了。 不过在建立 curve 链接之前,有一个 client 向 server 请求公钥的操作,我们甚至可以在抓到的数 据中看到 server 发送给 client 的公钥 [(#65P{8?aJEt@lWf/DDeQo@QX@gN{4nF3:?jz<^-]。

    因为传输公钥是在建立 curve 链接之前进行的, 所以我们还是可以看到明文数据的。

    在上面的抓包数据中, CURVE 关键字出现的时候,就是 server 和client 开始进行 curve 链接的过程了, 可以看到这几个关键字:HELLO、WELCOME、INITIATEX、READY、MESSAGE。这些都是 ZMQ 的 curve 协议的一部分。

    在上面的抓包数据中,我们没有看到 I say 1,也没有看到 I say 1, too。因为这些数据已经被加密传输了。 不过我们可以猜到,I say 1 和 I say 1, too 就跟在最后三行的两个 MESSAGE 的后面,只不过被加密了,我们看不到。


    同步发表:https://www.fengbohello.top/archives/zeromq-curve

  • 相关阅读:
    一张900w的数据表,16s执行的SQL优化到300ms?
    webpack学习收集
    集合对象的string类型字段进行排序
    react 项目中使用antd的select组件placeholder不生效的解决方法
    React Hook做页面跳转以及携带参数,并且获取携带的值
    eclipse jar包 Source not found
    细说Redis分布式锁🔒
    Spring Boot中有多个@Async异步任务时,记得做好线程池的隔离!
    HDFS基本命令
    斐波那契数(Java)
  • 原文地址:https://www.cnblogs.com/fengbohello/p/9735333.html
Copyright © 2020-2023  润新知