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)来自动执行部分反计算机资源框架保护。

相关推荐
光影少年7 分钟前
angular生态及学习路线
前端·学习·angular.js
猫头虎1 小时前
如何查看局域网内IP冲突问题?如何查看局域网IP环绕问题?arp -a命令如何使用?
网络·python·网络协议·tcp/ip·开源·pandas·pip
沿着路走到底2 小时前
python 基础
开发语言·python
无尽夏_2 小时前
HTML5(前端基础)
前端·html·html5
Jagger_2 小时前
敏捷开发流程-精简版
前端·后端
FIN66683 小时前
昂瑞微冲刺科创板:创新驱动,引领射频芯片国产化新征程
前端·安全·前端框架·信息与通信·芯片
GISer_Jing3 小时前
ByteDance——jy真题
前端·javascript·面试
睡美人的小仙女1273 小时前
浏览器为何屏蔽本地文件路径?
前端
真的想不出名儿3 小时前
Vue 中 props 传递数据的坑
前端·javascript·vue.js
FIN66683 小时前
昂瑞微:深耕射频“芯”赛道以硬核实力冲刺科创板大门
前端·人工智能·科技·前端框架·信息与通信·智能