【问题标题】:ActiveModel: dangerous use of send()?ActiveModel:危险使用 send()?
【发布时间】:2012-06-27 14:42:13
【问题描述】:

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

【问题讨论】:

标签: ruby-on-rails ruby ruby-on-rails-3 activemodel


【解决方案1】:

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

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

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

【讨论】:

  • 我了解 send 的作用。我的问题是:如果没有额外的代码来防止分配给任意字段,那么执行 Rasilscast 的建议是否危险? Rails 中是否有一些东西可以在默认情况下以某种方式使其安全?感谢您的宝贵时间。
  • 不,默认情况下不安全。
【解决方案2】:

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

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

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

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

【讨论】:

  • 测试respond_to? 很好,前提是该类不包含任何不应从外部设置的内部状态(因为它可能是数据传输对象的情况)。但是,如果它具有内部设置器,则需要将可批量分配的属性列入白名单。
猜你喜欢
  • 2018-10-17
  • 1970-01-01
  • 1970-01-01
  • 2021-07-24
  • 1970-01-01
  • 2013-03-21
  • 2018-09-04
  • 2017-12-25
  • 2021-12-01
相关资源
最近更新 更多