# Hiding table IDs from users

**URL:** <https://www.ruby-forum.com/t/hiding-table-ids-from-users/59517>\
**Category:** Rails\
**Created:** [May 3, 2006, 7:14pm UTC](https://www.ruby-forum.com/t/hiding-table-ids-from-users/59517 "2006-05-03T19:14:22Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![bluetrust](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/8e7dd6/32.png) [@bluetrust](https://www.ruby-forum.com/u/bluetrust)\
**Post date:** [May 3, 2006, 7:14pm UTC](https://www.ruby-forum.com/t/hiding-table-ids-from-users/59517/1 "2006-05-03T19:14:22Z")

</div>

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](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.

---

<div class="post-metadata">

**Author:** ![bluetrust](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/8e7dd6/32.png) [@bluetrust](https://www.ruby-forum.com/u/bluetrust)\
**Post date:** [May 3, 2006, 7:39pm UTC](https://www.ruby-forum.com/t/hiding-table-ids-from-users/59517/2 "2006-05-03T19:39:04Z")

</div>

On 5/3/06, Michael J. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) 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.

---

<div class="post-metadata">

**Author:** ![bluetrust](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/8e7dd6/32.png) [@bluetrust](https://www.ruby-forum.com/u/bluetrust)\
**Post date:** [May 3, 2006, 8:46pm UTC](https://www.ruby-forum.com/t/hiding-table-ids-from-users/59517/3 "2006-05-03T20:46:41Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![bluetrust](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/8e7dd6/32.png) [@bluetrust](https://www.ruby-forum.com/u/bluetrust)\
**Post date:** [May 3, 2006, 9:05pm UTC](https://www.ruby-forum.com/t/hiding-table-ids-from-users/59517/4 "2006-05-03T21:05:14Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![bluetrust](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/8e7dd6/32.png) [@bluetrust](https://www.ruby-forum.com/u/bluetrust)\
**Post date:** [May 3, 2006, 9:51pm UTC](https://www.ruby-forum.com/t/hiding-table-ids-from-users/59517/5 "2006-05-03T21:51:30Z")

</div>

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  
> removed\_email\_address@domain.invalid  
> [http://lists.rubyonrails.org/mailman/listinfo/rails](http://lists.rubyonrails.org/mailman/listinfo/rails)

\_Kevin

---

<div class="post-metadata">

**Author:** ![bluetrust](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/8e7dd6/32.png) [@bluetrust](https://www.ruby-forum.com/u/bluetrust)\
**Post date:** [May 3, 2006, 9:23pm UTC](https://www.ruby-forum.com/t/hiding-table-ids-from-users/59517/6 "2006-05-03T21:23:44Z")

</div>

On 5/3/06, Michael J. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) 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](http://wiki.rubyonrails.com/rails/pages/Uses+Guid+Plugin)

---

<div class="post-metadata">

**Author:** ![bluetrust](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/8e7dd6/32.png) [@bluetrust](https://www.ruby-forum.com/u/bluetrust)\
**Post date:** [May 4, 2006, 7:05am UTC](https://www.ruby-forum.com/t/hiding-table-ids-from-users/59517/7 "2006-05-04T07:05:08Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![bluetrust](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/8e7dd6/32.png) [@bluetrust](https://www.ruby-forum.com/u/bluetrust)\
**Post date:** [May 4, 2006, 6:55am UTC](https://www.ruby-forum.com/t/hiding-table-ids-from-users/59517/8 "2006-05-04T06:55:55Z")

</div>

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
