1. 程式人生 > >防禦CSRF攻擊

防禦CSRF攻擊

跨站請求偽造(CSRF)是一種安全漏洞,攻擊者利用受害者的 session 來通過受害者的瀏覽器發出請求。攻擊者通過受害者的瀏覽器傳送請求,並偽造成是受害者自己發出的請求。

建議你先熟悉CSRF,哪些是相關的攻擊向量而哪些不是。我們建議從這裡開始。

很難直接區分哪些請求是安全的而哪些請求容易被CSRF攻擊,這是因為沒有對外掛及未來擴充套件的明確規範。因為歷史遺留原因,瀏覽器的外掛及擴充套件放寬了信任規則,引入了CSRF這樣的漏洞,現在修復漏洞的任務就落到了框架頭上。因此Play預設採取了保守的方案,但允許開發者自由修改策略。預設情況下,當下列所有情況全部滿足時Play會要求做CSRF檢查:

  • 請求方法不是 GET,HEAD 或者 OPTIONS
  • 請求包含一個或多個 Cookie 或者 Authorization 頭
  • CORS 過濾器沒有配置為信任請求源(request's origin)

注意:如果你使用了基於瀏覽器的身份驗證,如NTLM或者客戶端證書,而非基於cookies的或者HTTP的身份驗證,那麼你必須將 play.filters.csrf.header.protectHeaders設定為null,或者在protectHeaders中將身份驗證的請求頭包含進來。

Play的CSRF防護

Play支援多種方式來校驗一個請求是否是CSRF請求。最優先的方式就是使用CSRF token。此token在query string或請求體中隨每次請求一起提交,並在使用者session中儲存。Play每次都會校驗這兩個token是否存在及是否匹配。

為了對那些非瀏覽器的請求做簡單保護,Play僅僅在請求頭中檢查cookies。如果請求是AJAX提交的,你可以將CSRF token儲存在html頁面中,然後將它放到Csrf-Token中提交。

或者你可以這樣設定 play.filters.csrf.header.bypassHeaders:

  • 如果設定了 X-Requested-With 頭,Play就將請求視為安全的。很多JS 庫都支援新增 X-Request-With ,如JQuery。
  • 如果 Csrf-Token 頭的值為 nocheck,或者提供了一個有效的 CSRF token,Play就將請求視為安全的。

具體的設定方法如下:

play.filters.csrf.header.bypassHeaders {
  X-Requested-With = "*"
  Csrf-Token = "nocheck"
}

在使用這種方式來防禦CSRF攻擊時應該格外謹慎,因為它會被歷史遺留的瀏覽器外掛破壞。

信任CORS請求

預設如果在CSRF 過濾器之前存在CORS過濾器,CSRF過濾器將允許特定來源的CORS請求。要禁用這種檢查,可以將 play.filters.csrf.bypassCorsTrustedOrigins 設定為 false。

使用全域性CSRF過濾器

注意:在Play2.6.x中,CSRF過濾器在Play的預設過濾器呼叫鏈中。要檢視更多過濾器資訊請點選這裡

Play提供了全域性CSRF過濾器來過濾所有的請求。這也是為專案新增CSRF防禦的最簡單方式。也可以這樣來手動新增它:

play.filters.enabled += "play.filters.csrf.CSRFFilter"

也可以通過在路由前新增nocsrf修飾符來為特定的路由禁用CSRF過濾:

+ nocsrf
POST  /api/new              controllers.Api.newThing

使用隱式請求

所有的CSRF功能都預設已經提供了一個預設的隱式 RequestHeader(也可以使用Request,它繼承了RequestHeader),當沒有找到時,它將不會編譯。下面會展示具體的例子。

在Action中定義隱式Request

對於所有需要回去CSRF token的action來說都需要一個隱式的request:

// this actions needs to access CSRF token
def someMethod = Action { implicit request =>
    // access the token as you need
    Ok
  }