CSRF攻擊原理及防御

一顷链、CSRF介紹

CSRF(cross-site request forgery橄抹,跨站域請求偽造),也被稱為 one link attack/session riding濒蒋,縮寫(XSRF/CSRF)盐碱。

二、 瀏覽器同源策略

同源策略(Same origin policy)是一種約定沪伙,它是瀏覽器最核心也最基本的安全功能瓮顽,如果缺少了同源策略,則瀏覽器的正常功能可能都會受到影響围橡∨欤可以說Web是構建在同源策略基礎之上的,瀏覽器只是針對同源策略的一種實現(xiàn)翁授。

同源是指:協(xié)議拣播、域名、端口 同時相同才認為是同源收擦。在同源檢測時贮配,將使用document.domain作為檢測的依據(jù)。

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)

下表依賴于瀏覽器的實現(xiàn)

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

一般瀏覽器默認80端口赠堵,當端口顯示制定為80時,根據(jù)瀏覽器策略而定叮称。

受限制內容

對JavaScript代碼能夠操作哪些Web內容的一條完整的安全限制,主要針對js讀取某些內容或讀寫某些屬性曹洽,例如:

  1. DOM無法獲得:禁止對不同源頁面DOM進行操作。這里主要場景是iframe跨域的情況辽剧,不同域名的iframe是限制互相訪問的送淆。
  2. ajax請求不能發(fā)送: 禁止使用XHR對象向不同源的服務器地址發(fā)起HTTP請求。
  3. Cookie怕轿、LocalStorage 和 IndexDB 無法讀取偷崩。

不受限制內容

允許嵌入資源,例如img鏈接撞羽、<script src="..."> </script> 阐斜、<img> 、<link> 等诀紊。

三谒出、 Cookie作用域

Cookie 是服務器寫入瀏覽器的一小段信息,只有同源的網(wǎng)頁才能共享邻奠。

Cookie有兩個很重要的屬性:Domain和Path笤喳,用來指示此Cookie的作用域:Domain告訴瀏覽器當前要添加的Cookie的域名歸屬;Path告訴瀏覽器當前要添加的Cookie的路徑歸屬碌宴,如果沒有明確指明則默認為當前路徑杀狡。瀏覽器提交的Cookie需要滿足以下兩點:

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

  2. 當前路徑或父路徑下的Cookie贰镣,要滿足這兩個條件的Cookie才會被提交呜象。

四、 CSRF攻擊原理

攻擊者(attacker)利用存儲在本地的有效cookie及cookie的作用域來偽造用戶的某種行為(只是利用cookie騙取服務器信任八孝,并不能拿到cookie董朝,也看不到cookie內容)。

  1. 用戶(victim)訪問信任網(wǎng)站A干跛,輸入用戶名和密碼并登錄成功子姜,產生網(wǎng)站A的生成的cookie。
  2. 在此cookie的有效期內楼入,用戶恰好訪問惡意網(wǎng)站B哥捕,網(wǎng)站B上有某個隱藏的鏈接或者圖片標簽會自動請求網(wǎng)站A的URL地址,例如表單提交,傳指定的參數(shù)嘉熊, 此時瀏覽器會自動攜帶網(wǎng)站A的cookie遥赚。
  3. 網(wǎng)站A收到這個請求后,誤認為是用戶(victim)的正常操作阐肤,偽造成功凫佛。

五讲坎、CSRF攻擊防御

大多數(shù)防御方法是在請求中嵌入額外的驗證數(shù)據(jù)來檢測是否是真實用戶的操作。

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 值。惡意網(wǎng)站受同源限制不能讀取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來實現(xiàn)。

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()

受同源策略限制腾供,惡意網(wǎng)站不能根據(jù)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值须肆,并且依賴瀏覽器匿乃。

?

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市豌汇,隨后出現(xiàn)的幾起案子幢炸,更是在濱河造成了極大的恐慌,老刑警劉巖拒贱,帶你破解...
    沈念sama閱讀 211,817評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件宛徊,死亡現(xiàn)場離奇詭異佛嬉,居然都是意外死亡,警方通過查閱死者的電腦和手機闸天,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評論 3 385
  • 文/潘曉璐 我一進店門暖呕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人号枕,你說我怎么就攤上這事缰揪。” “怎么了葱淳?”我有些...
    開封第一講書人閱讀 157,354評論 0 348
  • 文/不壞的土叔 我叫張陵钝腺,是天一觀的道長。 經常有香客問我赞厕,道長艳狐,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,498評論 1 284
  • 正文 為了忘掉前任皿桑,我火速辦了婚禮毫目,結果婚禮上,老公的妹妹穿的比我還像新娘诲侮。我一直安慰自己镀虐,他們只是感情好,可當我...
    茶點故事閱讀 65,600評論 6 386
  • 文/花漫 我一把揭開白布沟绪。 她就那樣靜靜地躺著刮便,像睡著了一般。 火紅的嫁衣襯著肌膚如雪绽慈。 梳的紋絲不亂的頭發(fā)上恨旱,一...
    開封第一講書人閱讀 49,829評論 1 290
  • 那天,我揣著相機與錄音坝疼,去河邊找鬼搜贤。 笑死,一個胖子當著我的面吹牛钝凶,可吹牛的內容都是我干的仪芒。 我是一名探鬼主播,決...
    沈念sama閱讀 38,979評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼腿椎,長吁一口氣:“原來是場噩夢啊……” “哼桌硫!你這毒婦竟也來了?” 一聲冷哼從身側響起啃炸,我...
    開封第一講書人閱讀 37,722評論 0 266
  • 序言:老撾萬榮一對情侶失蹤铆隘,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后南用,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體膀钠,經...
    沈念sama閱讀 44,189評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡掏湾,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,519評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了肿嘲。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片融击。...
    茶點故事閱讀 38,654評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖雳窟,靈堂內的尸體忽然破棺而出尊浪,到底是詐尸還是另有隱情,我是刑警寧澤封救,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布拇涤,位于F島的核電站,受9級特大地震影響誉结,放射性物質發(fā)生泄漏鹅士。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,940評論 3 313
  • 文/蒙蒙 一惩坑、第九天 我趴在偏房一處隱蔽的房頂上張望掉盅。 院中可真熱鬧,春花似錦以舒、人聲如沸趾痘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽扼脐。三九已至,卻和暖如春奋刽,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背艰赞。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評論 1 266
  • 我被黑心中介騙來泰國打工佣谐, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人方妖。 一個月前我還...
    沈念sama閱讀 46,382評論 2 360
  • 正文 我出身青樓狭魂,卻偏偏與公主長得像,于是被迫代替她去往敵國和親党觅。 傳聞我的和親對象是個殘疾皇子雌澄,可洞房花燭夜當晚...
    茶點故事閱讀 43,543評論 2 349

推薦閱讀更多精彩內容

  • CSRF是什么? (Cross Site Request Forgery, 跨站域請求偽造)是一種網(wǎng)絡的攻擊方式杯瞻,...
    謝澤閱讀 3,229評論 0 8
  • http://www.91ri.org/tag/fuzz-bug 通常情況下镐牺,有三種方法被廣泛用來防御CSRF攻擊...
    jdyzm閱讀 4,161評論 0 5
  • 本文是 Django 官網(wǎng)文檔的翻譯。官網(wǎng)鏈接:https://docs.djangoproject.com/en...
    學以致用123閱讀 5,664評論 0 5
  • 那年夏天魁莉,我轉學到了一個私立中學睬涧,讀初三募胃。 原本我的同桌是一個可愛搞笑的女生,卻因為鄰桌的男生上課太吵畦浓,所以班主任...
    123cmy閱讀 141評論 0 0
  • 明月皎皎痹束,清輝漫天。 如煙如水讶请,入眼入心祷嘶。 驅散陰霾,撫我心憂夺溢。 一路相隨论巍,照我歸途。 我的詩詞小窩
    探索書海閱讀 460評論 0 0