You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Ruby on Rails 6.1中从数据库获取Active Storage变体选项的最佳方案及安全疑问

替代eval的安全方案与$SAFE使用建议

你说得太对了——在用户可控的输入上使用eval极度危险的操作,哪怕加上$SAFE也不是稳妥的解决方案。下面给你几个更安全、更符合Rails最佳实践的替代方案,以及关于$SAFE的明确建议:

方案1:使用Rails序列化哈希(首推)

Rails原生支持将哈希序列化存储到数据库的text字段中,完全不需要手动解析或执行代码,既安全又省心:

1. 更新Slideshow模型

# app/models/slideshow.rb
class Slideshow < ApplicationRecord
  # 自动将options字段序列化为Hash,读取时直接返回哈希对象
  serialize :options, Hash

  # 设置默认值,避免nil导致的错误
  def options
    super || { resize_to_limit: [300, 222], kuwahara: '3%' }
  end
end

2. 优化Admin表单

把用户输入改成JSON格式(比Ruby哈希更通用且易解析),避免用户输入Ruby语法带来的风险:

# app/admin/slideshow.rb
form do |f|
  f.inputs 'Slideshow' do
    f.input :name
    f.input :options, 
            as: :text, 
            input_html: { value: f.object.options.to_json, rows: 3 },
            label: '配置选项(JSON格式)示例:{"resize_to_limit": [300, 222], "monochrome": true}'
    f.input :images, as: :file, input_html: { multiple: true }
  end
  f.actions
end

3. 简化控制器代码

直接读取模型返回的哈希即可,彻底告别eval

# app/controllers/slideshow_controllers.rb
def options
  @options = slideshow&.options || { resize_to_limit: [300, 222], kuwahara: '3%' }
end

def slideshow
  Slideshow.published.take
end

这样用户输入的JSON会被自动转换成Ruby哈希,Active Storage的variant方法可以直接使用这个哈希参数,完全没有代码注入的风险。

方案2:白名单验证(适合复杂场景)

如果业务需要更灵活的配置,可以提前定义允许的处理器和参数,只解析白名单内的内容。比如:

# 示例:只允许指定的图像处理方法
ALLOWED_TRANSFORMS = %i[resize_to_limit kuwahara monochrome].freeze

def parse_options(raw_options)
  # 先解析成哈希
  parsed = JSON.parse(raw_options)
  # 只保留白名单内的键,转换为符号键
  parsed.slice(*ALLOWED_TRANSFORMS.map(&:to_s)).transform_keys(&:to_sym)
rescue JSON::ParserError
  # 解析失败返回默认配置
  { resize_to_limit: [300, 222], kuwahara: '3%' }
end

但这个方案比序列化哈希复杂,除非有特殊需求,否则首推方案1。


关于$SAFE的明确建议

绝对不建议使用$SAFE:这个特性在Ruby 2.7版本已经被正式废弃,而且它的安全模型设计老旧,无法抵御现代的代码注入攻击。即使设置了$SAFE = 1,也不能完全阻止恶意代码执行,反而会让代码变得晦涩且难以维护。

正确的安全思路是从根源上避免执行用户输入的代码,用序列化、JSON解析或白名单验证的方式处理配置,彻底消除代码注入的风险。


内容的提问来源于stack exchange,提问作者Alex

火山引擎 最新活动