Ruby on rails 安全回形针URL仅用于安全页面

Ruby on rails 安全回形针URL仅用于安全页面,ruby-on-rails,https,paperclip,secure-scl,Ruby On Rails,Https,Paperclip,Secure Scl,我正试图找到使回形针URL安全的最佳方法,但仅限于安全页面 例如,显示存储在S3中的图像的主页是,图像url是 我有这样的安全页面,在S3中存储了图像,但S3协议是http而不是https,因此用户从浏览器收到警告,说页面上的某些元素不安全,等等等等 我知道我可以在模型中指定:s3_协议,但这使得一切都安全,即使在不需要的时候。因此,我正在寻找最好的方法,将协议动态更改为https,仅用于安全页面 一种(可能是不好的)方法是创建一个新的url方法,如: def custom_url(style

我正试图找到使回形针URL安全的最佳方法,但仅限于安全页面

例如,显示存储在S3中的图像的主页是,图像url是

我有这样的安全页面,在S3中存储了图像,但S3协议是http而不是https,因此用户从浏览器收到警告,说页面上的某些元素不安全,等等等等

我知道我可以在模型中指定:s3_协议,但这使得一切都安全,即使在不需要的时候。因此,我正在寻找最好的方法,将协议动态更改为https,仅用于安全页面

一种(可能是不好的)方法是创建一个新的url方法,如:

def custom_url(style = default_style, ssl = false)
  ssl ? self.url(style).gsub('http', 'https') : self.url(style)
end
需要注意的一点是,我使用的是ssl_需求插件,因此可能有一种方法将其与之结合起来


我确信有一些简单、标准的方法可以做到这一点,但我忽略了,但我似乎找不到它。

如果使用Rails 2.3.x或更高版本,您可以使用Rails中间件在将响应发送回用户之前过滤响应。通过这种方式,您可以检测当前请求是否为HTTPS请求,并相应地修改对s3.amazonaws.com的调用

创建一个名为
曲别针\u s3\u url\u rewriter.rb的新文件,并将其放置在服务器启动时加载的目录中。
lib
direcotry将起作用,但许多人更喜欢创建一个
app/middleware
目录,并将其添加到Rails应用程序加载路径中

将以下类添加到新文件:

class PaperclipS3UrlRewriter
  def initialize(app)
    @app = app
  end

  def call(env)
    status, headers, response = @app.call(env)
    if response.is_a?(ActionController::Response) && response.request.protocol == 'https://' && headers["Content-Type"].include?("text/html")
      body = response.body.gsub('http://s3.amazonaws.com', 'https://s3.amazonaws.com')
      headers["Content-Length"] = body.length.to_s
      [status, headers, body]
    else
      [status, headers, response]
    end
  end
end
然后只需注册新的中间件:

Rails 2.3.x:将下面的行添加到
Rails::Initializer.run
块开头的environment.rb中。
Rails 3.x:将下面的行添加到application类开头的application.rb中

config.middleware.use "PaperclipS3UrlRewriter"
更新:
我刚刚编辑了我的答案,并在if语句中添加了一个检查
response.is_a?(ActionController::response)
。在某些情况下(可能与缓存相关),响应对象是空数组(?),因此在调用
请求时失败

更新2:
我编辑了上面的机架/中间件代码示例,以更新
内容长度
标题。否则,HTML正文将被大多数浏览器截断。

在控制器类中使用以下代码:

# locals/arguments/methods you must define or have available:
#   attachment - the paperclip attachment object, not the ActiveRecord object
#   request - the Rack/ActionController request
AWS::S3::S3Object.url_for \
  attachment.path,
  attachment.options[:bucket].to_s,
  :expires_in => 10.minutes, # only necessary for private buckets
  :use_ssl => request.ssl?

当然,你可以把它很好地包装成一个方法。

如果现在有人无意中发现了这一点:有一个原因!简单地写下:

Paperclip::Attachment.default_options[:s3_protocol] = ""
在初始值设定项中,或在模型中使用
s3\u协议
选项


感谢@Thomas Watson发起了这项工作。

FYI-上面的一些答案不适用于Rails 3+,因为ActionController::Response已被弃用。使用以下命令:

class PaperclipS3UrlRewriter
  def initialize(app)
    @app = app
  end

  def call(env)
    status, headers, response = @app.call(env)
    if response.is_a?(ActionDispatch::BodyProxy) && headers && headers.has_key?("Content-Type") && headers["Content-Type"].include?("text/html")
    body_string = response.body[0]
    response.body[0] = body_string.gsub('http://s3.amazonaws.com', 'https://s3.amazonaws.com')
    headers["Content-Length"] = body_string.length.to_s
    [status, headers, response]
  else
    [status, headers, response]
  end
end
结束

并确保将中间件添加到堆栈中的适当位置(我在Rack::Runtime之后添加了它)


嗨,Shagymoe…我很想知道你的最终解决方案是什么:)回形针github问题:在应用程序服务的每个请求中注入S3 url重写器,而不是首先封装逻辑以生成正确的url,这似乎很不幸。事实上,@Winfield,跨每个响应体计算未绑定正则表达式是向后的。首先,请使用生成正确URL的解决方案。这是现在执行无方案URL的官方方法。请确保您使用的是3.1.4版或更高版本。早期版本有一个错误,其中包括协议冒号,它将中断所有图像链接。另外,升级版本时一定要重新启动服务器。请参阅,这对我使用曲别针3.0.4也有效,将行放入曲别针初始化器中,但不在模型中。感谢您的反馈,@NickEllis。我将等待有人确认,然后在需要时更新答案。
config.middleware.insert_after Rack::Runtime, "PaperclipS3UrlRewriter"