要做一个简短的解释,可以说我的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中执行此操作...
更新:我希望应用的所有用户能够查看图像,只要他们当前登录到网站。如果用户在站点上没有当前活动的会话,则直接访问图像应该产生通用图像或错误消息。
答案 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(因为该请求是单独制作的)。
缺点:
jpg
和jpg
)使用此方法我是否应该注意其他任何缺点或注意事项?到目前为止,我已经列出了,我可以忍受......
(重构欢迎。)
<强> 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网址。你的里程可能会有所不同......