2013-12-10 26 views
154

我試圖理解與CSRF和適當的方式來防止它的整個問題。 (資源我已閱讀,理解並同意:OWASP CSRF Prevention CHeat Sheet,Questions about CSRF。)爲什麼將CSRF預防標記放入Cookie中很常見?

據我所知,圍繞CSRF的漏洞是通過假設(從web服務器的角度來看)一個有效的會話cookie傳入的HTTP請求反映了經過身份驗證的用戶的願望。但是,所有來源域的cookie都會奇蹟般地附加到瀏覽器的請求中,所以真正的所有服務器都可以從請求中存在的有效會話cookie推斷出請求來自具有經過驗證的會話的瀏覽器;它不能進一步假定在該瀏覽器中運行的代碼,或者它是否真的反映了用戶的願望。防止這種情況的方法是在請求中包含額外的身份驗證信息(「CSRF令牌」),該信息通過瀏覽器的自動cookie處理以外的其他方式進行。鬆散地說,會話cookie認證用戶/瀏覽器,並且CSRF令牌認證在瀏覽器中運行的代碼。簡而言之,如果您使用會話cookie對Web應用程序的用戶進行身份驗證,則還應該爲每個響應添加一個CSRF令牌,並且在每個(變異)請求中都需要一個匹配的CSRF令牌。然後,CSRF令牌從服務器到瀏覽器返回服務器,向服務器證明發出請求的頁面已被該服務器(由該服務器生成)批准。

對我的問題,這是關於在該往返中用於該CSRF令牌的特定傳輸方法。

看來常見(如AngularJSDjangoRails)從服務器發送CSRF令牌客戶端作爲cookie(即在一個Set-Cookie標頭),然後有JavaScript中的客戶端刮出來的cookie並將其附加爲單獨的XSRF-TOKEN標頭以發送回服務器。

(另一種方法是由Express推薦的方法,其中由服務器生成的CSRF令牌通過服務器端模板擴展包含在響應主體中,直接附加到將提供給代碼/標記的代碼/標記服務器,例如作爲一個隱藏的表單輸入,這個例子是一個更加web 1.0的方式,但是會把它推廣到一個更重的JS客戶端上。)

爲什麼使用Set- Cookie作爲CSRF令牌的下游傳輸/爲什麼這是個好主意?我想所有這些框架的作者仔細考慮了他們的選擇,並沒有得到這個錯誤。但乍一看,使用cookie來解決cookies本質上的設計限制看起來很愚蠢。事實上,如果您使用cookie作爲往返傳輸(Set-Cookie:header下游服務器告訴瀏覽器CSRF令牌,並且Cookie:header上游瀏覽器將其返回給服務器),則您將重新引入此漏洞正在嘗試修復。

我意識到上面的框架在CSRF令牌的整個往返過程中不使用cookie;他們在下游使用Set-Cookie,然後在上游使用其他東西(例如X-CSRF-Token標頭),這確實關閉了漏洞。但即使使用Set-Cookie作爲下游交通工具也可能具有誤導性和危險性。瀏覽器現在將CSRF令牌附加到包括真正的惡意XSRF請求在內的每個請求;充其量只會讓請求變得比它需要的更大,而最壞的情況是一些善意但錯誤的服務器代碼可能會嘗試使用它,這將會非常糟糕。此外,由於CSRF令牌的實際目標收件人是客戶端JavaScript,這意味着此cookie不能僅使用http保護。因此,在Set-Cookie頭中向下遊發送CSRF令牌對我來說似乎並不理想。

回答

153

一個很好的理由是,一旦接收到CSRF cookie,就可以在客戶端腳本的整個應用程序中使用它,以便在常規窗體和AJAX POST中使用。這對於AngularJS所使用的大量JavaScript應用程序來說是有意義的(使用AngularJS並不要求應用程序將是單頁面應用程序,所以當狀態需要在不同的頁面請求之間流動時,CSRF值通常不能在瀏覽器中持續存在)。

考慮的每個接近你介紹一些優點和缺點的典型應用以下場景和過程。這些是基於Synchronizer Token Pattern

請求體法

  1. 用戶成功登錄。
  2. 服務器問題權威性的cookie。
  3. 用戶點擊導航到表單。
  4. 如果尚未爲此會話生成,服務器將生成CSRF令牌,並將其存儲在用戶會話中並將其輸出到隱藏字段。
  5. 用戶提交表單。
  6. 服務器檢查隱藏字段是否匹配會話存儲的令牌。

優點:

  • 容易實現。
  • 適用於AJAX。
  • 與窗體一起使用。
  • 餅乾,其實是可以HTTP Only

缺點:

  • 所有表格必須輸出HTML隱藏字段。
  • 任何AJAX POSTs也必須包含該值。
  • 頁面必須事先知道它需要CSRF令牌,因此它可以將其包含在頁面內容中,因此所有頁面都必須在某處包含令牌值,這可能會使其爲大型站點實施耗時。

自定義HTTP頭(下游)

  1. 用戶成功登錄。
  2. 服務器問題權威性的cookie。
  3. 用戶點擊導航到表單。
  4. 在瀏覽器中加載頁面,然後發出AJAX請求來檢索CSRF令牌。
  5. 服務器生成CSRF令牌(如果尚未爲會話生成),將其存儲在用戶會話中並將其輸出到 標頭。
  6. 用戶提交表單(令牌通過隱藏字段發送)。
  7. 服務器檢查隱藏字段是否匹配會話存儲的令牌。

優點:

  • 作品與AJAX。
  • Cookie可以是HTTP Only

缺點:

  • 不無AJAX請求來獲取標頭值工作。
  • 所有表格必須具有動態添加到其HTML的值。
  • 任何AJAX POSTs也必須包含該值。
  • 該頁面必須首先發出一個AJAX請求才能獲取CSRF令牌,因此每次都會有額外的往返行程。
  • 也可以簡單地將令牌輸出到保存額外請求的頁面。

自定義HTTP頭(上游)

  1. 用戶成功登錄。
  2. Server問題AUTH的cookie。
  3. 用戶點擊導航到表單。
  4. 如果尚未爲此會話生成,則服務器將生成CSRF令牌,並將其存儲在用戶會話中並將其輸出到某處的頁面內容中。
  5. 用戶通過AJAX提交表單(令牌通過標頭髮送)。
  6. 服務器檢查自定義標題匹配會話存儲的令牌。

優點:

  • 作品與AJAX。
  • Cookie可以是HTTP Only

缺點:

  • 不與表單。
  • 所有AJAX POST都必須包含標題。

自定義HTTP頭(下游上游&)

  1. 用戶成功登錄。
  2. Server問題AUTH的cookie。
  3. 用戶點擊導航到表單。
  4. 在瀏覽器中加載頁面,然後發出AJAX請求來檢索CSRF令牌。
  5. 服務器生成CSRF令牌(如果尚未爲會話生成),將其存儲在用戶會話中並將其輸出到 標頭。
  6. 用戶通過AJAX提交表單(令牌通過標頭髮送)。
  7. 服務器檢查自定義標題匹配會話存儲的令牌。

優點:

  • 作品與AJAX。
  • Cookie可以是HTTP Only

缺點:

  • 不與表單。
  • 所有AJAX POSTs也必須包含該值。
  • 該頁面必須首先發出AJAX請求才能獲取CRSF標記,因此每次都需要進行額外的往返。

的Set-Cookie

  1. 用戶成功登錄。
  2. 服務器問題權威性的cookie。
  3. 用戶點擊導航到表單。
  4. 服務器生成CSRF令牌,將其存儲在用戶會話中並將其輸出到cookie。
  5. 用戶通過AJAX或HTML表單提交表單。
  6. 服務器檢查自定義標頭(或隱藏表單域)與會話存儲令牌匹配。
  7. Cookie可在瀏覽器中使用,用於額外的AJAX和表單請求,無需向服務器提出額外請求來檢索CSRF令牌。

優點:

  • 容易實現。
  • 適用於AJAX。
  • 與窗體一起使用。
  • 不一定需要AJAX請求來獲取cookie值。任何HTTP請求都可以檢索它,它可以通過JavaScript附加到所有表單/ AJAX請求。
  • 一旦CSRF令牌被檢索到,因爲它被存儲在一個cookie中,該值可以被重複使用而無需其他請求。

缺點:

  • 所有形式的值必須添加到其HTML動態。
  • 任何AJAX POSTs也必須包含該值。
  • 該cookie將被提交請求(即所有圖像,CSS,JS等GET,不參與CSRF過程)增加請求大小。
  • Cookie不能是HTTP Only

所以餅乾方法是相當動態提供了一個簡單的方法來檢索cookie的值(任何HTTP請求),並使用它(JS能值自動添加到任何形式的,它可以在AJAX請求既可以使用作爲標題或表單值)。一旦接收到會話的CSRF令牌,就不需要重新生成它,因爲採用CSRF攻擊的攻擊者沒有檢索該令牌的方法。如果惡意用戶嘗試使用上述任何方法讀取用戶的CSRF令牌,則Same Origin Policy將阻止該操作。如果惡意用戶嘗試檢索CSRF令牌服務器端(例如,通過curl),那麼此令牌將不會與受害者的auth會話cookie從請求中丟失的相同用戶帳戶關聯(這將是攻擊者的 - 因此它將不會與服務器端與受害者會話相關聯)。

以及Synchronizer Token Pattern也有Double Submit Cookie CSRF預防方法,它當然使用cookie來存儲一種類型的CSRF令牌。這更容易實現,因爲它不需要CSRF令牌的任何服務器端狀態。 CSRF令牌實際上可以是使用此方法時的標準認證cookie,並且該值通常與Cookie一起通過cookie提交,但該值也會在隱藏字段或標頭中重複,攻擊者無法將其複製爲他們無法讀取價值。然而,建議選擇另一個cookie,除了身份驗證cookie之外,還可以通過標記HttpOnly來確保身份驗證cookie的安全。所以這是你爲什麼使用基於cookie的方法找到CSRF預防的另一個常見原因。

+0

感謝您的詳細解答。有關Cookie在初始頁面加載的生命週期內保持有效的觀點,對於不是單頁應用程序的應用程序來說,這是一個不錯的選擇。 – metamatt

+4

我不確定我是否理解「如何檢索CSRF令牌的AJAX請求」(「自定義標頭:下游」部分中的第4步)可以安全地完成;由於這是一個單獨的請求,因此服務器不知道它來自哪裏;它如何知道泄露CSRF令牌是安全的?在我看來,如果你不能從最初的頁面加載中獲取令牌,那麼你會丟失(不幸的是,這使得自定義的下游響應頭部不起作用)。 – metamatt

+1

它將以這樣的方式完成,即同源策略保護響應不被不同域(例如AJAX POST)讀取。 – SilverlightFox

4

我最好的猜測答案:請考慮如何讓CSRF從服務器到瀏覽器令牌下這3個選項。

  1. 在請求正文(不是HTTP頭)中。
  2. 在自定義HTTP標頭,不設置Cookie。
  3. 作爲一個cookie,在一個Set-Cookie頭。

我認爲第一之一,請求主體(同時通過the Express tutorial I linked in the question證明),並不像移植到各種各樣的情況;不是每個人都動態地生成每個HTTP響應;最終需要將令牌放入生成的響應中的方式可能差異很大(以隱藏的形式輸入;在JS代碼的片段或其他JS代碼可訪問的變量中;甚至可能在URL中,儘管這似乎通常是不好的地方放置CSRF令牌)。因此,儘管可以進行一些定製工作,但#1是一個難以實施一刀切的方法。

第二個,自定義標題,是有吸引力的,但實際上並沒有工作,因爲while JS can get the headers for an XHR it invoked, it can't get the headers for the page it loaded from

這留下了第三個,一個由Set-Cookie頭部攜帶的Cookie,作爲一種易於在所有情況下使用的方法(任何人的服務器都可以設置每個請求的Cookie標頭,而不是在請求體中涉及什麼樣的數據)。所以儘管它的缺點,它是框架廣泛實施的最簡單的方法。

+4

我可能會說明顯而易見的,這是否意味着cookie不能正確地更正? – Photon

20

使用cookie來保存CSRF令牌不允許成功的攻擊,因爲攻擊者無法讀取cookie的值,因此無法放入服務器端CSRF驗證要求的位置。

攻擊者將能夠通過請求頭中的身份驗證令牌cookie和CSRF cookie向服務器發出請求。但是服務器並沒有將CSRF標記作爲請求頭中的cookie來查找,而是查看請求的有效載荷。即使攻擊者知道將CSRF令牌放入有效載荷的位置,他們也必須讀取它的值才能將其置於那裏。但瀏覽器的跨域策略會阻止從目標網站讀取任何cookie值。

相同的邏輯不適用於auth令牌cookie,因爲服務器期望它在請求標頭中,並且攻擊者不需要做任何特殊的事情就可以將它放在那裏。

+0

當然,攻擊者並不需要首先讀取cookie。他們可以通過src ='bank.com/transfer?to = hacker&amount = 1000'在瀏覽器請求的地方插入一張圖片,並附上該網站的關聯cookie('bank.com')? – developius

+1

CSRF用於驗證客戶端的用戶,而不是像您所建議的那樣通常從服務器端妥協保護站點。 – Tongfa

相關問題