使用SSL与远程DB的PDO连接;验证服务器证书时的FastCGI错误

Art*_*rth 6 php mysql ssl pdo mariadb

我有一台带有MariaDB数据库的远程服务器,该服务器仅接受特定用户的SSL连接,并使用以下命令生成了一些自签名SSL证书

# Create CA certificate
openssl genrsa 2048 > ca-key.pem
openssl req -new -x509 -nodes -days 3600 -key ca-key.pem -out ca.pem

# Create server certificate, remove passphrase, and sign it
# server-cert.pem = public key, server-key.pem = private key
openssl req -newkey rsa:2048 -days 3600 
        -nodes -keyout server-key.pem -out server-req.pem
openssl rsa -in server-key.pem -out server-key.pem
openssl x509 -req -in server-req.pem -days 3600 \
        -CA ca.pem -CAkey ca-key.pem -set_serial 01 -out server-cert.pem

# Create client certificate, remove passphrase, and sign it
# client-cert.pem = public key, client-key.pem = private key
openssl req -newkey rsa:2048 -days 3600 \
        -nodes -keyout client-key.pem -out client-req.pem
openssl rsa -in client-key.pem -out client-key.pem
openssl x509 -req -in client-req.pem -days 3600 \
        -CA ca.pem -CAkey ca-key.pem -set_serial 01 -out client-cert.pem
Run Code Online (Sandbox Code Playgroud)

(摘自https://dev.mysql.com/doc/refman/5.6/en/creating-ssl-files-using-openssl.html

我为每个证书填写了以下详细信息

  • 国家名称:GB
  • 地区名称:公司镇
  • 机构名称:公司名称
  • 通用名称:DEV CA,DEV Server,DEV Client (分别)

并将所有其他字段留空


远程服务器具有以下内容 my.cnf

[mariadb]
ssl-ca=/path/to/ca.pem
ssl-cert=/path/to/server-cert.pem
ssl-key=/path/to/server-key.pem
Run Code Online (Sandbox Code Playgroud)

我可以通过在本地计算机的命令行中包含以下内容来进行连接 my.cnf

[client]
ssl-ca=/path/to/ca.pem
ssl-cert=/path/to/client-cert.pem
ssl-key=/path/to/client-key.pem
Run Code Online (Sandbox Code Playgroud)

我可以使用以下方法从本地计算机创建PDO连接

$pdo = new PDO(
    'mysql:host=xxx.xxx.xxx.xxx;dbname=database_1',
    'database_user',
    'database_password',
    [
       PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => false,
       PDO::MYSQL_ATTR_SSL_KEY => '/path/to/client-key.pem',
       PDO::MYSQL_ATTR_SSL_CERT => '/path/to/client-cert.pem',
       PDO::MYSQL_ATTR_SSL_CA => '/path/to/ca.pem',
    ]
);
Run Code Online (Sandbox Code Playgroud)

不幸的是,如果我删除线

PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => false,
Run Code Online (Sandbox Code Playgroud)

我收到内部服务器错误,并且在MAMP PRO apache错误日志中显示以下内容

… FastCGI: incomplete headers (0 bytes) received from server …
Run Code Online (Sandbox Code Playgroud)

我的PHP错误日志中没有错误

我只能假设证书验证出了点问题,

  • 我错过了什么吗? 和/或
  • PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT设置为false是否安全?

Geo*_*ter 9

当客户端验证服务器证书时,将检查以下内容

  • 签名
  • 证书有效期包括当前时间
  • 证书未吊销(CRL的一部分)
  • 主机名匹配CN或备用名称
  • 根ca

带有mysqlnd的PDO使用PHP流,该流仅检查CN字段,而不检查Subject Alternative Names字段。根据您的代码,您指定要连接的IP地址,而不是名称。

不幸的是,PHP也没有提供其他方法来检查对等证书的指纹。

也可以看看:

  • 当然,禁用服务器证书验证的安全性较差,因为您将无法检测到MTM攻击。如果您在专用/安全网络中,则可以。根据https://www.php.net/manual/zh/context.ssl.php,从PHP 5.6.0开始,现在可以检查对等证书的md5或sha1(首选)指纹,但是我不知道还不知道PDO是否支持。 (2认同)

Bar*_*n01 1

将 PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT 设置为 false 是否安全?

在大多数情况下,如果对服务器的访问是安全的,那么这样做是安全的,尽管不建议这么做。

失败的原因是 TLS(SSL) 证书被授予主机访问地址,其中主机访问地址是 IP 地址或主机名,而不是物理主机。因此,您的通用名称应该是服务器的 IP 地址或主机名;无论使用哪个,您都必须使用它来连接到服务器。

因此,当您连接到主机 xxx.xxx.xxx.xxx(来自'mysql:host=xxx.xxx.xxx.xxx;dbname=database_1')时,证书上的公用名需要为 xxx.xxx.xxx.xxx