Безопасные ссылки на скрепки только для защищенных страниц - PullRequest
11 голосов
/ 22 сентября 2010

Я пытаюсь найти лучший способ сделать URL-адреса скрепок безопасными, но только для защищенных страниц.

Например, домашняя страница, на которой отображаются изображения, хранящиеся в 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, так что, возможно, есть способ связать его с этим.

Я уверен, что есть какой-то простой, стандартный способчтобы сделать это, что я пропускаю, но я не могу найти это.

Ответы [ 4 ]

17 голосов
/ 14 июня 2012

Если кто-то наткнется на это сейчас: в Paperclip есть решение *1002*, начиная с Апрель 2012 !Просто напишите:

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

в инициализаторе или используйте параметр s3_protocol внутри вашей модели.

Спасибо @Thomas Watson за инициацию этого.

7 голосов
/ 05 января 2011

Если вы используете Rails 2.3.x или новее, вы можете использовать промежуточное программное обеспечение Rails для фильтрации ответа перед его отправкой обратно пользователю.Таким образом, вы можете определить, является ли текущий запрос запросом HTTPS, и соответственно изменить вызовы к s3.amazonaws.com.

Создайте новый файл с именем paperclip_s3_url_rewriter.rb и поместите его в каталог, который загружается, когда серверначинается.Direcotry 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.rb в начале класса Application.

config.middleware.use "PaperclipS3UrlRewriter"

ОБНОВЛЕНИЕ:
Я только что отредактировал свой ответ и добавил проверку для response.is_a?(ActionController::Response) в операторе if.В некоторых случаях (возможно, связанных с кэшированием) объект ответа является пустым массивом (?), И поэтому происходит сбой при вызове request.

ОБНОВЛЕНИЕ 2: Я редактировал Rack /Приведенный выше пример кода промежуточного программного обеспечения также обновляет заголовок Content-Length.В противном случае тело HTML будет обрезано большинством браузеров.

1 голос
/ 05 января 2011

Используйте следующий код в классе контроллера:

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

Вы, конечно, можете красиво обернуть это в метод.

0 голосов
/ 20 февраля 2014

К вашему сведению - некоторые из приведенных выше ответов не работают с 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" 
...