PHP stream_socket_client无法连接

时间:2015-10-13 20:17:43

标签: php ssl curl

我试图通过php的stream_socket_client()命令联系网址,该命令失败,没有错误代码或消息。这是使用openssl,curl还是别的什么?该网站使用https,并在网络浏览器中正常工作。

enter image description here

当我直接调用openssl时,它会连接但我的证书链显得不那么好。

root@drupal7 drupal7/includes# openssl s_client -connect test.cgps.org:443
CONNECTED(00000003)
Verify return code: 21 (unable to verify the first certificate)

与curl相同

curl https://test.cgps.org/?q=/admin/config/search/clean-urls/check
curl: (60) SSL certificate problem: unable to get local issuer certificate

所以我认为我需要将中间证书安装到Linux中,我将Apache使用的相同中间证书放入/ usr / local / share / ca-certificates并运行update-ca-certificates。

root@drupal7 drupal7/includes# update-ca-certificates
Updating certificates in /etc/ssl/certs... 1 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d....done.

仍然没有运气......

1 个答案:

答案 0 :(得分:0)

尽管在评论中发表声明称PHP的steam_socket_client()太低而无法关注证书,但我知道 关心,因为我观察过它在标准位置缺少某些证书的系统上返回false,其中提供流上下文(告诉它在哪里查找证书)会阻止这种情况发生。

令人沮丧的是,$errno可以保持为0,直到您修复此问题为止,因此最好先使用其他工具检查您的证书颁发机构目录。

诊断

通过curl

为了使curl工作正常,你通常可以通过添加--verbose标志来弄清楚发生了什么。这应该告诉您正在使用哪个连接的证书(CAfile / cacert)和CA目录(capath)的PEM文件(如果有)。在输出的顶部,你会得到类似的东西:

[...]
* successfully set certificate verify locations:
*   CAfile: /etc/pki/tls/certs/ca-bundle.crt
  CApath: /home2/wynddorg/private_html/trusted_roots
[...]

一旦您知道这些是默认值,您可以调整系统配置,也可以只添加--cacert <concatenated_cert_path>标记或--capath <c_rehash'd_directory>或两者。

通过openssl s_client

使用s_client有点棘手;您可以访问其-trace选项,具体取决于您的版本以及编译方式,但请尝试:

strace -e open,stat openssl s_client -connect test.cgps.org:443 [-CApath <dir>]
# this trick provided by the amazing xemdetia in irc://freenode/%23%23openssl

CONNECTED(00000003)消息后大约5行,您应该看到open("...", O_RDONLY)(或几个),它们应该显示哪些位置用于查找证书。

我缺少一个或多个证书。现在怎么办?

一旦您知道缺少哪些证书,您可以下载它们as shown here,然后执行任何操作:

  • 将它们连接到PEM文件(最好是in order),然后在尝试连接到您的网站时指定该文件
  • 将它们保存为默认目录中的单个“.crt”文件,然后在该目录上运行c_rehash(可能需要root / sudo)
  • 将它们保存为另一个目录中的单个“.crt”文件,并在连接时明确指定为capath。您可能希望在共享主机上执行此操作,或者如果您不希望所有应用程序都信任证书,只需要信任某些证书。

使用openssl s_clientcurl或两者后,您可以指定相同的选项:

$context = stream_context_create();
stream_context_set_option($context, 'ssl', 'cafile', <concatenated_cert_file_path>);
stream_context_set_option($context, 'ssl', 'capath', <c_rehashed_cert_dir_path>);
// You only really need to provide one of the two options above. Using capath is
// faster, but this only matters if you'll be making a huge number of
// connections.
$ssc = stream_socket_client(
    'ssl://subdomain.example.com:443',
    $errno,
    $errstr,
    30,
    STREAM_CLIENT_CONNECT,
    $context
);
if ($ssc) { /* ... */  }