2010-09-22 315 views
9

我试图找到使回形针网址安全的最佳方式,但仅限于安全网页。安全的回形针网址只适用于安全网页

例如,显示存储在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插件,所以有可能是配合它的方式在那。

我确定有一些简单的标准方法来做到这一点,我忽略了,但我似乎无法找到它。

+0

Shagymoe喜(我机架::运行后添加的话)。 ..我很感兴趣,知道哪个是你的最终解决方案:) – zetarun 2011-09-29 15:48:42

+0

回形针github问题在这里:https://github.com/thoughtbot/paperclip/issues/387 – swrobel 2012-03-01 00:55:58

回答

7

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

创建一个名为paperclip_s3_url_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" 

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

更新2: 我编辑的机架/中间件的代码示例以上同时更新Content-Length报头。否则,HTML主体将被大多数浏览器截断。

+3

这似乎是不幸的注入一个S3 url-rewriter到每单一请求您的应用程序服务而不是将逻辑封装到g首先填入正确的URL。 – Winfield 2011-10-26 17:22:50

+0

的确,@Winfield的评估跨每个响应主体的未绑定正则表达式都是向后的。使用首先生成正确URL的解决方案。 – Mars 2015-08-10 17:01:41

1

使用下面的代码,在控制器类:

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

当然你也可以很好地包裹这一成的方法。

14

如果有人绊倒现在:有一个solution in PaperclipApril 2012!简单地写:

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

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

感谢@托马斯沃森发起这一点。

+0

这是现在执行无计划网址的官方方式。 – Karew 2012-10-10 14:29:44

+1

确保您使用的是3.1.4或更高版本。早期版本有一个包含协议冒号的错误,这会破坏所有的图片链接。另外,请确保在升级版本时重新启动服务器。 – vansan 2013-07-30 18:28:50

+0

另请参阅http://www.rubydoc.info/github/thoughtbot/paperclip/Paperclip/Storage/S3 – 2014-11-20 13:37:40

0

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

,并确保你在在堆栈的好地方添加中间件

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