python - ActiveMQ-带有Python STOMP客户端的STOMP + SSL

标签 python ssl activemq stomp stomp.py

有谁能解释一下如何将ssl添加到我正在使用的python stomp客户机中。
我在activemq配置文件中添加了stomp+ssl传输连接器,我的基本python stomp客户端如下:

import time
import sys
import stomp
class MyListener(stomp.ConnectionListener):
    def on_error(self, headers, message):
        print('received an error "%s"' % message)
    def on_message(self, headers, message):
        print('received a message "%s"' % message)
conn = stomp.Connection()
conn.set_listener('', MyListener())
conn.start()
conn.connect('admin', 'password', wait=True)
conn.subscribe(destination='/queue/test', id=1, ack='auto')
conn.send(body=' '.join(sys.argv[1:]), destination='/queue/test')
time.sleep(2)
conn.disconnect()

我创建了http://activemq.apache.org/how-do-i-use-ssl.html文档中给定的密钥存储和信任存储,并将它们添加到代理中的SSL_OPTS环境变量中,但是我无法找到如何使用密钥存储和信任存储初始化Python STOMP客户端我应该使用stomp.Connection()方法中给出的ssl参数吗?如果是,如何使用?
有人能解释一下是否有其他方法可以在stomp上添加ssl吗?

最佳答案

Python STOMP client(从4.1.20版起)使用SSLContext来处理其密钥对/证书,因此没有理由为客户端生成Java密钥库。
考虑到这一点,让我们完成设置ApacheMQ以支持SSL包装的STOMP连接的整个过程以下过程已在ApacheMQ 5.15.4上进行了测试我们通过在代理和客户机之间手动移动自签名证书来显式地建立双向信任;使用证书颁发机构也是可能的,但是如何这样做是另一个问题。
创建客户端证书
如上所述,在python方面,keystore几乎没有用处,而且由于SSLContext期望使用pem编码的证书,所以我们最好手工创建密钥对和证书(即使用openssl)。首先,在客户机上,让我们创建一个4096位RSA密钥:

openssl genrsa -out client.key 4096

使用此方法,将公钥部分转换为证书并使用密钥本身对其进行签名;由于我们将手动将证书移动到代理,因此自签名证书不是问题:
openssl req -new -out client.csr -key client.key
openssl x509 -req -days 365 -in client.csr -signkey client.key -out client.pem
rm client.csr

STOMP客户端将同时需要已签名的证书client.pem和私钥client.key,而代理只需要证书。
创建代理证书
在代理上,我们可以遵循Apache指南的第一部分,并使用Javakeytool为服务器创建一个密钥库:
keytool -genkeypair -alias broker -keyalg RSA -keysize 4096 -keystore broker.ks

当提示输入“名字和姓氏”时,请提供服务器的主机名,在我们的示例中,我们将简单地将其设置为localhost;如果代理和客户机在不同的服务器上运行,请确保将其设置为Python客户机最终用于标识代理的任何设置:
What is your first and last name?
  [Unknown]:  localhost

所有其他输入值都可以保留为“未知”。
在一天结束时,我们只想允许客户使用我们知道的证书连接到代理,因此此时将上面生成的client.pem复制到代理,并通过
keytool -import -alias client -keystore broker.ts -file client.pem

如果代理允许来自任何客户端的连接,则可以跳过最后一步。
设置apachemq
默认情况下,通过STOMP的所有连接(实际上所有连接)都是纯文本连接,为了启用SSL上的STOMP连接,请将以下<transportConnector />添加到conf/apachemq.xml
<transportConnectors>
    <transportConnector name="stomp+ssl" uri="stomp+nio+ssl://0.0.0.0:61613?transport.enabledProtocols=TLSv1.2&amp;needClientAuth=true" />
</transportConnectors>

请务必删除任何现有的明文连接器,如默认STOP连接器,否则客户端将能够简单地使用这些,绕过SSL要求。还请注意,needClientAuth=true是强制客户端证书验证的原因;没有它,客户端就可以在不提供可信证书的情况下进行连接。
要将ApacheMQ配置为使用上面定义的密钥和信任存储,请定义环境变量ACTIVEMQ_SSL_OPTS到(在Unix上)
export ACTIVEMQ_SSL_OPTS = -Djavax.net.ssl.keyStore=/path/to/broker.ks -Djavax.net.ssl.trustStore=/path/to/broker.ts -Djavax.net.ssl.keyStorePassword=passwordForBrokerKs -Djavax.net.ssl.trustStorePassword=passwordForBrokerTs

或(在Windows上)
set ACTIVEMQ_SSL_OPTS=-Djavax.net.ssl.keyStore=C:\path\to\broker.ks -Djavax.net.ssl.trustStore=C:\path\to\broker.ts -Djavax.net.ssl.keyStorePassword=passwordForBrokerKs -Djavax.net.ssl.trustStorePassword=passwordForBrokerTs

这里,这两个密码是在上一步运行keytool之后选择的如果不需要客户端证书验证,只需省略trustStoretrustStorePassword的配置。
这样,ActiveMQ就可以像往常一样通过bin/activemq start启动要确保ssl配置符合预期,请注意在启动服务器时打印的输出的JVM args部分。
测试stomp客户端
通过正确设置代理,我们还可以配置客户机在这里,我们为stomp.Connection.set_ssl提供对在第一步中创建的密钥和证书的引用假设activemq服务器在localhost:61613上运行,那么测试脚本将
import time
import sys
import stomp

class MyListener(stomp.ConnectionListener):
    def on_error(self, headers, message):
        print('received an error "%s"' % message)
    def on_message(self, headers, message):
        print('received a message "%s"' % message)

host = 'localhost'
port = 61613
conn = stomp.Connection([(host, port)])
conn.set_ssl(for_hosts=[(host, port)], key_file='/path/to/client.key', cert_file='/path/to/client.pem')
conn.set_listener('', MyListener())
conn.start()
conn.connect('admin', 'password', wait=True)
conn.subscribe(destination='/queue/test', id=1, ack='auto')
conn.send(body='test message', destination='/queue/test')
time.sleep(2)
conn.disconnect()

为了确保apachemq确实在验证客户机证书,我们可以重复步骤1并创建一个新的对,比如client2.key/client2.pem并使用它。这样做会导致apachemq打印以下非感官错误消息:
ERROR | Could not accept connection from null : {}
java.io.IOException: javax.net.ssl.SSLHandshakeException: General SSLEngine problem

正在验证代理证书
现在,细心的读者会注意到,我们实际上从未将代理证书移动到客户机,但事情似乎无论如何都在工作。事实证明,stomp.py的默认行为是根本不执行证书验证,从而允许(活动的)攻击者对连接进行mitm。
当我们滚动自签名证书时,要解决这种情况,我们需要做的就是向python客户机提供实际的代理证书。在代理上,通过
keytool -exportcert -rfc -alias broker -keystore broker.ks -file broker.pem

并将broker.pem移到Python客户端现在,在上面的测试脚本中,通过将ssl配置替换为
conn.set_ssl(for_hosts=[(host, port)], key_file='/path/to/client.key', cert_file='/path/to/client.pem', ca_certs='/path/to/broker.pem')

如上所述,我们可以通过重复broker证书生成过程来测试它是否确实在执行正确的验证,以创建一个broker2.pem,在测试脚本中使用它,并注意它将在
ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:833)

关于python - ActiveMQ-带有Python STOMP客户端的STOMP + SSL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46770328/

相关文章:

python - 船舶到海岸线的距离(以海里为单位)

python - 在两个方向的 pandas 列中填充 NaN

Python:如果在没有命名空间的情况下添加新元素,则 xpath.find() 将找不到新元素

java - 默认 SSL 上下文初始化失败 : null

node.js - Nodejs如何从https服务器获取TLS对象

ssl - 自签名证书中要包含哪个证书链文件?

python - matplotlib savefig 线程安全吗?

java - 通过同一个 ActiveMQConnectionFactory 使用多个 ActiveMQ 队列

apache-camel - 为什么ActiveMQ 5.14.x无法启动嵌入camel-jms组件2.18.3

java - 如何在 JBoss 中配置 ActiveMQ JCA 连接器以使用 XA 连接?