美文网首页
CSRF攻击原理及防御

CSRF攻击原理及防御

作者: yangyaqdejs | 来源:发表于2019-01-12 17:17 被阅读0次

一、CSRF介绍

CSRF(cross-site request forgery,跨站域请求伪造),也被称为 one link attack/session riding,缩写(XSRF/CSRF)。

二、 浏览器同源策略

同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。

同源是指:协议、域名、端口 同时相同才认为是同源。在同源检测时,将使用document.domain作为检测的依据。

Compared URL Outcome Reason
http://www.example.com/dir/page2.html Success Same protocol, host and port
http://www.example.com/dir2/other.html Success Same protocol, host and port
http://username:password@www.example.com/dir2/other.html Success Same protocol, host and port

下表为反例。

Compared URL Outcome Reason
http://www.example.com:81/dir/other.html Failure Same protocol and host but different port
https://www.example.com/dir/other.html Failure Different protocol
http://en.example.com/dir/other.html Failure Different host
http://example.com/dir/other.html Failure Different host (exact match required)
http://v2.www.example.com/dir/other.html Failure Different host (exact match required)

下表依赖于浏览器的实现

Compared URL Outcome Reason
http://www.example.com:80/dir/other.html Depends Port explicit. Depends on implementation in browser.

一般浏览器默认80端口,当端口显示制定为80时,根据浏览器策略而定。

受限制内容

对JavaScript代码能够操作哪些Web内容的一条完整的安全限制,主要针对js读取某些内容或读写某些属性,例如:

  1. DOM无法获得:禁止对不同源页面DOM进行操作。这里主要场景是iframe跨域的情况,不同域名的iframe是限制互相访问的。
  2. ajax请求不能发送: 禁止使用XHR对象向不同源的服务器地址发起HTTP请求。
  3. Cookie、LocalStorage 和 IndexDB 无法读取。

不受限制内容

允许嵌入资源,例如img链接、<script src="..."> </script> 、<img> 、<link> 等。

三、 Cookie作用域

Cookie 是服务器写入浏览器的一小段信息,只有同源的网页才能共享。

Cookie有两个很重要的属性:Domain和Path,用来指示此Cookie的作用域:Domain告诉浏览器当前要添加的Cookie的域名归属;Path告诉浏览器当前要添加的Cookie的路径归属,如果没有明确指明则默认为当前路径。浏览器提交的Cookie需要满足以下两点:

  1. 当前域名或者父域名下的Cookie。

  2. 当前路径或父路径下的Cookie,要满足这两个条件的Cookie才会被提交。

四、 CSRF攻击原理

攻击者(attacker)利用存储在本地的有效cookie及cookie的作用域来伪造用户的某种行为(只是利用cookie骗取服务器信任,并不能拿到cookie,也看不到cookie内容)。

  1. 用户(victim)访问信任网站A,输入用户名和密码并登录成功,产生网站A的生成的cookie。
  2. 在此cookie的有效期内,用户恰好访问恶意网站B,网站B上有某个隐藏的链接或者图片标签会自动请求网站A的URL地址,例如表单提交,传指定的参数, 此时浏览器会自动携带网站A的cookie。
  3. 网站A收到这个请求后,误认为是用户(victim)的正常操作,伪造成功。

五、CSRF攻击防御

大多数防御方法是在请求中嵌入额外的验证数据来检测是否是真实用户的操作。

Synchronizer token pattern

在form表单中嵌入验证信息,并在server端校验。攻击者无法使用最新的csrf值进行操作,代码如下:

import tornado
import os
import binascii
from tornado import web
from tornado import ioloop
from tornado.web import HTTPError

csrfs = b""

class MainHandler(tornado.web.RequestHandler):

    def make_crsf(self):
        global csrf
        csrf = binascii.b2a_hex(os.urandom(16)).decode()
        return csrf

    def get(self):
        self.write("""<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <form action="/" method="POST" enctype="multipart/form-data">
            <input type="file" name="filename">
            <input type="hidden" name="csrf" value="%s">
            <input type="submit" name="submit">
        </form>
    </body>
</html>"""%(self.make_crsf()))


    def post(self):
        if csrf != self.get_argument('csrf',""):
            raise HTTPError(403)

        for filename,files in self.request.files.items():
            for file in files:
                print(self.request.headers.get('Content-Type'))
                print(file["filename"],"len %s bytes"%(len(file["body"])))

        self.write(b'upload ok')



class Application(tornado.web.Application):

    def __init__(self):
        settings = dict(
            debug=True,
        )
        handlers = [
            (r'/',MainHandler),
        ]

        super(Application,self).__init__(handlers,settings)


def make_app():
    return Application()


if __name__ == "__main__":
    app = make_app()
    app.listen(8888)
    ioloop.IOLoop.current().start()

弊端:

  1. 服务端需要存储每个用户的最新的csrf值。
  2. 同一个用户打开多个tab页面时,其它某些csrf值可能失效,返回403错误。

Cookie-to-header token

此方法是基于浏览器的同源策略,同源才能读取cookie 值。恶意网站受同源限制不能读取cookie值。

用户访问表单页面时,server端设置xsrf_cookie,页面嵌入js代码,自定义header头。

index.html

<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <script type="text/javascript" src="https://cdn.staticfile.org/jquery/2.0.0/jquery.min.js"></script>
        <script type="text/javascript" src="http://malsup.github.com/jquery.form.js"></script>
    </head>

    <body>
        <form id="myform" action="/" method="POST" enctype="multipart/form-data">
            <input id="file" type="file" name="filename">
        </form>
        <input id="submit" type="button" value="提交" onclick="showoption()">
    </body>
    <script>

    function getCookie(name) {
        var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
        return r ? r[1] : undefined;
    }

    function showoption(){

        var formData = new FormData();
        formData.append("filename",document.getElementById("file").files[0]);

        var option = {
            url : "/",
            type : 'POST',
            data: formData,
            headers : {"X-XSRFToken":getCookie("_xsrf")}, //添加请求头部
            contentType : false,
            processData : false,
            success : function(data) {
                 console.log('success');
                 document.write(data);
            },
            error: function(data) {
                 console.log('error');
                 document.write('upload failed');
            }
        }
        $.ajax(option)
    }
    </script>
</html>

handler

import os
import binascii
import tornado
from tornado import web
from tornado import ioloop

class MainHandler(tornado.web.RequestHandler):

    def get(self):
        xsrf = binascii.b2a_hex(os.urandom(16))
        self.set_cookie('_xsrf',xsrf)
        self.render("index.html")

    def check_xsrf_cookie(self):
        if self.request.headers.get('X-XSRFToken') != self.get_cookie("_xsrf"):
            raise tornado.web.HTTPError(403)

    def post(self):
        self.check_xsrf_cookie()
        for filename,files in self.request.files.items():
            for file in files:
                print(self.request.headers.get('Content-Type'))
                print(file["filename"],"len %s bytes"%(len(file["body"])))

        self.write(b'upload ok')

class Application(tornado.web.Application):

    def __init__(self):
        settings = dict(
            debug=True,
            xsrf_cookies=True
        )
        handlers = [
            (r'/',MainHandler)
        ]

        super(Application,self).__init__(handlers,settings)


def make_app():
    return Application()


if __name__ == "__main__":
    app = make_app()
    app.listen(8888)
    ioloop.IOLoop.current().start()

Double Submit Cookie

当form表单提交时,服务端设置_xsrf值到cookie中,同时也设置到form表单中一份,server端收到请求时,从cookie中_xsrf字段取出csrf_token与form提交的_xsrf中取出的csrf_token值是否一致。

下面用tornado中的xsrf_form_html来实现。

index.html

<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <form action="/" method="POST" enctype="multipart/form-data">
            <input type="file" name="filename">
            {% module xsrf_form_html() %}
            <input type="submit" name="submit">
        </form>
    </body>
</html>

handlers.py

import tornado
from tornado import web
from tornado import ioloop

class MainHandler(tornado.web.RequestHandler):

    def get(self):
        self.render("index.html")

    def post(self):
        self.check_xsrf_cookie()
        for filename,files in self.request.files.items():
            for file in files:
                print(self.request.headers.get('Content-Type'))
                print(file["filename"],"len %s bytes"%(len(file["body"])))

        self.write(b'upload ok')

class Application(tornado.web.Application):

    def __init__(self):
        settings = dict(
            debug=True,
            xsrf_cookies=True
        )
        handlers = [
            (r'/',MainHandler),
        ]

        super(Application,self).__init__(handlers,settings)


def make_app():
    return Application()


if __name__ == "__main__":
    app = make_app()
    app.listen(8888)
    ioloop.IOLoop.current().start()

受同源策略限制,恶意网站不能根据form提交的_xsrf值设置别的源下的cookie值。

Cookie: _xsrf=2|f6cb1468|2debdc878192abd5577e27000d0daf91|1547196447

表单中的值为

<html><head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<form action="/" method="POST" enctype="multipart/form-data">
<input type="file" name="filename">
<input type="hidden" name="_xsrf" value="2|221a566b|f93a9e845543e9d683af6503d9dced92|1547196447">
<input type="submit" name="submit">
</form>
</body></html>

cookie失效之前,cookie值不会改变。cookie中解出token,form表单每次刷新时value值会改变,因为form表单中使用随机值生成masked_token。

有疑问?

Client-side safeguards

待补充

Other techniques

检验 HTTP Referer 字段

攻击者不能篡改Referer值,但是某些浏览器会隐藏Referer值,并且依赖浏览器。

相关文章

  • 面试12:安全类

    课程思维导图 Q:常见的攻击方式有哪些? CSRF:跨站请求伪造 XSS:跨站脚本攻击 Q:CSRF的原理及防御措...

  • CSRF攻击原理及防御

    什么是CSRF? CSRF(Cross-site request forgery)跨站请求伪造,也被称为“One ...

  • CSRF攻击原理及防御

    一、CSRF介绍 CSRF(cross-site request forgery,跨站域请求伪造),也被称为 on...

  • 前端面试题六-前端安全性问题

    一、xss跨站脚本攻击 原理:方式:防御: 二、CSRF跨站请求伪造 原理:方式:防御 三、sql脚本注入 原理:...

  • 每日安全资讯(2020.01.14)

    CSRF攻击防御原理因为现代浏览器的工作机制原因,造成一种WEB攻击形态的存在, 这种攻击形式叫做CSRF攻击,以...

  • 长亭chaitin.cn的技术面

    宽字节注入的原理 CSRF原理及防御 SSRF原理及防御 xss:expression()支持的浏览器 渗透的几个...

  • CSRF

    一.本文介绍 1、本文介绍csrf攻击原理、CSRF分类、拖库、修改密码、防御。 2、环境:Discuz_X1.5...

  • CSRF攻击及防御

    CSRF(Cross-site request forgery)跨站请求伪造:攻击者诱导用户进入第三方网站,在第三...

  • Laravel - CSRF 攻击与防御

    CSRF攻击与防御-start 什么是CSRF攻击?CSRF是跨站请求伪造(Cross-site request ...

  • 网络安全系列(3) CSRF攻击

    1.CSRF概述 1.2 CSRF 攻击实例 1.3 CSRF 攻击的对象 2.当前防御 CSRF 的几种策略 2...

网友评论

      本文标题:CSRF攻击原理及防御

      本文链接:https://www.haomeiwen.com/subject/iyycdqtx.html