I was wondering if anyone had thoughts on the most efficient way of making sure users never see internal table IDs? Clearly, scaffold views show a lot of IDs by default and those can be hidden. The problem seems to be all of the IDs that Rails passes around in URLs (such as http://mysite.com/user/show/12345). My primary concerns are security and confidentiality--one can imagine that there are exploits that could involve knowledge about ID numbers or simply guessing random table row IDs and putting them into URLs to see what happens. Combined with a few coding mistakes this could lead to a catastrophic security/privacy breakdown. I'm also concerned about the ability of clever people to discern how how much activity/signups a commercial web site is getting by looking at auto-incremented ID numbers that are assigned to various signups/posts/etc (various schemes for implementing non-sequential IDs all seem kludgy and inefficient to me, but willing to be corrected as always). Surely I can't be the first person to ponder this issue. Any thoughts at all are appreciated. Mike J.
on 2006-05-03 19:14
on 2006-05-03 19:39
On 5/3/06, Michael Johnson <firstname.lastname@example.org> wrote: > catastrophic security/privacy breakdown. I'm also concerned about the > ability of clever people to discern how how much activity/signups a > commercial web site is getting by looking at auto-incremented ID numbers > that are assigned to various signups/posts/etc (various schemes for > implementing non-sequential IDs all seem kludgy and inefficient to me, > but willing to be corrected as always). If the page isn't public information, include an authorization routine in a before filter. Usually you would do this by having the user login, storing information in the session, and checking the session information in the before filter. That way users can only see the information that they should have access to.
on 2006-05-03 20:46
Jeremy Evans wrote: > information that they should have access to. Sorry, I did a weak job of explaining myself. I'm not trying to protect pages--I'm already using the SaltedHashLoginGenerator and filtering so users can only get to information that belongs to them. My issue is that I don't ever want users to see internal table ID column values. E.g. I never want to see URLs like: http://mysite/user/new?referred_by_user=27 http://mysite/order/show/113 A sneaky user could determine approximately how many orders my client company is generating per day by making an order in the morning, making an order in the evening, then subtracting the order_id numbers (assuming the database is using standard auto-increment IDs). And if some programmer on my project accidentally fails to filter the orders so each user can only see their own, then someone could easily start typing in http://mysite/order/show/114, /115, /116, etc. and see whatever they like. So for this example one solution would be to generate a complex and unique order number that is hard to guess and have the URL go to that instead (e.g., http://mysite/order/show/ax53nmfjw2312343k2 -- let's not have a discussion about how you could still employ a brute-force attack to guess valid numbers, etc). That one specific example probably has a really, really simple answer (I'm still a noob so please do tell--save me the ten minutes it will take to figure it out!) but I was hoping anyone had comments on preventing all such exposed table ID usage application-wide that doesn't require a lot of extra work and/or making sure every programmer understands a bunch of conventions that aren't reflected in the code in some way. I'm really hoping not to have to cobble together a random ID generating scheme of some sort because I find those to be problematic (how does a support staffer adding a data record manually generate a random ID? How does the guy writing a Perl script get an ID? More work, more cost, every time someone needs to touch a table.)
on 2006-05-03 21:05
Hi, What your urls look like is defined in the file routes.rb. The default configuration is :controller/:action/:id . Feel free to change this to whatever suits your needs. It can be :controller/:action/:hashed_id, and the action will receive a hased_id it can decode. You also can remove the controller and action if you can figure out what they are from the string returned by the user. Hope this helps, Nicolas
on 2006-05-03 21:23
On 5/3/06, Michael Johnson <email@example.com> wrote: > > I'm really hoping not to have to cobble together a random ID > generating scheme of some sort because I find those to be problematic > (how does a support staffer adding a data record manually generate a > random ID? How does the guy writing a Perl script get an ID? More work, > more cost, every time someone needs to touch a table.) It sounds like what you are asking for is to represent each record with a GUID. There is a plugin that will let you accomplish this which follows an industry standard way of creating unique identifiers (thus solving your perl script problem described above). See reference below: http://wiki.rubyonrails.com/rails/pages/Uses+Guid+Plugin
on 2006-05-03 21:51
1. You could also probably do some sneaky routing to get the ID numbers in the URL to refer to the order number of the current user. That way all they would see is how many order they have placed. something like... order belongs_to :customer order acts_as_list then do @order = Order.find_by_position(params[:position], :conditions=>["customer_id = ?", params[:customer_id]) 2. You can't get away from having to be careful about checking to see if the user has authorized access to the particular record. On Wednesday, May 03, 2006, at 12:20 PM, Josh Knowles wrote: >It sounds like what you are asking for is to represent each record with a >Rails@lists.rubyonrails.org >http://lists.rubyonrails.org/mailman/listinfo/rails > _Kevin
on 2006-05-04 06:55
Nice idea Nicolas, thanks -- any idea if there is some way of centralizing the hashed ID handling so it's completely automatic instead of forcing each and every action to unravel the IDs? Something like forcing the request to go to a controller that can unhash the ID then redirect to where you wanted to go originally. Mike
on 2006-05-04 07:05
Josh, the GUID plugin is a great find--thanks much for the pointer. The only reason I would balk at using GUIDs is because you can no longer just go into a database table and stick a record in manually--everything has to be done through a tool of some sort. That being said you could cobble together a script for that in minutes so not a major drawback. Ever wonder why MySQL doesn't have an automatic GUID column or a auto-random field? Sheesh. I suppose I could just switch to a database that has something like that. Mike