Forum: Ruby on Rails hiding table IDs from users

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
D809b34a8a8aab62eb18b11ec8a82b18?d=identicon&s=25 Michael Johnson (Guest)
on 2006-05-03 19:14
(Received via mailing list)
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.
58c44a4a506d878f9a112f1d7b7cb87e?d=identicon&s=25 Jeremy Evans (Guest)
on 2006-05-03 19:39
(Received via mailing list)
On 5/3/06, Michael Johnson <none@plzdontspam.us> 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.
D809b34a8a8aab62eb18b11ec8a82b18?d=identicon&s=25 Michael Johnson (Guest)
on 2006-05-03 20:46
(Received via mailing list)
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.)
C29d9db03853958c4de5ee6b06edd39a?d=identicon&s=25 Nicolas Buet (Guest)
on 2006-05-03 21:05
(Received via mailing list)
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
57e939ff00f9df2670a09f417c08da5e?d=identicon&s=25 Josh Knowles (Guest)
on 2006-05-03 21:23
(Received via mailing list)
On 5/3/06, Michael Johnson <none@plzdontspam.us> 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
5d15c6821f3c3054c04b85471824ba7c?d=identicon&s=25 Kevin Olbrich (Guest)
on 2006-05-03 21:51
(Received via mailing list)
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
D809b34a8a8aab62eb18b11ec8a82b18?d=identicon&s=25 Mike J. (Guest)
on 2006-05-04 06:55
(Received via mailing list)
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
D809b34a8a8aab62eb18b11ec8a82b18?d=identicon&s=25 Mike J. (Guest)
on 2006-05-04 07:05
(Received via mailing list)
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
This topic is locked and can not be replied to.