I''m building an application for a company that has thousands of clients, and for each client there will a set of documents that are private to that client. Rails makes it easy, of course, to show the list of documents on a per-client basis, using acts_as_authenticated and using current_user as part of the find any time a document list is displayed. The part for which I''m looking for the best solution is access to the documents themselves. My simple implementation has the Rails view showing a series of links to the files (which are word, excel, and powerpoint documents). The problem is that Rails isn''t involved at all in the actual document delivery, since these static files are served directly from Apache. So anyone who gets, or guesses, the URL can access these files without authentication. I''ve come up with three possible solutions and would appreciate hearing what others have done, and whether there are holes that I''m missing, or another approach I''ve missed. 1. Security by obscurity. Use long random strings for the directory and file names. This is probably secure enough in practice, but certainly isn''t secure in theory and doesn''t feel quite right. 2. Deliver the static files via Rails. Put the documents in a directory tree outside of public and use a Rails action to read the file and deliver it to the browser. This seems like it would be secure, and doesn''t require any Apache configuration, but it would dramatically increase the server load when these files are viewed. I''m not sure whether that would be a real issue or not. 3. Referrer-based blocking in Apache. Set the Apache config to prohibit access to the documents directories if the referrer is not the Rails view that renders the list of files from the database. This seems like potentially the best solution but I''m wondering if there''s any security hole here that I''m missing. One weakness is that some people seem to have their web browser set to not provide a referrer, and those people wouldn''t be able to access the documents. I''d appreciate any suggestions. Michael Slater www.mslater.com --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Hi~ On Jun 10, 2007, at 12:14 PM, Michael Slater wrote:> I''m building an application for a company that has thousands of > clients, and for each client there will a set of documents that are > private to that client. Rails makes it easy, of course, to show the > list of documents on a per-client basis, using > acts_as_authenticated and using current_user as part of the find > any time a document list is displayed. > > The part for which I''m looking for the best solution is access to > the documents themselves. My simple implementation has the Rails > view showing a series of links to the files (which are word, excel, > and powerpoint documents). The problem is that Rails isn''t involved > at all in the actual document delivery, since these static files > are served directly from Apache. So anyone who gets, or guesses, > the URL can access these files without authentication. > > I''ve come up with three possible solutions and would appreciate > hearing what others have done, and whether there are holes that I''m > missing, or another approach I''ve missed. > > 1. Security by obscurity. Use long random strings for the directory > and file names. This is probably secure enough in practice, but > certainly isn''t secure in theory and doesn''t feel quite right.Yeah this is not a satisfactory solution.> > 2. Deliver the static files via Rails. Put the documents in a > directory tree outside of public and use a Rails action to read the > file and deliver it to the browser. This seems like it would be > secure, and doesn''t require any Apache configuration, but it would > dramatically increase the server load when these files are viewed. > I''m not sure whether that would be a real issue or not.You don''t want to do this by reading the whole file in inside rails and then streaming it out, that will skyrocket your memory consumption.> > 3. Referrer-based blocking in Apache. Set the Apache config to > prohibit access to the documents directories if the referrer is not > the Rails view that renders the list of files from the database. > This seems like potentially the best solution but I''m wondering if > there''s any security hole here that I''m missing. One weakness is > that some people seem to have their web browser set to not provide > a referrer, and those people wouldn''t be able to access the documents.This won''t work in all situation so it''s not a viable option either.> > I''d appreciate any suggestions.A few ways to skin this cat. The most efficient way is to use X- Sendfile header with lighttpd or the X-Accell-Redirect feature of nginx. I recommend nginx. THe way this works is that a request for a file goes to your rails app so you can authenticate the request, but all your rails action has to do is set a response header with the path to a file somehwere outside of your publiuc/ dir. THen the front end nginx server will see that header and serve the file directly. Here''s a bit more info: http://blog.kovyrin.net/2006/11/01/nginx-x-accel-redirect-php-rails/ Or you can use a gem called mongrel_secure_download . This is a custom mongrel handler that allows for the same type of thing but all in the same mongrel process. So this doesn''t require interaction with a front end webserver, but it still lets mongrel serve the files fairly fast by streaming them and not reading the whole thing into memory at once. Good luck! Cheers- -- Ezra Zygmuntowicz -- Lead Rails Evangelist -- ez-NLltGlunAUd/unjJdyJNww@public.gmane.org -- Engine Yard, Serious Rails Hosting -- (866) 518-YARD (9273) --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
You could do (and don''t quote me on this as I haven''t used it): def fileserve file = Client.file.find(:first, ....) respond_to |format| format.zip { # send file here, not a link but a real file } end end Sorry for my obscurity in the answer, don''t know how else to explain it. That should work though I reckon. Never used respond_to for anything but rails files though. Cheers, Zach Inglis → Blog -- http://www.zachinglis.com → Company -- http://www.lt3media.com → Portfolio -- http://portfolio.zachinglis.com On Jun 10, 2007, at 2:14 PM, Michael Slater wrote:> I''m building an application for a company that has thousands of > clients, and for each client there will a set of documents that are > private to that client. Rails makes it easy, of course, to show the > list of documents on a per-client basis, using > acts_as_authenticated and using current_user as part of the find > any time a document list is displayed. > > The part for which I''m looking for the best solution is access to > the documents themselves. My simple implementation has the Rails > view showing a series of links to the files (which are word, excel, > and powerpoint documents). The problem is that Rails isn''t involved > at all in the actual document delivery, since these static files > are served directly from Apache. So anyone who gets, or guesses, > the URL can access these files without authentication. > > I''ve come up with three possible solutions and would appreciate > hearing what others have done, and whether there are holes that I''m > missing, or another approach I''ve missed. > > 1. Security by obscurity. Use long random strings for the directory > and file names. This is probably secure enough in practice, but > certainly isn''t secure in theory and doesn''t feel quite right. > > 2. Deliver the static files via Rails. Put the documents in a > directory tree outside of public and use a Rails action to read the > file and deliver it to the browser. This seems like it would be > secure, and doesn''t require any Apache configuration, but it would > dramatically increase the server load when these files are viewed. > I''m not sure whether that would be a real issue or not. > > 3. Referrer-based blocking in Apache. Set the Apache config to > prohibit access to the documents directories if the referrer is not > the Rails view that renders the list of files from the database. > This seems like potentially the best solution but I''m wondering if > there''s any security hole here that I''m missing. One weakness is > that some people seem to have their web browser set to not provide > a referrer, and those people wouldn''t be able to access the documents. > > I''d appreciate any suggestions. > > Michael Slater > www.mslater.com > > >--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
On 6/10/07, Zach Inglis // LT3media <lists-w8tEHcFK2X5Wk0Htik3J/w@public.gmane.org> wrote:> > You could do (and don''t quote me on this as I haven''t used it): > > def fileserve > file = Client.file.find(:first, ....) > respond_to |format| > format.zip { > # send file here, not a link but a real file > } > end > end > > Sorry for my obscurity in the answer, don''t know how else to explain it. > > That should work though I reckon. Never used respond_to for anything but > rails files though.That''ll lead to high memory usage, depending on the sizes of the files. In general, I''d stay away from send_data or the send_file methods. I''ve seen mongrel sizes over 1GB from serving files up to 200MB. I switched it to a heavily modified mongrel_secure_download handler and all was right in the world. So in general, do as Ezra said :) -- Rick Olson http://lighthouseapp.com http://weblog.techno-weenie.net http://mephistoblog.com --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
I''d definitely use x_sendfile per Ezra. He neglects to mention that Apache also supports this, via mod_xsendfile: http://tn123.ath.cx/mod_xsendfile/ I use this for exactly the reasons you describe. Note, however, that you must be running Apache2, and your Apache must be compiled to support DSOs (I believe all Apache2 standard installs do support this). This further implies that you must control the server, which it seems you do. -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Thanks everyone for your suggestions. I''m running at Rails Machine and would like to stick with their standard stack, which includes Apache 2.2, so it sounds like mod_xsendfile is the way to go. Michael www.mslater.com On Jun 11, 7:48 pm, Brian Ablaza <rails-mailing-l...-ARtvInVfO7ksV2N9l4h3zg@public.gmane.org> wrote:> I''d definitely use x_sendfile per Ezra. He neglects to mention that > Apache also supports this, via mod_xsendfile: > > http://tn123.ath.cx/mod_xsendfile/ > > I use this for exactly the reasons you describe. > > Note, however, that you must be running Apache2, and your Apache must be > compiled to support DSOs (I believe all Apache2 standard installs do > support this). This further implies that you must control the server, > which it seems you do. > > -- > Posted viahttp://www.ruby-forum.com/.--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
Forgot to mention that there''s a plug-in to make life easier: http://john.guen.in/rdoc/x_send_file/ -- Posted via http://www.ruby-forum.com/. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---