PHP和SSL CA验证 - 操作系统独立

时间:2013-04-30 11:02:22

标签: php linux windows ssl ssl-certificate

这是一个简单的PHP脚本,它打开一个准备发送HTTP请求的SSL套接字:

$contextOptions = array();

$socketUrl = 'ssl://google.com:443';
$streamContext = stream_context_create($contextOptions);
$socket = stream_socket_client($socketUrl, $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $streamContext);

if (!$socket || $errno !== 0) {
    var_dump($socket, $errstr);
    exit;
}

var_dump($socket);
exit('Socket created.');

这项工作 - 我刚刚对其进行了测试 - 但没有针对受信任的CA商店进行验证。

我们可以修改该脚本以使用PHP SSL Context options

$contextOptions = array(
    'ssl' => array(
        'cafile' => 'C:\xampp\cacerts.pem',
        'CN_match' => '*.google.com',  // CN_match will only be checked if 'verify_peer' is set to TRUE.  See https://bugs.php.net/bug.php?id=47030.
        'verify_peer' => TRUE,
    )
);

$socketUrl = 'ssl://google.com:443';
$streamContext = stream_context_create($contextOptions);
$socket = stream_socket_client($socketUrl, $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $streamContext);

if (!$socket || $errno !== 0) {
    var_dump($socket, $errstr);
    exit;
}

var_dump($socket);
exit('Socket created.');
只要' cafile'存在且具有正确的CA然后此示例也有效...

...但是如果不对CA文件名/文件路径进行硬编码,我们怎么能这样做呢?我们正在尝试创建一些可以独立于OS验证SSL证书的内容,而无需为运行此脚本的每个服务器单独配置。

我知道Linux有一个CA目录,我们可以将其作为' capath'。 Windows怎么样?它在哪里存储其可信任的CA?我搜索过,遗憾的是这些似乎都在注册表中,所以我们无法从PHP访问它们吗?其他操作系统怎么样?

1 个答案:

答案 0 :(得分:13)

失败的战斗......

如果不在PHP 5.6之前手动设置"cafile""CN_match"上下文选项,则无法在PHP中进行安全加密传输。不幸的是,即使您 正确设置这些值,您的传输仍然很可能会失败,因为在验证主机名时,5.6之前的版本不会查询对等证书中日益流行的SAN(subjectAltName)扩展名。因此,通过PHP的内置流包装器进行“安全”加密在很大程度上是一种误称。使用旧版PHP的最安全的赌注(字面意思)是卷曲扩展。

关于Windows证书......

Windows使用自己的证书存储区,并以不同的格式从OpenSSL对其证书进行编码。相比之下,openssl应用程序使用开放的.PEM格式。 5.6之前的PHP版本无法以任何方式与Windows证书库进行交互。因此,使用内置流包装器功能以跨操作系统方式进行可靠和安全的加密是不可能的。

PHP 5.6是向前迈出的重要一步

  • 新的 openssl.cafile openssl.capath php.ini指令允许您全局分配证书位置,而无需在每个流上下文中设置它们

  • 默认情况下,所有加密流都会验证对等证书和主机名,如果未提供"CN_match"上下文选项,则会自动从URI解析主机名。

  • 流加密操作现在在验证主机名时检查对等证书SAN条目

  • 如果在流上下文中没有指定CA文件/路径 php.ini指令,PHP会自动回退到操作系统的证书库(在Windows中也是如此)。

举例来说,这就是你需要做的就是在PHP-5.6中安全地连接到github.com:

<?php
$socket = stream_socket_client("tls://github.com:443");

是。真的就是这样。没有关于上下文设置和验证参数的烦恼。在这方面,PHP现在的功能类似于浏览器。

有关该主题的更多阅读

这些PHP 5.6更改只是关于SSL / TLS改进的冰山一角。我们努力使5.6成为迄今为止加密通信方面最安全的PHP版本。

如果您想了解有关这些新功能的更多信息,可通过官方渠道获取大量信息

5.4 / 5.5

中关于SAN匹配的说明

我们 正在努力向至少向与5.4和5.5分支匹配的SAN向后移动,因为在没有此功能的情况下以任何有意义的方式(作为客户端)使用加密包装是极其困难的。虽然这种向后移植工作在很大程度上取决于我作为志愿者的空闲时间,但提出这个答案肯定会帮助它更快地发生:)