简介
本指南面向在 DouPHP 上启用并加固 HTTPS 的部署人员,覆盖以下目标:
- 在 Apache/Nginx 上完成 SSL 证书安装与站点 HTTPS 化
- 通过项目内置的安全中间件启用 HSTS(HTTP 严格传输安全)
- 实现 HTTP 到 HTTPS 的重定向(推荐在反向代理/负载均衡层完成)
- 解决混合内容问题,确保所有资源均通过 HTTPS 加载
- 提供 SSL 证书自动续期的建议方案与常见问题排查
项目结构
DouPHP 将“安全响应头”能力集中在基础中间件中,三端(前台、后台、API)各自提供一个薄壳子类继承统一行为;HSTS 开关与参数由配置文件集中管理。根目录 .htaccess 负责 URL 重写与入口分发,不包含强制 HTTPS 规则(应交由反向代理或虚拟主机配置)。
graph TB
A["客户端"] --> B["Apache/Nginx<br/>SSL终止/重定向"]
B --> C[".htaccess<br/>URL重写与入口分发"]
C --> D["前端中间件栈<br/>SecurityHeadersMiddleware(前台/后台/API)"]
D --> E["业务控制器/路由"]
D --> F["响应头输出<br/>X-Content-Type-Options / X-Frame-Options / Referrer-Policy / Permissions-Policy / HSTS"]
核心组件
- 安全响应头中间件基类:统一下发基线安全头,并在满足条件时下发 HSTS
- 三端安全中间件薄壳:前台、后台、API 分别继承基类,保持行为一致
- 安全配置:集中定义可信代理、可信 Host、安全头策略(含 HSTS 开关、max_age、subdomains)、会话 Cookie 硬化等
- URL 重写与入口:.htaccess 负责将请求转发至各入口脚本(不含强制 HTTPS)
架构总览
下图展示了从浏览器访问到响应头下发的完整链路,以及 HSTS 的条件判断逻辑。
sequenceDiagram
participant U as "用户浏览器"
participant W as "Web服务器(Apache/Nginx)"
participant R as ".htaccess 重写"
participant M as "安全头中间件"
participant S as "业务处理"
U->>W : "HTTPS 请求"
W->>R : "进入应用重写规则"
R->>M : "命中路由后进入中间件"
M->>M : "读取配置 security.headers"
M->>M : "判断 isSecure() 且 hsts.enabled"
M-->>U : "返回响应 + 安全头(含可选 HSTS)"
M->>S : "继续处理业务"
S-->>U : "业务响应"
详细组件分析
HSTS 与安全响应头
- 触发条件:仅当当前请求为 HTTPS 且配置中 hsts.enabled 为真时才下发 Strict-Transport-Security
- 参数映射:
- max_age:以秒为单位,控制浏览器缓存 HSTS 策略的时间
- subdomains:开启后将 includeSubDomains 加入响应头,使子域也受 HSTS 保护
- 其他安全头:X-Content-Type-Options、X-Frame-Options、Referrer-Policy、Permissions-Policy 由同一中间件根据配置下发
flowchart TD
Start(["进入安全头中间件"]) --> ReadCfg["读取 security.headers"]
ReadCfg --> BaseHeaders{"是否配置基础安全头?"}
BaseHeaders --> |是| SendBase["发送基础安全头"]
BaseHeaders --> |否| CheckHSTS{"检查 HSTS 条件"}
SendBase --> CheckHSTS
CheckHSTS --> |isSecure 且 enabled| BuildHSTS["构建 HSTS 值(max-age, includeSubDomains)"]
BuildHSTS --> SendHSTS["发送 Strict-Transport-Security"]
CheckHSTS --> |不满足| Next["继续后续中间件/控制器"]
SendHSTS --> Next
Next --> End(["结束"])
三端安全中间件(前台/后台/API)
- 前台、后台、API 均提供 SecurityHeadersMiddleware 薄壳,继承统一基类,保证行为一致
- 该设计便于未来对某端单独扩展,同时复用公共逻辑
URL 重写与入口分发
- 根目录 .htaccess 负责静态资源放行、API/后台/前台入口重写
- 未包含强制 HTTPS 规则,建议在反向代理或虚拟主机层面实现
协议检测与辅助工具
- API 启动阶段会检测 HTTPS(支持直接 HTTPS 与 X-Forwarded-Proto),用于生成对外链接
- 通用重定向 helper 可用于业务内跳转(注意:全局强制 HTTPS 应在反向代理层实现)
依赖关系分析
- 中间件依赖配置:AbstractSecurityHeadersMiddleware 通过 Config 读取 security.headers
- 三端中间件继承基类,形成“薄壳+核心”的分层结构
- .htaccess 与中间件解耦:前者负责路由分发,后者负责响应头策略
classDiagram
class AbstractSecurityHeadersMiddleware {
+handle(next)
-sendHeaders(headers)
}
class Front_SecurityHeadersMiddleware
class Admin_SecurityHeadersMiddleware
class Api_SecurityHeadersMiddleware
class SecurityConfig {
+headers.hsts.enabled
+headers.hsts.max_age
+headers.hsts.subdomains
}
Front_SecurityHeadersMiddleware --> AbstractSecurityHeadersMiddleware : "继承"
Admin_SecurityHeadersMiddleware --> AbstractSecurityHeadersMiddleware : "继承"
Api_SecurityHeadersMiddleware --> AbstractSecurityHeadersMiddleware : "继承"
AbstractSecurityHeadersMiddleware --> SecurityConfig : "读取配置"
性能与兼容性考虑
- HSTS 仅在 HTTPS 且显式开启时下发,避免非 HTTPS 环境误发导致无法回退
- 基础安全头在管道最前置下发,减少后续处理的额外开销
- 若使用反向代理/负载均衡,请正确设置可信代理与 Host 白名单,避免 IP/Host 被伪造污染对外链接
故障排除指南
- 未收到 HSTS 头
- 确认当前请求为 HTTPS(可通过浏览器开发者工具查看请求协议)
- 检查 config/security.php 中 hsts.enabled 是否为真
- 确认中间件已执行(仅命中路由的请求才会经过中间件)
- 出现混合内容警告
- 确保所有资源(CSS/JS/图片/字体/视频)均通过 https:// 加载
- 第三方外链需替换为 HTTPS 或使用相对协议(//)但更推荐显式 https://
- 模板与主题中的硬编码 http:// 资源需统一修正
- 登录后仍提示不安全或 Cookie 丢失
- 检查会话 Cookie 的 secure 与 samesite 配置是否与部署模式匹配
- 若经反向代理,确保传递了正确的 X-Forwarded-Proto 与 Host
- 重定向循环
- 若同时在反向代理与应用层都做了强制 HTTPS,可能产生循环
- 建议只在反向代理层做强制跳转,应用层专注业务逻辑
结论
- 在 DouPHP 中启用 HSTS 只需在配置中打开开关并设置 max_age 与 subdomains,中间件会在 HTTPS 环境下自动下发
- 强制 HTTPS 与证书管理建议在反向代理/负载均衡层完成,应用层专注于安全头与业务逻辑
- 彻底消除混合内容的关键在于全站资源统一走 HTTPS,并在模板与第三方集成中保持一致
附录:服务器与自动续期配置要点
Apache 启用 HTTPS 与重定向
- 在虚拟主机中启用 mod_ssl,并指向证书与私钥路径
- 在 80 端口虚拟主机中添加 301 重定向到 https://yourdomain
- 如需隐藏敏感文件类型,可保留现有 .htaccess 中的 FilesMatch 规则
Nginx 启用 HTTPS 与重定向
- 在 server 块中监听 443,配置 ssl_certificate 与 ssl_certificate_key
- 在 80 端口 server 块中添加 return 301 https://$host$request_uri
- 建议启用现代 TLS 套件与 HSTS(若不在应用层下发,可在 Nginx 层下发)
HSTS 参数建议
- max_age:生产环境建议设置为至少 31536000(一年)
- subdomains:如确需保护子域,开启 includeSubDomains;否则谨慎开启
- 上线前先在测试环境验证,避免误开启导致回滚困难
混合内容解决方案清单
- 全站资源改为 https:// 绝对路径或同域相对路径
- 第三方 CDN 资源切换为 HTTPS 域名
- 模板中动态生成的 URL 基于当前协议或固定 https://
- 外部 iframe、WebSocket、AJAX 等全部使用 HTTPS
SSL 证书自动续期
- 使用 Let’s Encrypt 配合 certbot 或云厂商提供的自动续期服务
- 在反向代理层配置定时任务或系统服务,确保证书到期前自动更新并重载配置
- 续期后验证 HTTPS 与 HSTS 是否正常生效