在徽章系统的Rails 5中保留eval的条目

时间:2017-03-07 14:16:14

标签: ruby-on-rails ruby ruby-on-rails-5

我目前正在为Ruby on Rails 5应用程序开发客户端徽章系统。我不想将每个徽章硬编码到系统中,我发现eval()是一种带有危险后果的方法。

这是我目前的策略:

应用程序/模型/ user.rb

class User
  has_many :awards, dependent: :destroy
end

应用程序/模型/ badge.rb

class Badge
  has_many :awards, dependent: :destroy

  # name        - string - Name of the badge
  # icon        - string - URL of badge icon
  # description - text   - Long text description of the badge
  # criterion   - text   - boolean operation to eval() to earn badge
end 

应用程序/模型/ award.rb

class Award
  belongs_to :user
  belongs_to :badge

  def self.automatic_award
    User.find_each do |user|
      Badge.find_each do |badge|
        # If the badge has not been awarded to the user
        if Award.where(user: user, badge: badge).blank?
          # If the badge criteria is met
          if eval(badge.criterion.untaint)
            Award.create(user: user, badge: badge)
            # Add method to notify user of award.
          end
        end
      end
    end
  end 

end

我会写一个工人定期运行Award.automatic_award方法(每10分钟一次?)这些徽章将由管理员在登录安全性(非标准用户)后面编写但我担心安全性和污点条目。

我错过了什么?还有更好的方法吗?

2 个答案:

答案 0 :(得分:0)

我认为将代码存储在数据库中并允许管理员维护它是一种极其危险的做法。它可以在您的服务器上运行任何内容,并绕过部署可执行代码的最佳实践,即暂存和测试它。

我会尝试将徽章需要做的事情分解为可以更好地封装为数据的内容,例如:规则引擎或特定于域的语言类型框架,您可以更自信地验证输入并限制其行为。

答案 1 :(得分:0)

显然,您会看到此方法背后的安全问题,但为了清楚起见,某人(管理员或有权访问编辑徽章标准的人)可以编写类似User.delete_all的内容。你相信管理员那么多吗?

我看到这种方法的其他问题(将代码保存在数据库中):

  • 您将如何测试标准代码?
  • 该标准代码没有版本控制
  • 只是邀请生产环境中发生的错误,您无法在本地重现。你怎么知道管理员会写一些成功执行的东西?

从给出的示例中很难猜出这些标准是什么样的,但我会将代码放在项目源中,即使它意味着为每个徽章编码。我不希望管理员知道如何正确地执行它,除非他们是开发人员,如果他们没有理由不明确地实施项目来源的标准。

如果你真的需要灵活,你最好设计一些“相对简单的语言”,比如说:comments > 4 && last_login > 3 days。并允许预定义的一组“变量”commesnts, last_login,预定义的谓词集<, >=, =等等。但是这样的事情并不简单,商业价值需要证明实施成本。