Django中HTTP_REFERER判断Stripe来源在Safari端失效的修复方法
问题根因
你这套逻辑跑不动Safari的核心原因是过度依赖HTTP_REFERER字段做来源校验,这个字段在Safari上天生就不可靠:
- Safari的内置智能防跟踪(ITP)机制对跨站跳转的Referer传输有非常严格的限制,你在Django里配的
SECURE_REFERRER_POLICY = "no-referrer-when-downgrade"其实只管你自己站点往外发请求的时候带不带Referer,根本管不到Safari处理Stripe域名跳转到你站点时的Referer行为——只要用户开了Safari默认开启的跨站跟踪拦截,跨站跳转的Referer头会被直接置空,你根本拿不到预期的Stripe来源值,自然会把合法跳转的用户重定向到错误页。 - 你原来写的全字符串硬匹配
https://checkout.stripe.com/本身鲁棒性就差:实际Stripe结账跳转回来的Referer经常会带会话路径、查询参数,甚至末尾斜杠的格式都不一定和你写的字符串完全一致,Chrome能正常跑只是刚好匹配上了,本身没有任何容错能力。
修复方案
核心思路是别把判断全押在Referer上,用Stripe原生支持的回传参数做优先级最高的校验,Referer只当兜底项:
- 先改Stripe Checkout Session的配置,把结账成功后跳转回注册页的URL加上专属校验标识,比如设置成站点路径
/register?checkout_token=xxx。不要直接用这种明文的stripe_checkout=1参数当校验依据,最好在创建Checkout Session的时候生成一个带时效、绑定本次会话的随机token存在后端缓存里,用户回传的时候再校验token有效性,避免被人恶意拼接参数绕过判断。 - 调整视图里的判断逻辑,同时覆盖可靠校验和兜底校验:
def register(request): # 优先校验Stripe回传的带时效token,这部分逻辑不受浏览器Referer策略影响 stripe_source_valid = check_token_valid(request.GET.get('checkout_token')) # 兜底校验Referer,只匹配Stripe的基础域名,不做全路径硬匹配 referer = request.META.get('HTTP_REFERER', '') stripe_referer_valid = referer.startswith('https://checkout.stripe.com') if stripe_source_valid or stripe_referer_valid: return render(request, 'users/register.html') return redirect('error')
- 这套逻辑跑起来之后,哪怕Safari把Referer头完全截断,只要用户是从Stripe合法跳转过来的,就能通过token校验进入注册页,不会被误重定向。而且不管是Chrome、iOS端Safari还是其他内核的浏览器,都能统一生效,不需要用户调整任何浏览器设置。
内容的提问来源于stack exchange,提问作者KieranDL3
相关产品推荐
相关产品推荐

