CSRF介绍及Python实现

CSRF

文章目录

  • CSRF
    • [1. CSRF是什么?](#1. CSRF是什么?)
    • [2. CSRF可以做什么?](#2. CSRF可以做什么?)
    • [3. CSRF漏洞现状](#3. CSRF漏洞现状)
    • [4. CSRF的原理](#4. CSRF的原理)
    • [5. 举例说明](#5. 举例说明)
    • [6. CSRF的防御](#6. CSRF的防御)

1. CSRF是什么?

  • CSRF(C ross-S ite R equest Forgery),中文名称:跨站请求伪造,也被称为:one click attack/session riding,缩写为:CSRF/XSRF。

2. CSRF可以做什么?

  • 你这可以这么理解CSRF攻击:**攻击者盗用了你的身份,以你的名义发送恶意请求。**CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账...造成的问题包括:个人隐私泄露以及财产安全。

3. CSRF漏洞现状

  • CSRF这种攻击方式在2000年已经被国外的安全人员提出,但在国内,直到06年才开始被关注,08年,国内外的多个大型社区和交互网站分别爆出CSRF漏洞,如:NYTimes.com(纽约时报)、Metafilter(一个大型的BLOG网站),YouTube和百度HI...而现在,互联网上的许多站点仍对此毫无防备,以至于安全业界称CSRF为"沉睡的巨人"。

4. CSRF的原理

  • 下图简单阐述了CSRF攻击的思想:
  • 从上图可以看出,要完成一次 CSRF攻击,受害者必须依次完成两个步骤:

    1. 登录受信任网站A,并在本地生成Cookie。
    2. 在不登出A的情况下,访问危险网站B。
  • 看到这里,你也许会说:"如果我不满足以上两个条件中的一个,我就不会受到CSRF的攻击"。是的,确实如此,但你不能保证以下情况不会发生:

    1. 你不能保证你登录了一个网站后,不再打开一个tab页面并访问另外的网站。
    2. 你不能保证你关闭浏览器了后,你本地的Cookie立刻过期,你上次的会话已经结束。(事实上,关闭浏览器不能结束一个会话,但大多数人都会错误的认为关闭浏览器就等于退出登录/结束会话了...)
    3. 上图中所谓的攻击网站,可能是一个存在其他漏洞的可信任的经常被人访问的网站。

5. 举例说明

  • 上面大概地讲了一下CSRF攻击的思想,这里用个例子详细说说具体的CSRF攻击,这里我以一个银行转账的操作作为例子(仅仅是例子,真实的银行网站没这么傻)

  • 银行网站A,它以GET请求来完成银行转账的操作:如:http://www.mybank.com/Transfer.php?toBankId=11&money=1000

  • 危险网站B,它里面有一段HTML的代码如下:

    <img src=http://www.mybank.com/Transfer.php?toBankId=11&money=1000>

  • 首先,你登录了银行网站A,然后访问危险网站B,噢,这时你会发现你的银行账户少了1000块...

    为什么会这样呢?原因是银行网站A违反了HTTP规范,使用GET请求更新资源。在访问危险网站B的之前,你已经登录了银行网站A,而B中的<img>以GET的方式请求第三方资源(这里的第三方就是指银行网站了,原本这是一个合法的请求,但这里被不法分子利用了),所以你的浏览器会带上你的银行网站A的Cookie发出Get请求,去获取资源http://www.mybank.com/Transfer.php?toBankId=11&money=1000,结果银行网站服务器收到请求后,认为这是一个更新资源操作(转账操作),所以就立刻进行转账操作...

  • 理解了例子中的攻击模式,其实可以看出,CSRF攻击是源于WEB的隐式身份验证机制!WEB的身份验证机制虽然可以保证一个请求是来自于某个用户的浏览器,但却无法保证该请求是用户批准发送的!

6. CSRF的防御

  • Python 不提供针对 CSRF 攻击的内置built-in保护;开发人员必须通过检查 anti-CSRF tokens 或使用许多经过良好测试的库和框架中的一个来手动实现这一功能。

Python示例

以下步骤展示了如何使用登录时生成的每个会话 token 手动保护 Flask 端点 /delete_user 免受 CSRF 攻击。

  1. 身份验证成功后,会以安全方式生成一个随机 token,并作为用户的会话变量存储起来。

    python 复制代码
    @login.route("/login", methods=['POST'])
     def login():
         username = request.form.get("username")
         password = request.form.get("password")
    
         if validate_credentials(username, password):
             session['anti_crf_token'] = get_random_token()
             # ...

    函数 get_random_token() 必须返回用户会话唯一的强随机字符串。请参阅 uuid 或 Python3 secrets 库生成加密安全令牌。

  2. 为了保护任何改变状态的 endpoint,表单必须将 anti-CSRF token 设置为隐藏值。在下面的代码中, /users endpoint将渲染 users.html Jinja2 template。

    python 复制代码
    @login.route("/users", methods=['GET'])
    def users():
      if session_is_authenticated():
        return render_template('users.html', anti_crf_token=session['anti_crf_token'])

    users.html template 定义了包含标记 anti_crf_token 的 HTML 表单。

    html 复制代码
    <form action="/delete_user" method="post">
      <!-- ... -->
      <input type="hidden" name="anti_crf_token" value="{{anti_crf_token}}">
     </form>
  3. 现在,可以通过检查表单 POST 参数中发送的 anti_csrf_token 是否与 session['anti_crf_token'] 是否匹配来确保 /delete_user 的安全。

    python 复制代码
    @login.route("/delete_user", methods=['POST'])
    def delete_user():
       anti_csrf_token = request.form.get("anti_csrf_token")
       if session['anti_crf_token'] != anti_csrf_token:
           return "Error, wrong anti CSRF token", 401
       # Continue with a valid token

还可以使用其他库(如 WTFormsFlask-WTF)来自动执行部分反计算机资源框架保护。

相关推荐
哆啦A梦15881 小时前
[前台小程序] 01 项目初始化
前端·vue.js·uni-app
小周同学@3 小时前
谈谈对this的理解
开发语言·前端·javascript
Wiktok3 小时前
Pyside6加载本地html文件并实现与Javascript进行通信
前端·javascript·html·pyside6
一只小风华~3 小时前
Vue:条件渲染 (Conditional Rendering)
前端·javascript·vue.js·typescript·前端框架
柯南二号3 小时前
【大前端】前端生成二维码
前端·二维码
乔巴先生244 小时前
LLMCompiler:基于LangGraph的并行化Agent架构高效实现
人工智能·python·langchain·人机交互
程序员码歌4 小时前
明年35岁了,如何破局?说说心里话
android·前端·后端
博客zhu虎康5 小时前
React Hooks 报错?一招解决useState问题
前端·javascript·react.js
张子夜 iiii5 小时前
实战项目-----Python+OpenCV 实现对视频的椒盐噪声注入与实时平滑还原”
开发语言·python·opencv·计算机视觉
灰海5 小时前
vue中通过heatmap.js实现热力图(多个热力点)热区展示(带鼠标移入弹窗)
前端·javascript·vue.js·heatmap·heatmapjs