PHP项目在本地开发时,很多时候使用 http://localhost 就可以正常运行。但随着浏览器安全策略、登录系统、Cookie、安全接口以及第三方服务的要求越来越严格,开发环境也经常需要使用 HTTPS。
例如,一个网站在正式环境中使用 https://example.com,开发阶段如果始终使用普通 HTTP,就可能无法准确模拟生产环境中的 Cookie、安全上下文、HTTPS 跳转以及部分浏览器行为。涉及登录、支付流程、OAuth、WebAuthn、Service Worker 或某些第三方 API 时,本地 HTTPS 的价值会更加明显。
本地 HTTPS 和生产环境 HTTPS 的核心原理并没有区别:浏览器与服务器建立 TLS 加密连接,服务器向浏览器提供证书,浏览器验证证书是否可信、是否属于当前访问的域名,以及证书是否处于有效期。
区别在于,本地开发通常没有必要申请一张面向公网的商业证书。
最简单的方法是使用自签名证书。但自签名证书最大的问题不是“不能加密”,而是“浏览器不信任”。
也就是说,HTTPS 本身可能已经建立成功,但浏览器仍然会提示证书不受信任。因为证书不是由操作系统和浏览器信任的证书颁发机构签发的。
因此,本地开发实际上有两种常见方案。
一种是直接使用自签名证书,然后在测试时忽略信任警告;另一种是建立一个本地开发 CA,再让系统和浏览器信任这个 CA,由它为 localhost、myproject.test 等本地域名签发证书。
如果只是临时测试,第一种方法最简单。如果需要长期维护多个 PHP 项目,第二种方法通常更加舒服。
生成证书时,还有一个容易被老教程带偏的地方。
过去很多教程会告诉开发者把域名写进 Common Name,也就是 CN。例如生成一个 CN=localhost 的证书。
现在不能只依赖 CN。
现代浏览器主要根据证书中的 SAN,也就是 Subject Alternative Name,判断证书是否包含当前访问的域名。因此,如果你准备访问:
https://localhost
证书中应该包含 DNS:localhost。
如果本地项目使用:
https://project1.test
那么证书中应该包含 DNS:project1.test。
如果还需要通过 127.0.0.1 访问,则可以把它作为 IP 地址写进 SAN,例如 IP:127.0.0.1。
这也是很多本地 HTTPS 配置明明“证书加载成功”,浏览器却仍然报错的原因。
证书文件通常分成两部分:证书本身和私钥。
例如:
server.crt
保存的是公开证书,可以交给 Apache 或 Nginx 使用。
而:
server.key
保存的是私钥。
私钥必须严格保护,不能上传到网站目录、代码仓库或者公开文件服务器。一旦私钥泄露,攻击者就可能冒充对应的服务器。
Apache 配置 HTTPS 时,首先要确保 Apache 已经加载 SSL 模块。不同操作系统和安装方式的配置文件位置不同,因此不能简单规定所有环境都修改同一个 httpd.conf。
在启用了 SSL 模块以后,Apache 的 HTTPS 虚拟主机通常会包含类似这样的配置:
Listen 443
以及:
SSLEngine on
再指定证书和私钥:
SSLCertificateFile
SSLCertificateKeyFile
实际路径必须根据你的 PHP 开发环境调整。
如果使用 XAMPP、WAMP 或其他 Windows 集成环境,配置文件的位置与 Linux 上的 Apache 并不一样。不能直接复制网上针对 Ubuntu、CentOS 的路径。
Apache 的 HTTPS 配置完成以后,还需要配置虚拟主机。
这一步对于同时开发多个 PHP 网站尤其重要。
例如本地 hosts 文件中可以设置:
127.0.0.1 project1.test
127.0.0.1 project2.test
然后 Apache 根据浏览器发送过来的 Host 名称,把 project1.test 和 project2.test 分别指向不同的网站目录。
这时候访问:
https://project1.test
浏览器先通过 hosts 找到本机,然后把请求发送给 Apache。Apache 再根据域名选择对应的 HTTPS VirtualHost。
因此,本地 HTTPS 实际上涉及三个相互配合的部分:
hosts 负责“域名指向哪里”,证书负责“这个域名是否属于证书”,Apache 或 Nginx 则负责“这个域名对应哪个网站”。
任何一个环节出错,HTTPS 都可能无法正常工作。
Nginx 的逻辑也是类似的。
在 HTTPS 的 server 块中,一般需要指定 443 端口、开启 SSL,并分别指定证书和私钥。例如:
listen 443 ssl;
ssl_certificate
以及:
ssl_certificate_key
如果漏掉私钥配置,Nginx 通常无法正确加载 HTTPS 配置。
如果浏览器出现 NET::ERR_CERT_COMMON_NAME_INVALID 或类似的域名不匹配错误,首先不要怀疑 SSL 加密本身,而应该检查证书的 SAN 是否包含当前访问的域名。
例如你访问的是:
https://project1.test
但证书只包含:
DNS:localhost
那么证书即使完全有效,浏览器仍然会认为它不是给 project1.test 使用的。
另一个问题是证书信任。
自签名证书可以建立加密连接,但操作系统默认并不信任它。因此,长期使用本地 HTTPS 时,可以把自己的本地开发 CA 加入系统信任库,再使用这个 CA 为不同项目签发证书。
这种方法比给每一个项目都创建一个完全独立的自签名证书更加方便。
在 Windows 上,可以通过证书管理工具把本地 CA 导入“受信任的根证书颁发机构”。macOS 则可以通过钥匙串访问进行管理。
这里需要注意,证书导入问题通常与 UTF-8、GBK 这样的文本编码没有直接关系。更常见的问题是证书格式、证书链、导入位置以及系统信任范围不正确。
如果只是测试服务器是否能够响应 HTTPS,可以使用 curl。
例如:
curl -k https://localhost
这里的 -k 或 --insecure 会关闭客户端对证书信任的严格验证。
它适合测试“服务器有没有正常提供 HTTPS”,但不能证明证书配置已经完全正确。
如果希望测试证书本身,可以使用 OpenSSL 查看 TLS 握手和证书信息,例如:
openssl s_client -connect localhost:443 -servername localhost
这样可以观察服务器返回的证书以及 TLS 握手情况。
不过需要注意,curl 使用 -k 成功,只能说明 HTTPS 服务可能已经工作,并不能说明浏览器也会信任这个证书。
还有一个经常出现的问题,是把 Linux 的文件权限规则直接搬到 Windows。
在 Linux 服务器上,私钥设置为仅允许相关用户读取,是非常常见的安全措施,例如通过 chmod 限制访问权限。但 Windows 的 NTFS 权限机制不同,本地 XAMPP 或 WAMP 环境不能机械地执行所谓“600、644”标准。
真正需要关注的是:运行 Apache 或 Nginx 的账户必须能够读取私钥,而普通用户和其他不需要访问它的进程不应该拥有不必要的权限。
对于开发环境来说,最危险的操作之一,是把私钥放到网站 Web Root 下面。
例如网站目录是:
C:\xampp\htdocs\project
就不要把 server.key 放在可以被浏览器直接访问的位置。
因为一旦服务器配置错误,某些静态文件可能被直接下载。如果私钥泄露,问题就不再只是一个本地测试环境的证书警告。
另一个错误是直接把生产环境的私钥和证书复制到本地电脑。
本地开发环境应该和生产环境保持证书隔离。开发证书、开发 CA 和开发私钥应该单独管理。
生产环境则应该使用受浏览器和操作系统信任的 CA 签发的证书。现在并不意味着必须购买昂贵的商业 SSL 证书,很多网站可以使用受信任的免费证书服务,但必须按照生产环境的实际域名和证书管理方式进行部署。
至于 ngrok 之类的反向代理或隧道工具,则解决的是另外一个问题。
如果开发者需要让互联网上的测试人员访问自己电脑上的 PHP 项目,可以通过隧道服务把公网请求转发到本地服务器。这类工具通常还可以提供 HTTPS。
但如果只是自己在电脑上开发 PHP 网站,就没有必要为了 HTTPS 而把本地服务器暴露到公网。
本地 HTTPS 最实用的配置思路其实很简单:先确定本地开发域名,再配置 hosts,再生成包含正确 SAN 的开发证书,然后让 Apache 或 Nginx 在 443 端口加载证书,最后根据需要把开发 CA 加入系统信任库。
如果只需要临时测试,可以接受浏览器的证书警告,或者在命令行使用 curl -k 验证连接。
如果需要长期维护多个本地 PHP 网站,则更推荐使用本地开发 CA,为每个项目签发对应域名的证书。
这样配置以后,本地环境就可以比较接近生产环境的 HTTPS 行为。开发人员不仅能够测试网页是否能打开,还可以测试 Secure Cookie、HTTPS 重定向、混合内容、跨域请求以及其他依赖安全上下文的功能。
本地 HTTPS 的意义并不是给 localhost 增加一个漂亮的锁头图标,而是让开发环境提前暴露那些只有在 HTTPS 条件下才会出现的问题。把证书、域名、虚拟主机和信任链分别理解清楚,之后无论使用 Apache、Nginx、PHP 内置服务器还是反向代理,本地 HTTPS 配置都会容易很多。
PHP 开发环境中的 SSL 证书怎么配置?本地 HTTPS 测试入门
图片说明:示意图 图片来源:Public Domain(公有领域)
喜欢这篇报道?
使用下面的功能,方便以后继续阅读和分享 MNewsTV
关于文章收藏
收藏不需要注册帐号,收藏信息仅保存在当前浏览器中。
删除收藏请进入「我的收藏」进行管理。
捐助(Paypal): https://www.paypal.me/observeccp 订阅中国观察电报 Telegram : https://t.me/s/ObserveCCP