我目前正在为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分钟一次?)这些徽章将由管理员在登录安全性(非标准用户)后面编写但我担心安全性和污点条目。
我错过了什么?还有更好的方法吗?
答案 0 :(得分:0)
我认为将代码存储在数据库中并允许管理员维护它是一种极其危险的做法。它可以在您的服务器上运行任何内容,并绕过部署可执行代码的最佳实践,即暂存和测试它。
我会尝试将徽章需要做的事情分解为可以更好地封装为数据的内容,例如:规则引擎或特定于域的语言类型框架,您可以更自信地验证输入并限制其行为。
答案 1 :(得分:0)
显然,您会看到此方法背后的安全问题,但为了清楚起见,某人(管理员或有权访问编辑徽章标准的人)可以编写类似User.delete_all
的内容。你相信管理员那么多吗?
我看到这种方法的其他问题(将代码保存在数据库中):
从给出的示例中很难猜出这些标准是什么样的,但我会将代码放在项目源中,即使它意味着为每个徽章编码。我不希望管理员知道如何正确地执行它,除非他们是开发人员,如果他们没有理由不明确地实施项目来源的标准。
如果你真的需要灵活,你最好设计一些“相对简单的语言”,比如说:comments > 4 && last_login > 3 days
。并允许预定义的一组“变量”commesnts, last_login
,预定义的谓词集<, >=, =
等等。但是这样的事情并不简单,商业价值需要证明实施成本。