django 安全之防御 csrf

发布于 2024-10-03 11:11:14 字数 2738 浏览 10 评论 0

本文主要通过分析 django 源码 介绍 django 在 csrf (跨站请求伪造) 的防御措施, 默认大家对 csrf 有一定的了解

0x01

一般问到如何防御 csrf, 很多人都会给这么个答案,请求的时候带一个 token,到服务器验证 token 的有效性。原理是没错,但是如果让你设计这个防御系统,需要考虑哪些呢,我觉得有这么几点

  • token 如何存储
  • token 如何验证
  • token 何时刷新

存储和验证相关联,有这么一种做法,每次用户登录生成随机值,存在数据库或者缓存中,请求的时候带上 token,每次去查询 token 有效性,这种方法其实就跟 session 验证用户是否登录一样。但问题是如果用户很多,验证的效率怎么保证。所以这种方法可行,但是成本不划算。第二种就是现在大多数的做法,cookie 里面带一个 csrf_token, 每次请求的时候也带上 token ,然后只要比较两者是否相同就行了,这样服务器没存任何东西,保证了效率。当然如果你的站点有 xss 之类的漏洞,cookie 也会泄露,同样不能保证这种方案的有效性。

token 刷新其实可以只要登录的时候刷新下,因为除非泄露,一般情况下 token 被暴力破解的概率不大。

0x02

下面看 django 如何实现的
django 对于 csrf 的防御主要在 middleware 实现,默认是开始 csrf 防御的,当然也可以关闭,单独对一些 view 开启,不过不建议这么做


try:
csrf_token = _sanitize_token(
request.COOKIES[settings.CSRF_COOKIE_NAME])
# Use same token next time
request.META['CSRF_COOKIE'] = csrf_token
except KeyError:
csrf_token = None

这部分取得 cookie 里面的 csrf_token, 如果不存在则生成一个新的 csrf_token

request_csrf_token = request.POST.get('csrfmiddlewaretoken', '')

这个是取得 post 请求的 request_csrf_token

request_csrf_token = request.META.get(settings.CSRF_HEADER_NAME, '')

对于 put delete 或者 ajax 请求来说,需要把 token 放到 headers 里面,名字为 X-CSRFToken

最后只要比较 csrf_token 和 request_csrf_token 就能有效的防御 csrf

这里面有个特殊的地方,对于 http 来说,有可能存在中间人攻击,所以没法信任 HTTP_REFERER 这个 header ,但如果是 https, 做了下 HTTP_REFERER 的检查,只要 referer 不在信任域,一律拒绝。


referer = force_text(
request.META.get('HTTP_REFERER'),
strings_only=True,
errors='replace'
)
if referer is None:
return self._reject(request, REASON_NO_REFERER)

# Here we generate a list of all acceptable HTTP referers,
# including the current host since that has been validated
# upstream.
good_hosts = list(settings.CSRF_TRUSTED_ORIGINS)
# Note that request.get_host() includes the port.
good_hosts.append(request.get_host())
good_referers = ['https://{0}/'.format(host) for host in good_hosts]
if not any(same_origin(referer, host) for host in good_referers):
reason = REASON_BAD_REFERER % referer
return self._reject(request, reason)

在登录的时候需要加上 rotate_token, 来刷新 token

def rotate_token(request):
"""
Changes the CSRF token in use for a request - should be done on login
for security purposes.
"""
request.META.update({
"CSRF_COOKIE_USED": True,
"CSRF_COOKIE": _get_new_csrf_key(),
})

0x03

总结下,django 框架本身对于安全性这块做的挺好的,对于工程师来说是福也是祸,能够更专注逻辑实现,但是有时候也因为忽视导致安全事故的发生。所以安全研发意识其实很重要,形成一些好的习惯,防患于未然。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

夏雨凉

暂无简介

0 文章
0 评论
23 人气
更多

推荐作者

謌踐踏愛綪

文章 0 评论 0

开始看清了

文章 0 评论 0

高速公鹿

文章 0 评论 0

alipaysp_PLnULTzf66

文章 0 评论 0

热情消退

文章 0 评论 0

白色月光

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文