2011-04-02 63 views
1

我用rails new demo做了一個演示應用程序,然後用rails generate scaffold User name:string email:string生成了一個腳手架的用戶控制器。腳手架代碼有ApplicationControllerprotect_from_forgeryUserController也源自ApplicationControllerprotect_from_forgery不保護PUT/DELETE請求

我運行webrick,添加一個用戶,很酷。真實性標記按照POST/on用戶承諾的方式工作。

但仍使用Rails 3.0.5,我能夠做到:

[email protected]:~$ telnet 10.0.0.4 3000 
PUT /users/3 HTTP/1.1 
Content-Type: application/x-www-form-urlencoded 
Content-Length: 39 

user[name]=vvvvv&user[email]=shiaus.pl 

,並讓用戶修改3不給令牌:

Started PUT "https://stackoverflow.com/users/3" for 10.0.0.4 at 2011-04-02 14:51:24 +0200 
    Processing by UsersController#update as HTML 
    Parameters: {"user"=>{"name"=>"vvvvv", "email"=>"shiaus.pl\r"}, "id"=>"3"} 
    User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = 3 LIMIT 1 
', "updated_at" = '2011-04-02 12:51:24.437267' WHERE "users"."id" = 3s.pl 
Redirected to http://10.0.0.4:3000/users/3 
Completed 302 Found in 92ms 

我也可以做同樣的DELETE:

DELETE /users/3 HTTP/1.1 

這給了我:

Started DELETE "https://stackoverflow.com/users/3" for 10.0.0.4 at 2011-04-02 15:43:30 +0200 
    Processing by UsersController#destroy as HTML 
    Parameters: {"id"=>"3"} 
    SQL (0.7ms) SELECT name 
FROM sqlite_master 
WHERE type = 'table' AND NOT name = 'sqlite_sequence' 

    User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = 3 LIMIT 1 
    AREL (0.5ms) DELETE FROM "users" WHERE "users"."id" = 3 

Redirected to http://10.0.0.4:3000/users 
Completed 302 Found in 180ms 

您能否向我解釋爲什麼我從來不會在這些請求旁邊發送任何令牌?

回答

9

非常短的版本protect_from_forgery旨在防止來自僞造的HTML FORM元素的XSRF攻擊。 PUT和DELETE不容易受到XSRF攻擊,因爲HTML表單不能使用PUT或DELETE。

XSRF(跨站點請求僞造)攻擊是受害者瀏覽器被誘騙將未經用戶交互的僞造請求提交給服務器。

加長版:你能做到這一點的原因是您:

  • 有需要的任何安全/登錄,或
  • 已經登錄並正在從劇本的要求託管在同一個域上,或者
  • 正在通過Fiddler或類似的方式(繞過瀏覽器的內置保護)發出請求。

這些不是場景protect_from_forgery旨在防範。

protect_from_forgery的目的是防止XSRF攻擊 - 跨站點請求僞造。當用戶訪問一個惡意網站(或者一個惡意的好網站)被誘騙將請求提交給另一個網站時,就會發生這種情況。例如,你可以欺騙訪問者到作出任何GET請求,就像這樣:只要受害者訪問的網站邪惡

<img src="http://victim.com/victimPage?action=delete&id=ID12345" /> 

,他的瀏覽器會自動嘗試檢索圖像。這顯然不會檢索圖像,但同時,victim.com將執行請求刪除項目ID12345。 POST可以以類似的方式僞造,只需創建一個表單,然後使用腳本將其提交給外部站點,或者誘使用戶點擊它來提交。

這就是protect_from_forgery進來的地方:服務器將令牌發送到帶有窗體的隱藏字段中的客戶端。如果沒有出現有效令牌,則服務器得出結論:所提交的表單不是由服務器發送的真正表單的提交,所以該請求被拒絕,因爲可能是僞造的。

但你知道。

問題是HTTP表單只能使用GET和POST方法,而不能使用PUT或DELETE。這有兩個方面的影響:

  • 首先,如果你得到一個PUT或DELETE,無處可放令牌protect_from_forgery。 PUT或DELETE不是表單提交的結果,因此服務器無法將令牌發送給客戶端,因此客戶端沒有令牌可以發回。其次,由於HTML表單只能使用POST和GET,如果請求是PUT或DELETE,攻擊者不能使用HTML表單強制或欺騙用戶提交請求。他們可以使用XMLHttpRequest,但XMLHttpRequest不允許跨站點請求(除非通過兩個站點上的安全設置啓用)。

這意味着,只要你主持它不包含惡代碼本身的域名,這是沒有必要保護PUT和DELETE僞造。如果服務器確實包含惡意代碼,攻擊者可以使任意XMLHttpRequest請求獲得有效的令牌,因此無論如何都很容易規避僞造防護。

對於XSRF的簡短描述試一下: