2012-06-27 58 views
2

RailsCast 219,下面的代碼是提供用於創建數據運送從形式來回一類,但沒有任何ActiveRecord的持久性:ActiveModel:危險使用send()?

class Message 
    include ActiveModel::Validations 

    attr_accessor :name, :email, :content 

    validates_presence_of :name 
    validates_format_of :email, :with => /^[-a-z0-9_+\.]+\@([-a-z0-9]+\.)+[a-z0-9]{2,4}$/i 
    validates_length_of :content, :maximum => 500 

    def initialize(attributes = {}) 
    attributes.each do |name, value| 
     send("#{name}=", value) 
    end 
    end 
end 

我是新來的Ruby,但send("#{name}=", value)好像邀請對於攻擊者 將任意值賦給任意字段。這是一個問題嗎?一些評論者詢問similar questions,但沒有迴應。

+0

這裏的保護:http://api.rubyonrails.org/classes/ActiveModel/MassAssignmentSecurity/ClassMethods.html#method-i-attr_accessible – jdoe

回答

1

當我問有關同一RailsCast一個question最近,被告知初始化劑是危險的,但遺憾的是沒有給出理由。

經過深入研究,我現在認爲,並不是,因爲jdoe在你的問題的評論中隱瞞的原因而引入了安全漏洞。 send方法不會繞過訪問器方法,因此屬性的安全性通常由訪問器聲明來控制。

但是,我會推薦一個驗證檢查以提高健壯性,以防止嘗試分配不可訪問或不存在的屬性。類似Sergio的建議,但更普遍的:

attributes.each do |name, value| 
    send("#{name}=", value) if respond_to?("#{name}=") 
end 
+0

如果類不包含任何不應該從外部設置的內部狀態(因爲數據傳輸對象可能是這種情況),那麼測試'respond_to?'是沒有問題的。但是,如果它有內部設置者,則需要將可批量分配的屬性列入白名單。 –

3

send是動態調用方法的常用方法(當您事先不知道您將調用什麼時)。

如果您擔心安全問題,那麼您絕對應該進行一些驗證。這裏有一個簡單的限制檢查:

def initialize(attributes = {}) 
    attributes.each do |name, value| 
    if [:name, :email, :content].include?(name) 
     send("#{name}=", value) 
    end 
    end 
end 
+0

我明白了什麼是送做。我的問題是:執行Rasilscast所建議的內容是否危險?沒有額外的代碼來防止分配給任意字段? Rails中是否有某種方式默認安全?謝謝你的時間。 –

+0

不,默認情況下它不安全。 –