Context
我正在建立一个使用Django框架和条带的用户支付在Python的网站.我目前正处于本地开发的测试/调试阶段,离生产版本还很远.
目前在用CSRF保护砖墙,也找不到解决方案.我的收银台在没有CSRF保护的情况下工作得很好.
这里还有其他非常类似的话题,但由于我对CSRF保护本身缺乏了解,我希望有人能告诉我在我的特定场景中应该做些什么.
这种情况应该有一个通用的实践解决方案,但我已经研究了Django和Strip的大部分文档,但没有成功.
欢迎批评,这是我的第一篇StackOverflow帖子.
The Problem
我有一个查看功能,使用户能够在我的网站上通过发送到Stripe外部 checkout 页面购买产品.
Views.py(过时)
@csrf_exempt # CSRF Protection disabled for testing
def create_checkout_session(request):
if request.method == 'POST':
try:
checkout_session = stripe.checkout.Session.create(
...
)
except Exception as e:
...
return redirect(签出_会话.url)
在测试期间,我使用Django的@csrf_exempt修饰器禁用了查看功能的CSRF保护.我这样做是为了绕过"403 CSRF验证失败"错误.
我之所以得到这个错误,首先是因为Django's Documentation上的this statement:
<form method="post">{% csrf_token %}
个
不应对以外部URL为目标的POST表单执行此操作,因为这会导致CSRF令牌泄漏,从而导致漏洞.
在删除@csrf_exempt修饰符之后,我现在被卡住了,因为这正是我的提交表单的工作方式,如下面的Products.html中所示, checkout URL是由stripe生成的(如views.py中所示),因此(我认为)是一个外部URL:
Products.html
<form rel="noreferrer" action="{% url 'checkout' %}" method="POST">
{% csrf_token %} <!-- forbidden in POST to external URL -->
<button rel="noreferrer" id="checkout-button" class="btn btn-sm" type="submit">
Buy
</button>
</form>
目前正在质疑以下几件事:
- 有没有其他方法可以在不使用POST的情况下获得相同的结果?
- 我是不是误解了STRIP文档?
- checkout URL实际上是"外部的"吗?
- 为了更好的安全性,我是否应该放弃这种方法,并在我的网站上硬编码条纹的 checkout ?
UPDATE个
根据要求,在对敏感信息进行一些更改后,下面是详细的文件.
Views.py:
@csrf_exempt
def create_checkout_session(request):
if request.method == 'POST':
try:
checkout_session = stripe.checkout.Session.create(
line_items=[
{
'price': 'pr_123456789',
'quantity': 1,
},
],
mode='payment',
success_url=DOMAIN + 'payments/success',
cancel_url=DOMAIN + 'payments/cancel',
automatic_tax={'enabled': True},
)
except Exception as e:
return HttpResponse(f'<h1>{str(e)}</h1>')
return redirect(签出_会话.url)
Urls.py:
urlpatterns = [
path('', views.home, name='home'),
path('checkout/', views.create_checkout_session, name='checkout'),
path('success/', views.success, name='success'),
path('cancel/', views.cancel, name='cancel'),
]
变量checkout_session接受参数并返回一个对象,我可以在其中调用签出_会话.url,如views.py中所示.
我的印象是check out_ession.url是一个外部URL,这是因为Strip生成并托管了这个链接.为了确认这一点,我在check out_ession.url上运行了一次控制台打印,它返回以下内容:
签出_会话.url
https://checkout.stripe.com/c/pay/cs_test_long_hex_variable_relevant_to_my_API_keys个
此URL对于由条纹生成的每个 checkout 会话都是唯一的.
我确信Stripe有它自己的安全性,但我担心的是CSRF Protection的跨站点部分.
- 我有责任为用户维护外部支付Provider 的安全吗?
- 这就是CSRF保护的工作方式吗?
- 如果是这样的话,Django的内置解决方案是什么,因为这必须是一种常见的做法?
使用的资源:
- Stripe Documentation个
- Django Documentation个
- Windows 11
- PyCharm IDE
- Python3.11
- 现在是4:2.
- 条带5.4
- firefox 114.0.1
What I've Tried:
我试图找到类似的解决方案,我在这里发现了与我的问题相关的多个问题,但我发现没有一个涉及CSRF保护外部URL的细节.
Django文档指出,禁止在POST期间使用{%CSRF_TOKE%}到外部URL,但在进一步调查后,没有详细说明任何解决办法或替代方案.
在得出解决方案并不明显的结论后,我的印象是,我的问题不是别人造成的,因为我缺乏CSRF防护和一般网络安全方面的知识.这就把我带到了StackOverflow的知识池中.