2

RailsCast 219中,提供了以下代码来创建一个用于从表单来回传送数据的类,但没有任何 ActiveRecord 持久性:

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)似乎是在邀请攻击者将任意值分配给任意字段。这是一个问题吗?一些评论者提出了类似的问题,但没有回应。

4

2 回答 2

3

send是动态调用方法的常用方式(当您事先不知道要调用什么时)。

如果您担心安全性,则绝对应该进行一些验证。这是一个简单的限制检查:

def initialize(attributes = {})
  attributes.each do |name, value|
    if [:name, :email, :content].include?(name)
      send("#{name}=", value)
    end
  end
end
于 2012-06-27T14:52:03.400 回答
1

当我最近问了一个与同一个 RailsCast 相关的问题时,被告知初始化程序很危险,但遗憾的是没有给出任何理由。

经过更深入的研究,我现在认为该方法不会引入任何安全漏洞,原因是 jdoe 在对您的问题的评论中没有提到。send 方法不会绕过访问器方法,因此属性的安全性通常由访问器声明控制。

但是,我建议进行验证检查,以提高针对尝试分配不可访问或不存在的属性的鲁棒性。类似于 Sergio 的建议,但更笼统:

attributes.each do |name, value|
  send("#{name}=", value) if respond_to?("#{name}=")
end
于 2013-06-13T12:42:33.627 回答