【发布时间】:2018-02-15 11:55:00
【问题描述】:
我想通过 PHP 应用程序(脚本)使用 SSL 认证连接到 WebSphere MQ 队列。
- 队列管理器版本为 7.0 或 7.5
- MQ 客户端版本为 8.0
- PHP 版本为 7.0 (docker)
- 使用 PHP mqseries pecl 扩展 v0.15(带有自定义修复)
到目前为止,我能够在没有 SSL 连接的情况下进行连接。
到目前为止,我必须完成以下步骤:
- 我已经安装了适用于 Linux 的 WebSphere MQ Client v8(在我的例子中是 CentOS)
- 我已经下载了 mqseries php 扩展的 PECL 0.15 版本。 (作为扩展中的一个小错误,我不得不重新编译它以使其正常工作。我曾经在 MQGET 上遇到分段错误。
- 我将 mqseries.so 链接到 php 并启用了扩展。
我成功了(没有 SSL)
- 连接到队列管理器
- 打开阅读队列
- 获取队列中的消息
- 关闭连接
当我将脚本中的 USE_SSL 设置为 true 时,我收到错误代码 2393,意思是“An MQCONN or MQCONNX call was issued with SSL configuration options specified, but an error occurred during the initialization of the SSL environment.”此错误消息非常笼统,无法帮助我确定问题出在哪里。
MQ_KEYSTORE 设置为/path/to/my/key,我的文件名是key.kdb,与documentation 建议的级别相同key.sth
脚本中的MQ_SSL_CIPHER_SPEC 与指定MQ_CHANNEL_SSL 在队列管理器上指定的相同。检查了多次。这些不是用于 JMS 连接的Cipher Suite
队列管理器上的安全缓存已刷新。
在服务器端,我检查了队列管理器的错误日志,但似乎没有看到我的通道名称。我说“似乎”是因为有很多噪音,并且有几个??? 频道名称。所以我觉得由于某种原因它没有到达队列管理器。
我还使用了 MQ 客户端安装 bin 文件夹中的“amqssslc”命令来测试我的 ssl 配置。我得到与使用 PHP 脚本相同的错误。
我还使用 WireShark 在相应的MQ_PORT 上嗅探数据包。包的内容包含证书信息。所以有些事情看起来像是 SSL 握手。
我现在对如何调试案例一无所知。有谁知道接下来要检查什么?我应该检查我的 MQ 客户端安装上的连接日志吗?
这是connection using SSL in PHP的示例
这是我的 MQ 脚本的简化版本(我删除了输出)。出于安全目的,某些常量未公开。
所有 MQSERIES_* 常量都在扩展中定义
所有 MQ_* 都是用于测试我的脚本的硬编码参数,但它们的定义没有出现在脚本摘录中。
<?php
// Constants defined here
$options = [
'Version' => MQSERIES_MQCNO_VERSION_4,
'Options' => MQSERIES_MQCNO_STANDARD_BINDING,
'MQCD' => [
'Version' => 7,
'ChannelName' => MQ_CHANNEL,
'ConnectionName' => sprintf('%s(%s)', MQ_HOST, MQ_PORT),
'TransportType' => MQSERIES_MQXPT_TCP,
]
];
if (USE_SSL) {
$options['MQSCO'] = [
'KeyRepository' => MQ_KEYSTORE
];
$options['MQCD']['ChannelName'] = MQ_CHANNEL_SSL;
$options['MQCD']['SSLCipherSpec'] = MQ_SSL_CIPHER_SPEC;
}
mqseries_connx(MQ_QUEUE_MANAGER, $options, $conn, $comp_code, $reason );
$mqods2 = [
'ObjectType' => MQSERIES_MQOT_Q,
'ObjectName' => MQ_QUEUE
];
mqseries_open($conn, $mqods2, MQSERIES_MQOO_INPUT_AS_Q_DEF | MQSERIES_MQOO_FAIL_IF_QUIESCING, $obj, $comp_code, $reason);
$gmd = [];
$gmo = [
'Options' => MQSERIES_MQGMO_FAIL_IF_QUIESCING | MQSERIES_MQGMO_WAIT, 'WaitInterval' => 3000
];
$msg = "";
$data_length = "";
for ($i = 0; $i < 1000; $i++) {
mqseries_get($conn, $obj, $gmd, $gmo, 10000, $msg, $data_length, $comp_code, $reason);
if ($reason === 2033) {
printf("No more messages to process\n");
break;
}
// Business logic
}
mqseries_disc($conn, $comp_code, $reason);
?>
更新
使用我不知道存在的客户端日志。我们终于发现我们的服务器没有使用正确的证书。服务器的证书实际上是自签名的,因此没有授予我们访问权限,因为我们的 .kdb 文件没有它的公钥。我们将服务器自己的公钥添加到 .kdb 文件中,使该步骤顺利进行。
正如 JoshMC 的 cmets 中所建议的,对于我们的下一个问题,我们怀疑密钥库文件中的标签错误。我们没有从 .kdb 文件中指定特定标签。来自docs“For queue managers and clients respectively, the following sources are searched in sequence for a non-empty value. The first non-empty value determines the certificate label. The certificate label must exist in the key repository. If no matching certificate in the correct case and format is found that matches a label, an error occurs and the SSL or TLS handshake fails.”
它还声明“The certificate label cannot contain spaces.”。
我将在明天再次尝试使用正确的标签命名并发送特定的标签名称。我将尝试查看名称约定 ibmwebspheremq<user_that_runs_the_php_process> 是否真的会影响有效性。
更新 2
终于成功了。正如 JoshMC 所提到的,私钥需要具有特定的标签 ibmwebspheremq。我还没有尝试过 CertificateLabel。下周我可能会深入研究。
起初我们使用 ibm 的 GUI (ikeyman) 来生成 .kdb 文件。但是我们发现它有很多错误。例如,它导入两次具有相同标签的私钥(从证书自动生成的标签)。无法编辑标签名称(因此存在连接问题)。为了解决这部分问题,我们使用了命令行工具ikeycmd,它基本上在命令行上提供了相同的功能(减去错误)。要运行该命令,您需要 IBM jre(未验证,需要签出)并将其作为 java com.ibm.gsk.ikeyman.ikeycmd 运行。从这里开始,IBM 网站上有大量关于如何创建证书、重命名标签、检查详细信息等的文档。非常有趣!
【问题讨论】:
-
key.kdb 中包含什么?这是否包含带有
ibmwebspheremq<user_that_runs_the_php_process>之类标签的私钥?队列管理器通道是否有SSLCAUTH(REQUIRED)或OPTIONAL? -
如果这是一个完整的客户端安装,那么它会将客户端错误记录到
/var/mqm/errors/AMQERR01.LOG并且可能/var/mqm/errors/*.FDC也会检查这些位置。如果在客户端协商通道之前连接失败,qmgr 可以记录通道名称???。您没有说队列管理器使用的是哪个版本的 MQ,但如果它是 7.5 或更低版本,则在 TLS 握手完成之前不会交换通道名称。使用 v8 和更高版本的客户端到 v8 和更高版本的服务器,他们可以在 TLS 协商期间使用 TLS SNI 交换通道名称,但 MQ 可能不会记录这一点。 -
哇,我花了那么多时间寻找问题,但我从未见过这些日志。这是一个认证问题。所有的问题细节一直都在那里。现在只需要解决这个问题,它应该可以工作。
-
队列管理器是 v7.0 还是 v7.5 不确定,客户端是 v8
-
另请注意,对于 v8 及更高版本,您可以在 mqclient.ini 的
SSL节中使用CertificateLabel=anyvalue。可以从 /var/mqm/mqclient.ini 复制一个模板并放置在应用程序执行的目录中,也可以通过环境变量指定位置,或放置在主目录中。这记录在 IBM MQ v8 KC 页面“SSL stanza of the client configuration file”中。