使用 SSL 与远程数据库的 PDO 连接;验证服务器证书时出现 FastCGI 错误

Posted

技术标签:

【中文标题】使用 SSL 与远程数据库的 PDO 连接;验证服务器证书时出现 FastCGI 错误【英文标题】:PDO connection to remote DB using SSL; FastCGI errors when verifying server cert 【发布时间】:2020-01-06 16:32:37 【问题描述】:

我有一个带有 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

(取自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

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

[client]
ssl-ca=/path/to/ca.pem
ssl-cert=/path/to/client-cert.pem
ssl-key=/path/to/client-key.pem

我可以使用以下命令从本地计算机创建 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',
    ]
);

很遗憾,如果我删除该行

PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => false,

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

… FastCGI: incomplete headers (0 bytes) received from server …

我的 php 错误日志中没有任何错误

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

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

【问题讨论】:

对于您的最后一个问题,对于自签名证书,您必须将其保留为 false,因为由于不涉及根 CA,因此永远无法验证证书。对于您所描述的单个连接,它应该是安全的,尽管解决问题的正确方法是由根 CA 签名的“真实”证书,它可以让您将该变量设置为 true。 你的服务器证书中的CN是什么?您可以检查它,例如openssl x509 -noout -subject -in server.pem. 【参考方案1】:

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

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

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

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

【讨论】:

谢谢,我可以试试。服务器是安全的,但不在同一个网络上,并且 MariaDB 用户使用建立连接的机器的特定 IP 设置(用户名@yyy.yyy.yyy.yyy)。为什么命令行访问对证书满意,但对 PDO 连接不满意? 由于命令行客户端使用 MySQL Connector/C,而 PDO 使用 php 流。 MySQL Connector/C 检查 CN、替代名称以及 IP 地址:github.com/MariaDB/mariadb-connector-c/blob/3.1/libmariadb/… 你说的是 MySQL 连接器,然后链接到 MariaDB 连接器,MariaDB 不是 MySQL,它只是与 MySQL 兼容。 也只是为了 100% 正确证书不存储 IP 地址、存储访问名称(通常称为主机名或主机地址)。如果证书包含 IP 地址,则 IP 地址是保存在主题备用名称中的主机名,使用其中的 IP 地址与我上面所说的完全相同。SAN 这些是有效的替代 CN 所以它仍然是主机名或主机地址,使用与机器交谈, 花了我一段时间才回过神来,但是将服务器证书上的公用名设置为 MySQL 服务器的 IP 确实解决了问题,并且允许我不再设置 PDO:: MYSQL_ATTR_SSL_VERIFY_SERVER_CERT 为假。感谢您的帮助:)【参考方案2】:

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

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

带有 mysqlnd 的 PDO 使用 PHP 流,它只检查 CN 字段,而不是主题备用名称字段。根据您的代码,您指定要连接的 IP 地址,但不是名称。

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

另见:

RFC 5280

PHP Bug 71845

【讨论】:

谢谢,那您是不是提示验证失败是因为IP与CN不匹配?使用主机 IP 作为服务器证书 CN 有帮助吗?由于命令行连接有效,我猜这不会执行相同的步骤.. 另外,从错误报告中 - 它几乎暗示将 MYSQL_ATTR_SSL_VERIFY_SERVER_CERT 变为 false 是一个正确的解决方案。了解这有多安全吗? 禁用服务器证书验证当然不太安全,因为您将无法检测到 MTM 攻击。如果您在私有/安全网络中,这可能没问题。根据php.net/manual/en/context.ssl.php,现在可以从 PHP 5.6.0 开始检查对等证书的 md5 或 sha1(首选)指纹,但我不知道 PDO 是否支持它。 PDO 连接不太安全,如果关闭服务器证书验证,则不是不安全的。正如 George 已经指出的,如果两台服务器都在同一个专用网络上,那么这不是一个真正的问题(除非系统出于某种原因具有非常严格的安全要求)。 如果您有自签名证书,则只需使用公用名中的服务器 IP 地址即可。 CN 通常用于全限定域名,但也可用于通配符域名或 IP 地址。l

以上是关于使用 SSL 与远程数据库的 PDO 连接;验证服务器证书时出现 FastCGI 错误的主要内容,如果未能解决你的问题,请参考以下文章

PHP PDO 使用 SSL 连接到 MS SQLServer Express

R RPostgreSQL 使用 SSL 连接到远程 Postgres 数据库

如何使用 PDO ssl 连接到 azure mysql 数据库

通过 SSL 上的 PHP PDO 连接到 MSSQL 服务器

通过 SSL 的 Spring Boot 远程 Mysql 连接

“连接被远程接口拒绝”使用 PDO 连接到 Firebird 3