PHP Mysql与OpenSSL
前段时间开了没有SSL的FTP端口, 不到两天就中勒索病毒, 现在对于网络传输安全也开始重视起来. 这几天在折腾 PHP
的一些功能, 需要连接本地 MySQL
服务, 于是尝试使用 SSL
加密, 在这里记录一下踩到的坑.
生成自签名的证书
据说 Mysql
可以使用 mysql_ssl_rsa_setup
生成证书, 但是我已经切换到了 mariadb
, 并没有看到这个功能, 所以只能自己用 openssl
生成.
网上有很多方法是先生成数字证书, 然后分别生成服务端和客户端的密钥和数字证书, 但是这个方法我用了提示证书错误. 下面这个方法生成的证书是可以使用的:
1 | $ openssl req -x509 -newkey rsa:1024 -days 3650 -keyout server-key-enc.pem -out server-cert.pem -subj '/DC=com/DC=example/CN=server' -passout pass:qwerty |
关键在于 ca.pem
是最后由两个文件合成的, 原因据说是需要提供双向的验证. 注意这里我们使用的都是本地的 IP
进行连接, 所以需要跳过域名的验证. 然后把证书移动到一个合适的存储位置.
把证书的位置写入配置文件
然后编辑配置文件 my.cnf
, 这个文件往往位于某个 /etc
文件夹中, 加入以下内容:
1 | [mysqld] |
进入 Mysql
的命令行, 输入 show variables like '%ssl%';
查看当前状态
1 | MariaDB [(none)]> show variables like '%ssl%'; |
可以看到 have_openssl
和 have_ssl
都是 YES
, 表示当前配置支持 SSL
, 否则还要考虑将 openssl
作为扩展使用 phpize
加入(有空了再写).
配置好了之后重启 Mysql
服务, 命令可能是 service restart mysql
, 可能是 brew services restart mysql
, 根据自己的配置来确定. 重启之后用相同的命令应该可以看到如上述的输出, 此时 Mysql
仍然可以不使用 SSL
登录. 我们创建一个强制使用 SSL
的账户, 并配置访问的权限:
1 | GRANT ALL PRIVILEGES ON *.* TO 'ssluser'@'localhost' IDENTIFIED BY 'password' require ssl; |
使用以下命令登录:
1 | mariadb --ssl-ca=/usr/local/cert/ca.pem --ssl-cert=/usr/local/cert/client-cert.pem --ssl-key=/usr/local/cert/client-key.pem -u ssluser -p |
需要输入密码, 这里也可以直接在命令中填充密码, 但是 -p
和密码之间不能有空格. 使用 status
查看当前连接的状态, 确认 SSL
已经启用. 其实在这里不指定客户端的证书也是可以登录的, 但是只是使用 SSL
加密链接, 并不对身份加以验证.
使用 Navicat
连接时, 在 SSL
界面勾选启用, 并设置证书的位置, 但是不用勾选 验证CA的服务器证书
, 不然会报错.
PHP中使用SSL
为了源码泄露导致密码被窃取, 这里可以把密码等敏感信息放在网站的根目录之外的文件, 使用时 include
进来. 注意这里的 $servername
一定不能写 localhost
, 不然会在连接时报如下错误:
1 | Warning: mysqli_real_connect(): This stream does not support SSL/crypto in /html/sql-ssl.php on line 10 |
很多人说这是 openssl
没有配置好需要重新加入 openssl
扩展, 但是查看 phpinfo
可以看到明明 openssl
已经在编译时就加入了, 即使费劲心思把它作为 .so
加载进来也会报重复引入的警告. 折腾了两天, 终于找到一个回帖, 说问题的关键如下:
当你连接到
localhost
时mysql_connect(“localhost”,…)
如果这样的链接可用,则通信通过本地套接字转换
mysql_connect(): [2002] (trying to connect via unix:/// (…)
实际上,这样的链接“不支持SSL /加密”(加密本地通信信道没有意义) .
要绕过此优化并强制通过TCP/IP
进行通信,请连接到127.0.0.1
.
特别鸣谢这个链接, 虽然我觉得这是英文翻译过来的, 但我确实找不到原贴.
使用以下代码建立连接:
1 |
|
就可以连上啦!
phpize
添加 openssl
扩展
PHP
添加扩展的只要方式有两种, 一种是 PECL
, 一种是 phpize
. 在能使用 pecl
时尽量使用, 可以减少好多奇怪的问题. 这里就来讲讲添加扩展的方式.
这里选用 openssl
是因为这玩意没法用 pecl
安装, 网上的教程也比较奇怪. 首先进入 php/include/php/ext
查看有没有 openssl
文件夹, 这里文件夹存在并不代表已经作为扩展加入, 因为这里只是些配置文件. 如果没有, 去 PHP
官网下载同版本的安装包, 里面有对应的文件夹拷贝过来. 把 config0.m4
重命名为 config.m4
, 然后在此目录下运行以下指令:
1 | $ /opt/homebrew/Cellar/php/8.2.8/bin/phpize |
如果没有安装 pkg-config
需要执行 brew install pkg-config
. 如果提示找不到 openssl
的文件可以尝试指定目录或者在 /usr/local
进行一次标准的安装. 说实话这么重要的库我建议还是不要用 HomeBrew
安装, 因为它对头文件的支持实在是太差了.
安装完后会自动把 openssl.so
拷贝到 pecl
文件夹. 使用 php --ini
查看配置文件位置, 打开 php.ini
文件取消 extension=openssl
的注释或者加入 extension="openssl.so"
. 执行 php -m | grep openssl
, 有输出则已经启动扩展.