仅适用于安全页面的安全回形针 URL

发布于 2024-09-24 23:00:48 字数 900 浏览 1 评论 0原文

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

例如,显示存储在 S3 中的图像的主页为 http://mydomain.com,图像 url 为 < a href="http://s3.amazonaws.com/mydomainphotos/89/thisimage.JPG?1284314856" rel="noreferrer">http://s3.amazonaws.com/mydomainphotos/89/thisimage.JPG?1284314856< /a>.

我有像 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 插件,因此可能有一种方法可以将其与该插件结合起来。

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

I'm trying to find the best way to make paperclip urls secure, but only for secure pages.

For instance, the homepage, which shows images stored in S3, is http://mydomain.com and the image url is http://s3.amazonaws.com/mydomainphotos/89/thisimage.JPG?1284314856.

I have secure pages like https://mydomain.com/users/my_stuff/49 that has images stored in S3, but the S3 protocol is http and not https, so the user gets a warning from the browser saying that some elements on the page are not secure, blah blah blah.

I know that I can specify :s3_protocol in the model, but this makes everything secure even when it isn't necessary. So, I'm looking for the best way to change the protocol to https on the fly, only for secure pages.

One (probably bad) way would be to create a new url method like:

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

One thing to note is that I'm using the ssl_requirement plugin, so there might be a way to tie it in with that.

I'm sure there is some simple, standard way to do this that I'm overlooking, but I can't seem to find it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

智商已欠费 2024-10-01 23:00:48

如果现在有人偶然发现这一点:自从 2012 年 4 月!只需在初始化程序中编写:

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

或在模型中使用 s3_protocol 选项。

感谢@Thomas Watson 发起此活动。

If anyone stumbles upon this now: There is a solution in Paperclip since April 2012! Simply write:

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

in an initializer or use the s3_protocol option inside your model.

Thanks to @Thomas Watson for initiating this.

橘香 2024-10-01 23:00:48

如果使用 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:将下面的行添加到 Rails::Initializer.run 块开头的environment.rb中。< br>
Rails 3.x:将以下行添加到 Application 类开头的 application.rb 中。

config.middleware.use "PaperclipS3UrlRewriter"

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

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

If using Rails 2.3.x or newer, you can use Rails middleware to filter the response before sending it back to the user. This way you can detect if the current request is an HTTPS request and modify the calls to s3.amazonaws.com accordingly.

Create a new file called paperclip_s3_url_rewriter.rb and place it inside a directory that's loaded when the server starts. The lib direcotry will work, but many prefer to create an app/middleware directory and add this to the Rails application load path.

Add the following class to the new file:

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

Then just register the new middleware:

Rails 2.3.x: Add the line below to environment.rb in the beginning of the Rails::Initializer.run block.
Rails 3.x: Add the line below to application.rb in the beginning of the Application class.

config.middleware.use "PaperclipS3UrlRewriter"

UPDATE:
I just edited my answer and added a check for response.is_a?(ActionController::Response) in the if statement. In some cases (maybe caching related) the response object is an empty array(?) and hence fails when request is called upon it.

UPDATE 2:
I edited the Rack/Middleware code example above to also update the Content-Length header. Otherwise the HTML body will be truncated by most browsers.

罪歌 2024-10-01 23:00:48

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

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

您当然可以将其很好地包装到方法中。

Use the following code in a controller class:

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

You can of course wrap this up nicely into a method.

糖果控 2024-10-01 23:00:48

仅供参考 - 上面的一些答案不适用于 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

end

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

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

FYI - some of the answers above do not work with Rails 3+, because ActionController::Response has been deprecated. Use the following:

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

end

And make sure that you add the middleware in a good place in the stack (I added it after Rack::Runtime)

config.middleware.insert_after Rack::Runtime, "PaperclipS3UrlRewriter" 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文