Rails:在Amazon S3上模糊图像URL? (安全问题)

时间:2010-02-12 07:17:34

标签: ruby-on-rails security amazon-s3

要做一个简短的解释,可以说我的Rails应用程序允许用户将图像上传到他们想要应用程序中的应用程序(意思是,没有热链接)。

所以我试图找到一种方法来混淆图像URL,以便图像的地址取决于该用户是否登录到该网站,所以如果有人尝试热链接到图像,他们会得到401拒绝访问错误。

我在想,如果我可以通过控制器路由请求,我可以重新使用我已经在我的应用程序中构建的许多授权,但是我被困在那里。

我想要的是通过我的某个控制器的URL访问我的图像,例如:

http://railsapp.com/images/obfuscated?member_id=1234&pic_id=7890

如果用户右键点击网站上显示的图像并选择“复制地址”,然后将其输入,则为SAME网址(如同,不会背叛图像实际托管的位置) )。

实际图片将生活在这样的网址上:

http://s3.amazonaws.com/s3username/assets/member_id/pic_id.extension

这有可能实现吗?也许使用Rails'render方法?或者是其他东西?我知道PHP可以返回正确的标题以使浏览器认为它是一个图像,但我不知道如何在Rails中执行此操作...

更新:我希望应用的所有用户能够查看图像,只要他们当前登录到网站。如果用户在站点上没有当前活动的会话,则直接访问图像应该产生通用图像或错误消息。

5 个答案:

答案 0 :(得分:2)

S3允许您为请求构造查询字符串,允许限时下载其他私有对象。您可以为每个用户唯一地生成映像的URL,并使用短暂的超时来防止重用。

请参阅the documentation,查找“查询字符串请求验证替代”部分。我直接链接,但是破坏框架的javascript会阻止它。

答案 1 :(得分:2)

这是当天晚些时候回答,但另一个选择是将文件存储在MongoDB的GridFS中,通过一些需要授权传递的Rack Middleware提供服务。几乎和你一样安全,URL甚至都不需要混淆。

这样做的另一个好处是文件的可用性和系统未来的可扩展性。

答案 2 :(得分:1)

图像是否仅供该用户使用,或者您是否希望将其提供给一组用户(朋友)?

在任何情况下,如果您想停止热链接,您应该将图像文件存储在您的网络服务器的DocumentRoot下。

如果是前者,您可以将图像作为MD5存储在服务器上(image_file_name_as_exposed_to_user + logged_in_username_from_cookie)。当用户请求image_file_name_as_exposed_to_user时,在rails应用程序中,如前所述构造映像文件名,然后在rails app中打开该文件并将其写出(首先在响应头中正确设置Content-Type)。这是安全的设计。

如果图像可以与朋友共享,那么你不应该在构造的文件名中包含用户名,但其他建议应该有效。

答案 3 :(得分:1)

感谢您的回复,但我仍然怀疑是否“超时”亚马逊的网址是一种非常有效的方式。

我已经更新了上面的问题,以便更清楚我正在尝试做什么,并试图阻止。

经过一些实验,我想出了一种在Rails应用程序中做我想做的事情的方法,尽管这个解决方案并非没有缺点。实际上,我所做的是使用指向控制器的URL构建我的image_tag,并获取path参数。该控制器首先测试用户是否有权查看图像,然后在单独的请求中获取图像的内容,并将内容存储在实例中变量,然后传递给repond_to视图以返回图像,成功地模糊了实际图像的URL(因为该请求是单独制作的)。

缺点:

  1. 添加到请求时间(我觉得考虑到这种方法给我的隐私,可以接受执行此双重请求所需的额外时间)
  2. 为视图和路线添加一些混乱(少量,可能比我想要的多一点)
  3. 如果用户已获得授权,并尝试直接访问该图像,则会立即下载该图像,而不是在浏览器中显示(任何人都知道如何修复此问题?修改HTTP标头?仅使用{{1虽然......)
  4. 您必须为要投放的每种文件格式创建单独的视图(两个对我来说,jpgjpg
  5. 使用此方法我是否应该注意其他任何缺点或注意事项?到目前为止,我已经列出了,我可以忍受......

    (重构欢迎。)


    <强> application_controller.rb

    png

    views / application / obfuscate_image.png.haml &amp;的视图/应用/ obfuscate_image.jpg.haml

    class ApplicationController < ActionController::Base
    
      def obfuscate_image
        respond_to do |format|
          if current_user
            format.jpg { @obfuscated_image = fetch_url "http://s3.amazonaws.com/#{Settings.bucket}/#{params[:path]}" }
          else
            format.png { @obfuscated_image = fetch_url "#{root_url}/images/assets/profile/placeholder.png" }
          end
        end
      end
    
      protected
    
      # helps us fetch an image, obfuscated
      def fetch_url(url)
        r = Net::HTTP.get_response(URI.parse(url))
        if r.is_a? Net::HTTPSuccess
          r.body
        else
          nil
        end
      end
    end
    

    <强>的routes.rb

    = @obfuscated_image
    

    <强>到config / environment.rb

    map.obfuscate_image 'obfuscate_image', :controller => 'application', :action => 'obfuscate_image'
    

    调用模糊图像

    Mime::Type.register "image/png", :png
    Mime::Type.register "image/jpg", :jpg
    

答案 4 :(得分:0)

你遇到的问题是,据我所知,你需要S3上的图像是世界可读的才能访问它们。在这个过程中的某个时刻,必须执行HTTP GET才能检索图像,这会将真实的URL暴露给可以嗅探HTTP的工具,例如Firebug。

顺便提一下,37signals认为这不是一个大问题,因为如果我在私人背包帐户中查看图像,我可以在浏览器地址栏中看到公共S3网址。你的里程可能会有所不同......