案例:我想打开SSL连接,localhost
而SSL证书是FQDN的问题.
问题:如果没有特殊处理,(*)
下面的程序将失败并显示以下消息:
PHP Warning: stream_socket_enable_crypto(): Peer certificate CN='myhost.com' did not match expected CN='localhost' in test.php
测试PHP程序:
$fp = stream_socket_client("tcp://localhost:993", $errno, $errstr, 30);
// (*) if commented, the program fails
//stream_context_set_option($fp, 'ssl', 'verify_peer_name', false);
if (!$fp) {
die("Unable to connect: $errstr ($errno)");
}
if (!stream_socket_enable_crypto($fp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
die("Failed to start SSL");
}
fwrite($fp, "USER god\r\n");
fwrite($fp, "PASS secret\r\n");
while ($motd = fgets($fp)) {
echo $motd;
}
fclose($fp);
Run Code Online (Sandbox Code Playgroud)
由于我有很多遗留代码,我希望通过仅对php.ini
(或CLI)应用更改来获得解决方案,但遗憾的是,以下两种方法都不起作用:
php -d verify_peer_name=false test.php
php -d ssl.verify_peer_name=false test.php
想法?
参考文献:
β.ε*_*.βε 12
何时cafile
和capath
同时是运行时配置和SSL上下文选项,verify_peer_name
并且verify_peer
只是SSL上下文选项.
因此,后来的两个不能通过运行时配置指令进行修改.
我可以理解这里复制的文档中的混淆,但这两段实际上是指PHP中的两个不同的概念.
通过设置openssl.cafile或openssl.capath配置设置,或者通过使用cafile或capath上下文选项基于每个请求,可以在全局基础上覆盖默认CA捆绑包.
虽然一般不推荐,但可以通过将verify_peer context选项设置为FALSE来禁用请求的对等证书验证,并通过将verify_peer_name context选项设置为FALSE来禁用对等名称验证.
首先要注意的是,文件本身就是一个明显的区别openssl.cafile
,并openssl.capath
成为在全球范围内或在每个请求的基础上对verify_peer
和verify_peer_name
是一个要求而已.
因此,这基本上意味着,何时openssl.cafile
,openssl.capath
可以通过php.ini
或通过适应stream_context_set_option
,另一方面verify_peer
,verify_peer_name
只能通过stream_context_set_option
.
PHP源代码本身也证实了这一点,下面是一些显示PHP
底层C
语言php_stream_context_get_option
仅从中获取值的行.
must_verify_peer_name = GET_VER_OPT("verify_peer_name")
? zend_is_true(val)
: sslsock->is_client;
Run Code Online (Sandbox Code Playgroud)
为清楚起见,这里是宏的声明 GET_VER_OPT
#define GET_VER_OPT(name) (PHP_STREAM_CONTEXT(stream) && (val = php_stream_context_get_option(PHP_STREAM_CONTEXT(stream), "ssl", name)) != NULL)
Run Code Online (Sandbox Code Playgroud)
当cafile
和capath
第一次匹配php_stream_context_get_option
值时,然后,如果它们NULL
在上下文中,则它们将在ini配置中获取.
GET_VER_OPT_STRING("cafile", cafile);
GET_VER_OPT_STRING("capath", capath);
if (cafile == NULL) {
cafile = zend_ini_string("openssl.cafile", sizeof("openssl.cafile")-1, 0);
cafile = strlen(cafile) ? cafile : NULL;
}
Run Code Online (Sandbox Code Playgroud)
然后在完全相同的功能中稍低一点:
if (capath == NULL) {
capath = zend_ini_string("openssl.capath", sizeof("openssl.capath")-1, 0);
capath = strlen(capath) ? capath : NULL;
}
Run Code Online (Sandbox Code Playgroud)
为清楚起见,这里是宏的声明 GET_VER_OPT_STRING
#define GET_VER_OPT_STRING(name, str) if (GET_VER_OPT(name)) { convert_to_string_ex(val); str = Z_STRVAL_P(val); }
Run Code Online (Sandbox Code Playgroud)
您还可以看到的是,当这两个值openssl.capth
和openssl.cafile
被定义为现有的ini
配置,后来verify_peer
和verify_peer_name
是无处可寻.
令人遗憾的是,正如文档提示的那样,唯一的方法就是为请求配置它 stream_context_set_option ( $stream_or_context , 'ssl' , 'verify_peer_name' , false )
另请注意:根据文档的提示,PHP版本5.6.0中更改了这两个SSL上下文选项的默认值:
5.6.0添加了peer_fingerprint和verify_peer_name.verify_peer默认更改为TRUE.
这意味着这样的问题可以在升级PHP之后出现PHP < 5.6.0
,即使我不建议,因为PHP
即将到来的是支持生命周期,这两个选项的默认值可以通过坚持到5.6.0
低于的版本5.*.*
.