PHP零信任需每次请求实时验证身份与权限,禁用none算法、校验exp/nbf、动态比对scope,不依赖$_SESSION/$_COOKIE,敏感操作须二次验证,API网关与业务层双校验,mTLS需透传并验证书及吊销状态。

PHP 本身不提供零信任能力,零信任不是 session_start() 或 JWT::decode() 调用一次就自动生效的机制——它要求每个请求路径上都完成「实时身份验证 + 权限决策」,且不能跳过、不能缓存、不能依赖客户端传来的任意字段做判断。
每次请求都校验 JWT,而不是只在登录时校验
常见错误是:用户登录成功后生成一个 $token,前端存进 localStorage,后续所有请求都带这个 token,但服务端只在中间件里简单 JWT::decode($token, $key) 就放行。这漏掉了关键三要素:签名强校验、alg 白名单、scope 动态比对。
- 必须显式指定
algorithms=["RS256"],禁用none算法(否则攻击者可构造无签名 token) - 必须检查
exp和nbf,且用服务端时间(time()),不能信客户端传的iat - 必须从载荷中提取
scope或permissions字段,并与当前接口所需权限比对,例如read:orders接口不能接受仅有read:users的 token
不依赖 $_SESSION,也不信任 $_COOKIE 中的任意字段
传统 PHP 会话靠 PHPSESSID cookie 关联服务端 session 文件,但这违反零信任的「默认拒绝」原则:一旦 session ID 泄露或被重放,攻击者就能长期冒用。更危险的是把用户角色直接写进 cookie(如 role=admin),等于把权限控制权交给客户端。
- 禁止使用
$_COOKIE['role']或$_COOKIE['user_id']做权限判断 - 若必须用 session,只用于临时存储已通过 JWT/mTLS 验证后的上下文(如
$_SESSION['verified_device_id']),且 session 生命周期应极短(ini_set('session.gc_maxlifetime', 300)) - 所有敏感操作(如删除、导出、提权)必须二次验证:重新解析 JWT 并检查
acr(认证上下文类)是否 ≥ 2(即含 MFA)
API 网关层与业务层双校验,避免绕过中间件
很多项目把鉴权逻辑全塞进 Laravel 的 auth:api 中间件,但一旦某个路由用了 ->withoutMiddleware(),或控制器里直接调用 Auth::user(),整个链路就断了。零信任要求验证点紧贴实际数据访问入口。
立即学习“PHP免费学习笔记(深入)”;
- 数据库查询前必须校验:比如
User::find($id)之前,先确认当前 JWT 中的sub是否有权限读该$id(RBAC/ABAC 检查) - 文件下载接口不能只校验 token 有效,还要检查
scope是否含download:report,且文件路径必须白名单过滤(防../etc/passwd) - 使用
register_shutdown_function()做兜底:若请求生命周期内未调用任何权限校验函数,强制记录告警并返回 403
mTLS 场景下必须透传并验证客户端证书信息
当 PHP 服务部署在 Nginx 后且启用了 mTLS,Nginx 默认不会把客户端证书内容传给 PHP。若只靠 HTTP Header 做“伪 mTLS”,等于形同虚设。
- Nginx 配置中必须设置:
proxy_set_header SSL_CLIENT_CERT $ssl_client_cert; - PHP 中通过
$_SERVER['HTTP_SSL_CLIENT_CERT']获取原始 PEM,用openssl_x509_parse()解析 CN/O/OU,并与策略引擎比对(例如只允许O=Finance, OU=API-Client) - 证书吊销检查不可省:需调用 OCSP 或 CRL 端点(如
curl -s https://ocsp.example.com -d "$(openssl ocsp -issuer issuer.pem -cert client.pem -text)"),不能只看有效期
最易被忽略的一点:零信任不是加一层中间件就结束,而是要把「谁在什么设备、什么网络、什么行为模式下,想访问哪个资源」这些维度全部纳入每次请求的决策上下文——PHP 代码里没出现 device_fingerprint、geoip_country、behavior_risk_score 这类变量,大概率还没真正落地零信任。



















