php - 如何在PHP中使用SSL认证连接到WebSphere MQ队列

标签 php ssl ibm-mq

我想使用来自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 Client安装bin文件夹中找到的“ amqssslc”命令来测试我的ssl配置。与使用PHP脚本相比,我得到了相同的错误。

我还使用WireShark在相应的MQ_PORT上嗅探数据包。软件包的内容包含证书信息。因此,有些事情看起来像是SSL握手。

我现在对如何调试外壳一无所知。有谁知道下一步要检查什么?我应该检查MQ Client安装上的连接日志吗?

这是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的评论中所建议,对于我们的下一个问题,我们怀疑密钥库文件中的标签错误。我们没有从.kdb文件中指定特定标签。从docsFor 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网站上提供了有关如何创建证书,重命名标签,检查详细信息等的大量文档。无数的乐趣!

最佳答案

完整安装IBM MQ客户端后,客户端错误将记录到以下目录:/var/mqm/errors

错误(如果有的话)将记录到文件AMQERR01.LOG中(它将与另外两个以0203结尾的文件一起轮换。如果错误是MQ所不希望的,它也可能会创建一个以结尾的文件.FDC以及其他详细信息。



如果在客户端发送通道名称之前进行通道协商期间连接失败,则队列管理器将记录通道名称???。如果IBM MQ队列管理器正在使用v7.5或更低版本,则直到TLS握手完成后才交换通道名称。

在v8和更高版本的客户端连接到v8和更高版本的队列管理器的情况下,MQ将在TLS协商期间使用TLS SNI交换通道名称,但是我不确定MQ是否也得到了增强,可以记录此通道名称,在以前的版本中它记录的。请注意,即使在v8及更高版本上,Java的IBM MQ类和JMS客户端的IBM MQ类也不支持SNI功能,并且在TLS握手完成之后才发送通道名称。



检查您的客户端???是否具有私钥。 MQ使用三种方式来标识要使用的私钥。


在MQ Client v7.5和更早版本中,私钥的标签必须为:

ibmwebspheremq<user_that_runs_the_php_process>

使用MQ客户端v7.5和更早版本,替代方法是将私钥设置为默认证书,并确保在执行程序的环境中设置了以下环境变量。请注意,这也适用于8.0.0.7/9.0.0.1,但与之相比,我更喜欢下一种方法。

 AMQ_SSL_ALLOW_DEFAULT_CERT=1

在MQ Client v8和更高版本中,可以在key.kdbCertificateLabel=anylabelvalue节中使用SSL。下面的例子:

SSL:
    CertificateLabel=anylabelvalue


mqclient.ini设置记录在IBM MQ v8 KC页面“ SSL stanza of the client configuration file”中。

可以从CertificateLabel复制mqclient.ini的模板,并将其放在应用程序执行所在的目录中。也可以通过环境变量指定该位置,如果未设置该变量并且在应用程序执行的同一目录中找不到该变量,则MQ会在文件的其他几个位置中查找。 MQ查找该文件的各种方式记录在IBM MQ v8 KC页面“ Location of the client configuration file”中

关于php - 如何在PHP中使用SSL认证连接到WebSphere MQ队列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46084567/

相关文章:

javascript - 从 javascript 设置按钮 id

android - 为证书固定存储公钥有多安全?

ruby-on-rails - Heroku 控制台中的预期 (200) <=> 实际 (401 未经授权)

Java不接受同名的2个方法

java - MQDestination 覆盖记帐 token 值

ibm-mq - 通过 MQ Explorer 连接容器中的远程队列管理器

java - WebSphere MQ 中的消息组

php - iPhone - 将图像上传到服务器时如何显示进度条?

java - 我怎样才能检测到mysql的变化?

php - 用给定的索引替换 php 数组中的值