You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 20:35:22