Nginx带过期时间的IP绑定Secure Link返回403问题求助
解决Nginx Secure Link绑定IP后返回403的问题
核心问题定位
403错误本质是Nginx端生成的校验串与PHP生成的签名不匹配,根源大概率出在IP获取不一致、URI编码差异或代理环境下的IP传递错误上。
分步解决方案
1. 确保Nginx与PHP获取的IP完全一致
如果服务器使用CDN、反向代理(如Cloudflare、自建Nginx代理),Nginx的$remote_addr会是代理服务器IP,而非真实客户端IP,PHP的$_SERVER['REMOTE_ADDR']也会受此影响,导致两边IP不一致,校验失败。
代理场景处理:
- 确认Nginx已安装
ngx_http_realip_module(Ubuntu默认Nginx通常包含),在http或server块添加真实IP配置:
set_real_ip_from 192.168.1.0/24; # 替换为你的代理/CDN IP段 real_ip_header X-Forwarded-For; real_ip_recursive on;
- 修改Secure Link配置,用
$realip_remote_addr替代$remote_addr:
location /files { secure_link $arg_md5,$arg_expires; secure_link_md5 "$secure_link_expires$uri$realip_remote_addr enigma"; if ($secure_link = "") { return 403; } if ($secure_link = "0") { return 410; } }
- 同步修改PHP代码,适配代理场景获取真实IP:
// 替换原$ip = $_SERVER['REMOTE_ADDR']; function getClientIP() { $ip = $_SERVER['REMOTE_ADDR']; if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { $ip = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])[0]; } return trim($ip); } $ip = getClientIP();
2. 校验URI的一致性
Nginx的$uri是未解码的原始请求路径,而PHP代码中使用urldecode会导致URI与Nginx端不一致(若含特殊字符如%20),进而签名不匹配。
修改PHP代码,移除urldecode:
// 原代码:$uri = urldecode('/files/test.pdf'); $uri = '/files/test.pdf';
3. 调试验证(关键步骤)
在Nginx配置中添加日志,输出签名原始字符串,对比PHP生成的内容:
location /files { secure_link $arg_md5,$arg_expires; secure_link_md5 "$secure_link_expires$uri$realip_remote_addr enigma"; # 添加调试日志 access_log /var/log/nginx/secure_link_debug.log "expires=$secure_link_expires uri=$uri ip=$realip_remote_addr string=$secure_link_expires$uri$realip_remote_addr enigma"; if ($secure_link = "") { return 403; } if ($secure_link = "0") { return 410; } }
重启Nginx后,访问链接查看日志,同时在PHP中输出签名原始字符串:
// 在getSecureHash函数中添加调试输出 function getSecureHash($ip, $uri, $secure_text, $expires){ $str = $expires.$uri.$ip.$secure_text; echo "PHP生成的签名字符串:".$str."<br>"; // 调试用 $tmp = md5( $str, true ); $tmp = base64_encode( $tmp ); return str_replace( array('+', '/', '='), array('-', '_', ''), $tmp ); }
只有两边字符串完全一致,校验才能通过。
4. 其他注意事项
- 确保PHP中
$expires已正确赋值(如$expires = time() + 3600;表示1小时后过期) - 签名字符串的空格要严格一致:Nginx配置中
$realip_remote_addr与enigma间的空格,和PHP中$secure_text = ' enigma'的前置空格必须完全匹配。
内容的提问来源于stack exchange,提问作者Hamid Ali
相关产品推荐
相关产品推荐

