Hiding table IDs from users

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 5/3/06, Michael J. [email protected] 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.

Jeremy E. 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.)

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

  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])

  1. 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 K. wrote:

It sounds like what you are asking for is to represent each record with a
[email protected]
http://lists.rubyonrails.org/mailman/listinfo/rails

_Kevin

On 5/3/06, Michael J. [email protected] 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

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

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