文档目录
IP访问控制

简介

本指南面向在负载均衡或Nginx反向代理环境下部署DouPHP的运维与开发者,聚焦IP访问控制的两个关键能力:

  • 可信代理(trusted_proxies):决定何时信任X-Forwarded-*等转发头,从而正确识别真实客户端IP与协议。
  • 可信Host白名单(trusted_hosts):防止Host头注入污染对外URL(邮件、通知、跳转、缓存等)。

通过合理配置,可确保:

  • 日志、限流、风控基于真实用户IP;
  • 对外链接始终指向规范域名,避免钓鱼与缓存投毒;
  • HTTPS判定准确,避免混合内容与安全策略失效。

项目结构

与IP访问控制直接相关的代码集中在以下位置:

  • 安全配置入口:config/security.php
  • 请求对象与IP/Host处理:core/web/http/Request.php
  • 中间件幂等设置:core/foundation/middleware/TrustProxyMiddleware.php
  • 初始化阶段加载安全配置:core/init/InitTrait.php
graph TB
A["安全配置<br/>config/security.php"] --> B["初始化加载<br/>core/init/InitTrait.php"]
B --> C["可信代理设置<br/>core/web/http/Request.php::setTrustedProxies"]
B --> D["可信Host设置<br/>core/web/http/Request.php::setTrustedHosts"]
E["请求管道中间件<br/>TrustProxyMiddleware.php"] --> C
C --> F["ip() / isSecure()<br/>core/web/http/Request.php"]
D --> G["host() / url() / fullUrl()<br/>core/web/http/Request.php"]

图表来源

  • config/security.php:17-60
  • core/init/InitTrait.php:157-179
  • core/web/http/Request.php:876-913
  • core/foundation/middleware/TrustProxyMiddleware.php:24-45

章节来源

  • config/security.php:17-60
  • core/init/InitTrait.php:157-179
  • core/web/http/Request.php:876-913
  • core/foundation/middleware/TrustProxyMiddleware.php:24-45

核心组件

  • 安全配置(security.php)
    • trusted_proxies:可信反向代理名单(精确IP或CIDR),为空表示不信任任何代理。
    • trusted_hosts:可信Host白名单(精确域名或*.example.com子域通配),为空时不校验Host。
    • headers/throttle/session:其他安全相关项,与本指南主题相关度较低。
  • Request类
    • setTrustedProxies/setTrustedHosts:写入可信代理与可信Host。
    • ip()/isSecure():仅在请求来自可信代理时才采信X-Forwarded-For/X-Forwarded-Proto。
    • host()/url()/fullUrl():若Host未命中白名单,回落到白名单首项,防止Host头注入。
  • TrustProxyMiddleware
    • 在请求管道最前置幂等读取配置并设置可信代理,保证即使Init顺序异常也不漏设。
  • InitTrait
    • 在构造AuditService等需要ip()之前加载安全配置并设置可信代理,避免伪造XFF被提前采信。

章节来源

  • config/security.php:17-60
  • core/web/http/Request.php:835-1160
  • core/foundation/middleware/TrustProxyMiddleware.php:24-45
  • core/init/InitTrait.php:157-179

架构总览

可信代理与Host白名单的工作流程如下:

sequenceDiagram
participant Client as "客户端"
participant LB as "负载均衡/Nginx"
participant App as "DouPHP应用"
participant Init as "InitTrait"
participant Req as "Request"
participant MW as "TrustProxyMiddleware"
Client->>LB : HTTP 请求
LB->>App : 转发请求(可能带 X-Forwarded-*)
App->>Init : 启动并加载安全配置
Init->>Req : setTrustedProxies(trusted_proxies)
Init->>Req : setTrustedHosts(trusted_hosts)
App->>MW : 进入中间件管道
MW->>Req : 再次幂等设置可信代理
App->>Req : 业务调用 ip()/isSecure()/host()
Req-->>App : 返回受控后的值

图表来源

  • core/init/InitTrait.php:157-179
  • core/foundation/middleware/TrustProxyMiddleware.php:24-45
  • core/web/http/Request.php:876-913

详细组件分析

可信代理(trusted_proxies)工作原理

  • 默认不信任任何代理:当trusted_proxies为空时,Request::ip()仅使用REMOTE_ADDR,忽略X-Forwarded-For/HTTP_CLIENT_IP;isSecure()也不会采信X-Forwarded-Proto。
  • 启用条件:只有当REMOTE_ADDR命中可信代理名单(精确IP或CIDR)时,才会展开并解析X-Forwarded-For(取最左侧原始客户端)、HTTP_CLIENT_IP,并在isSecure()中采信X-Forwarded-Proto(多级逗号分隔时取最左段)。
  • CIDR匹配:支持如10.0.0.0/8、172.16.0.0/12等网段匹配,内部按位掩码计算实现。
flowchart TD
Start(["进入 Request::ip()"]) --> CheckProxies{"是否配置了可信代理?"}
CheckProxies -- "否" --> UseRemote["仅使用 REMOTE_ADDR"]
CheckProxies -- "是" --> FromProxy{"REMOTE_ADDR 是否命中可信代理?"}
FromProxy -- "否" --> UseRemote
FromProxy -- "是" --> Collect["收集候选IP:<br/>X-Forwarded-For(拆分逗号)<br/>HTTP_CLIENT_IP<br/>REMOTE_ADDR"]
Collect --> Select["优先IPv4(含映射),再IPv6,兜底首段"]
Select --> End(["返回客户端IP"])
UseRemote --> End

图表来源

  • core/web/http/Request.php:835-874
  • core/web/http/Request.php:970-1022
  • core/web/http/Request.php:1024-1063

章节来源

  • core/web/http/Request.php:835-874
  • core/web/http/Request.php:970-1022
  • core/web/http/Request.php:1024-1063

Host白名单(trusted_hosts)与防Host头注入

  • 作用:当trusted_hosts非空时,Request::host()会校验HTTP_HOST是否命中白名单(支持精确域名与*.example.com子域通配)。未命中则回落到白名单首项,确保对外URL始终指向规范域名。
  • 影响范围:host()、url()、fullUrl()均受此保护,避免邮件链接、跳转、缓存键等被恶意Host头污染。
  • 兼容性:若trusted_hosts为空,保持原样返回HTTP_HOST,不影响未配置的既有站点。
flowchart TD
HStart(["进入 Request::host()"]) --> LoadList["加载 trusted_hosts 白名单"]
LoadList --> Allowed{"HTTP_HOST 是否命中白名单?"}
Allowed -- "是" --> ReturnHost["返回原始 Host"]
Allowed -- "否" --> Fallback["回落到白名单首项"]
Fallback --> ReturnFallback["返回规范域名"]
ReturnHost --> HEnd(["结束"])
ReturnFallback --> HEnd

图表来源

  • core/web/http/Request.php:915-967
  • core/web/http/Request.php:1145-1178

章节来源

  • core/web/http/Request.php:915-967
  • core/web/http/Request.php:1145-1178

初始化与中间件的协作

  • InitTrait在构造审计服务(会调用request()->ip())之前加载安全配置并设置可信代理,避免伪造XFF被提前采信。
  • TrustProxyMiddleware在请求管道最前置再次幂等设置可信代理,保证即使Init顺序异常也不漏设。
sequenceDiagram
participant Boot as "应用启动"
participant IT as "InitTrait"
participant AS as "审计服务(需ip)"
participant MW as "TrustProxyMiddleware"
participant RQ as "Request"
Boot->>IT : loadSecurityConfig()
IT->>RQ : setTrustedProxies(...)
IT->>AS : 构造并调用 ip()
Boot->>MW : 进入中间件管道
MW->>RQ : 再次 setTrustedProxies(...)

图表来源

  • core/init/InitTrait.php:157-179
  • core/foundation/middleware/TrustProxyMiddleware.php:24-45

章节来源

  • core/init/InitTrait.php:157-179
  • core/foundation/middleware/TrustProxyMiddleware.php:24-45

依赖关系分析

  • 配置到运行时:
    • config/security.php提供trusted_proxies与trusted_hosts。
    • InitTrait在早期加载该配置并写入Request。
    • TrustProxyMiddleware在管道层再次设置,形成双重保障。
  • 运行时行为:
    • Request::ip()/isSecure()依赖可信代理判定决定是否采信X-Forwarded-*。
    • Request::host()/url()/fullUrl()依赖trusted_hosts进行Host校验与回落。
graph LR
CFG["config/security.php"] --> INIT["InitTrait.loadSecurityConfig"]
INIT --> REQ["Request.setTrustedProxies/Hosts"]
MW["TrustProxyMiddleware"] --> REQ
REQ --> IP["Request.ip()"]
REQ --> SEC["Request.isSecure()"]
REQ --> HOST["Request.host()/url()/fullUrl()"]

图表来源

  • config/security.php:17-60
  • core/init/InitTrait.php:157-179
  • core/foundation/middleware/TrustProxyMiddleware.php:24-45
  • core/web/http/Request.php:876-913
  • core/web/http/Request.php:835-874
  • core/web/http/Request.php:1112-1133
  • core/web/http/Request.php:1145-1178

章节来源

  • config/security.php:17-60
  • core/init/InitTrait.php:157-179
  • core/foundation/middleware/TrustProxyMiddleware.php:24-45
  • core/web/http/Request.php:835-874
  • core/web/http/Request.php:1112-1133
  • core/web/http/Request.php:1145-1178

性能与行为特性

  • 默认安全:未配置trusted_proxies时,完全忽略X-Forwarded-*,避免误判与攻击面扩大。
  • 最小开销:仅在REMOTE_ADDR命中可信代理后才解析转发头;CIDR匹配为位运算,成本极低。
  • 惰性加载:trusted_hosts首次使用时从配置文件惰性载入,减少无关启动开销。
  • 幂等设置:中间件层再次设置,避免重复配置风险。

故障排查指南

  • 现象:日志中的客户端IP均为代理出口IP或全为同一地址
    • 检查:是否在trusted_proxies中配置了负载均衡/Nginx出口IP或网段。
    • 验证:确认REMOTE_ADDR确实来自可信代理;否则Request不会展开X-Forwarded-For。
    • 参考:可信代理判定与XFF展开逻辑。
  • 现象:HTTPS页面出现“不安全内容”警告或重定向循环
    • 检查:是否配置了trusted_proxies以允许X-Forwarded-Proto;并确保代理正确设置该头。
    • 验证:isSecure()仅在可信代理下采信X-Forwarded-Proto。
  • 现象:邮件/通知中的链接指向错误域名
    • 检查:是否配置trusted_hosts白名单;未命中时会回落到首项。
    • 建议:将主域名与常用子域加入白名单,避免Host头注入。
  • 现象:本地开发无法获取真实IP
    • 检查:本地直连场景通常不应信任外部代理;保持trusted_proxies为空即可。
    • 如需模拟:可在开发环境临时添加本地代理出口,但生产务必收紧。

章节来源

  • core/web/http/Request.php:835-874
  • core/web/http/Request.php:1112-1133
  • core/web/http/Request.php:1145-1178

结论

通过配置trusted_proxies与trusted_hosts,DouPHP能够在代理环境中准确识别真实客户端IP与协议,同时防止Host头注入对对外URL的影响。建议在所有生产环境启用这两项配置,并结合负载均衡/Nginx的正确转发头设置,以获得一致且安全的运行效果。

附录:配置示例与最佳实践

trusted_proxies配置格式

  • 单个IP:例如“192.168.1.10”
  • CIDR网段:例如“10.0.0.0/8”、“172.16.0.0/12”
  • 多个条目:数组形式列出,如["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]
  • 注意:
    • 未配置或为空时,不信任任何代理,仅使用REMOTE_ADDR。
    • 仅当REMOTE_ADDR命中可信代理时,才会采信X-Forwarded-For与X-Forwarded-Proto。

章节来源

  • config/security.php:24-30
  • config/security.php:51-60
  • core/web/http/Request.php:876-895
  • core/web/http/Request.php:991-1022

trusted_hosts白名单配置示例

  • 精确域名:例如“www.example.com”、“example.com”
  • 子域通配符:例如“*.example.com”
  • 多域名:数组形式列出,如["www.example.com", "example.com", "*.example.com"]
  • 行为:
    • 非空时,未命中的Host会回落到白名单首项,防止Host头注入。
    • 为空时保持兼容,不校验Host。

章节来源

  • config/security.php:28-30
  • config/security.php:56-60
  • core/web/http/Request.php:915-967
  • core/web/http/Request.php:1145-1178

负载均衡与Nginx反向代理环境下的正确配置

  • 负载均衡/CDN:
    • 将负载均衡或CDN出口IP或网段加入trusted_proxies。
    • 确保代理正确设置X-Forwarded-For(客户端IP在最左)与X-Forwarded-Proto(https/http)。
  • Nginx反代:
    • 在proxy_pass前设置proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    • 设置proxy_set_header X-Forwarded-Proto $scheme;
    • 将Nginx所在服务器IP或网段加入trusted_proxies。
  • 多级代理:
    • X-Forwarded-For为逗号分隔列表,系统取最左侧作为原始客户端;请确保每级代理追加而非覆盖。

章节来源

  • core/web/http/Request.php:1024-1063
  • core/web/http/Request.php:1112-1133

常见网络拓扑下的最佳实践

  • 单节点直连:
    • 保持trusted_proxies为空,避免误信外部XFF。
    • 若确有需要(如本地调试代理),谨慎添加并限制范围。
  • 云托管(ALB/SLB + Web集群):
    • 将ALB/SLB出口网段加入trusted_proxies。
    • 配置trusted_hosts为主域名与常用子域。
  • CDN + WAF:
    • 将CDN/WAF出口网段加入trusted_proxies。
    • 确保CDN透传X-Forwarded-For与X-Forwarded-Proto。
  • 多环境隔离:
    • 开发/测试/生产分别维护不同trusted_proxies与trusted_hosts,避免跨环境误用。
添加日期:2026-10-05