【问题标题】:Secure paperclip urls only for secure pages仅用于安全页面的安全回形针 URL
【发布时间】:2014-02-20 15:50:07
【问题描述】:

我正在努力寻找使回形针网址安全的最佳方法,但仅限于安全页面。

例如,显示存储在 S3 中的图像的主页是 http://mydomain.com,而图像 url 是 http://s3.amazonaws.com/mydomainphotos/89/thisimage.JPG?1284314856

我有像https://mydomain.com/users/my_stuff/49 这样的安全页面,它的图像存储在 S3 中,但 S3 协议是 http 而不是 https,所以用户会从浏览器收到警告,说页面上的某些元素不安全,等等等等废话。

我知道我可以在模型中指定 :s3_protocol,但这可以确保一切安全,即使在不必要时也是如此。因此,我正在寻找将协议即时更改为 https 的最佳方式,仅适用于安全页面。

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

def custom_url(style = default_style, ssl = false)
  ssl ? self.url(style).gsub('http', 'https') : self.url(style)
end

需要注意的一点是,我正在使用 ssl_requirement 插件,因此可能有一种方法可以将其与它联系起来。

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

【问题讨论】:

标签: ruby-on-rails https paperclip secure-scl


【解决方案1】:

如果现在有人偶然发现:自从April 2012 以来就有一个solution in Paperclip!简单写:

Paperclip::Attachment.default_options[:s3_protocol] = ""

在初始化程序中或在模型中使用 s3_protocol 选项。

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

【讨论】:

  • 这是现在做无模式 URL 的官方方法。
  • 确保您使用的是 3.1.4 或更高版本。早期版本有一个错误,其中包括协议冒号,这将破坏您的所有图像链接。另外,升级版本时一定要重启你的服务器。
  • 这对我使用回形针 3.0.4 有效,将线放在回形​​针初始化器中,但不在模型中。
  • 感谢您的反馈,@NickEllis。我会等待有人确认,如果需要,我会更新答案。
【解决方案2】:

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

创建一个名为paperclip_s3_url_rewriter.rb 的新文件并将其放在服务器启动时加载的目录中。 lib 目录可以工作,但许多人更喜欢创建一个 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:将下面的行添加到 environment.rb 的 Rails::Initializer.run 块的开头。
Rails 3.x:在 Application 类开头的 application.rb 中添加以下行。

config.middleware.use "PaperclipS3UrlRewriter"

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

更新 2: 我编辑了上面的机架/中间件代码示例来更新Content-Length 标头。否则 HTML 正文将被大多数浏览器截断。

【讨论】:

  • 不幸的是,将 S3 url-rewriter 注入到您的应用程序服务的每个请求中,而不是首先封装逻辑以生成正确的 URL。
  • 确实@Winfield,在每个响应正文中评估未绑定的正则表达式是倒退的。使用首先生成正确 URL 的解决方案。
【解决方案3】:

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

# 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?

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

【讨论】:

    【解决方案4】:

    仅供参考 - 上面的一些答案不适用于 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 之后添加了它)

    config.middleware.insert_after Rack::Runtime, "PaperclipS3UrlRewriter" 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-01-23
      • 2015-10-10
      • 1970-01-01
      • 2011-02-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多