2010-09-22 63 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"