Encrpting urls to hide PKs

2,441 views
Skip to first unread message

ALJ

unread,
May 9, 2011, 8:24:03 AM5/9/11
to Django users
I have a form that I use to collect contact information from
unregistered users. When they submit the form I want to redirect to a
confirmation page (as the Django documentation suggests). However,
instead of a generic page, I wanted to include the information that
they have submitted and the contact details of the person for their
area. I was also thinking that I could include the current status of
their enquiry. Therefore they could perhaps use the same link to come
back to check the status of their query.

Given that, is there a best practice pattern for handling this
situation? I have a quick demo where the URL is:

http://www.mydomain.com/contact/confirmation/1234

... where '1234' is the pk for the query. Obviously I would want to
encrypt the pk in this case, otherwise someone could just use the pk
to trawl through the database.

Are there any default ways of encrypting django urls?

Oleg Lomaka

unread,
May 9, 2011, 8:37:18 AM5/9/11
to django...@googlegroups.com
Take a look at django-registration app. With slight modification it should satisfy your requirements.

For URL encryption, you can generate some sort of UUID and save in your database that such UUID corresponds to given profile PK. django-registration uses such urls for email confirmation.

Cal Leeming [Simplicity Media Ltd]

unread,
May 9, 2011, 8:59:18 AM5/9/11
to django...@googlegroups.com, astley....@gmail.com
To be honest, I'd be careful when using this approach.

If you are intending on hiding the PKs, as a way to stop people hitting PKs they shouldn't be able to hit, then this means your security model is flawed from the ground up.

However, if you are doing it to stop PKs from being leaked, then this is fine.

Remember the number 1 rule in security.. NEVER TRUST THE CLIENT!!!


--
You received this message because you are subscribed to the Google Groups "Django users" group.
To post to this group, send email to django...@googlegroups.com.
To unsubscribe from this group, send email to django-users...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/django-users?hl=en.


Brian Bouterse

unread,
May 9, 2011, 9:15:09 AM5/9/11
to django...@googlegroups.com, astley....@gmail.com
In the name of not trusting any data coming from the client, one way that IBM uses often is called continuations.  Basically you keep all data on the server, and only give the client an identifier of that data.  This typically enforces a server-side state machine that ensures what a user can and can't do with the application from a given state.

This is not exactly what is being discussed here, but it is near it in topic, so I thought I would mention it.

Brian
--
Brian Bouterse
ITng Services

ALJ

unread,
May 9, 2011, 2:43:16 PM5/9/11
to Django users
I was really looking for something lightweight. I didn't really want
to have to change the model structure to include a UUID ... although I
realise that this seems to way to go. I really just wanted to avoid
any 'opportunistic' attempts at extracting the data. The data itself
isn't critical and not worth the effort of going to great lengths to
crack any encryption I would put in. I was tempted to just use base64,
perhaps joining the PK and the postcode for example. That might be
enough just to obfuscate the id a bit and have a pseudo dual key.

Oh well.

Thanks anyway.

ALJ

Shawn Milochik

unread,
May 9, 2011, 2:44:58 PM5/9/11
to django...@googlegroups.com
There's no need to change your models to add UUIDs.

You can just store a dict of UUID-to-primary key values in the session data.

Eric Chamberlain

unread,
May 9, 2011, 4:08:55 PM5/9/11
to django...@googlegroups.com

We needed a similar way to obfuscate publicly accessible objects and we didn't want usage information leaked by exposing the public key. We found and have been using short_url for over six months now. We use <http://www.michaelfogleman.com/2009/09/python-short-url-generator/> to generate short URL's from the primary key (integer). The short_url code is handy, because it doesn't need any extra columns in the database and it is pretty hard for users to reverse engineer the primary key id from the short URL.

--
Eric Chamberlain, Founder
RF.com - http://RF.com/

Greg Donald

unread,
May 9, 2011, 5:12:29 PM5/9/11
to django...@googlegroups.com
On Mon, May 9, 2011 at 8:15 AM, Brian Bouterse <bmbo...@gmail.com> wrote:
> In the name of not trusting any data coming from the client, one way that
> IBM uses often is called continuations.

I thought they were called cookies?

> Basically you keep all data on the
> server, and only give the client an identifier of that data.

Yeah, sounds exactly like a session-based cookie.


--
Greg Donald
destiney.com | gregdonald.com

Cal Leeming [Simplicity Media Ltd]

unread,
May 9, 2011, 5:21:19 PM5/9/11
to django...@googlegroups.com, ALJ
If you are looking for a quick and easy way to encrypt the URLs, why not
create some Middleware which encrypts/decrypts them on the fly with a
secret string from settings?

Although, the URLs are going to look ugly as sin, and I wouldn't
recommend this if you want decent SEO lol.

Remember you'd have to cater for encrypting redirects, query string
separation etc, and you've have to overwrite the request META vars so
that the app logic doesn't need to be patched.

Cal

Cal Leeming [Simplicity Media Ltd]

unread,
May 9, 2011, 5:23:17 PM5/9/11
to django...@googlegroups.com, Greg Donald
Just to be clear, the issue I was referring to, was to not trust the
data sent by the client.

I.e. if you are allowing the user to access an object in the database,
and not enforcing any restrictions other than client side UI, then this
is bad.

This topic spreads wayyyyyyyy long cookies and sessions lol.

ALJ

unread,
May 10, 2011, 4:22:35 AM5/10/11
to Django users
Some interesting stuff here. The short URL generator looks
interesting. But yes, I appreciate the thoughts about security. Horses
for courses and all that.

Cheers

ALJ

Sean Brant

unread,
May 10, 2011, 10:32:14 AM5/10/11
to Django users
Sorry I think I only responded to the original poster.

>>> from django.utils.http import int_to_base36, base36_to_int
>>> int_to_base36(123)
'3f'
>>> base36_to_int('3f')
123

Sean

bedros

unread,
May 10, 2011, 4:37:59 PM5/10/11
to Django users
rather than embedding the confirmation ID in the URL; you can use
session messages to pass the ID to the confirmation page view

check out some examples here

http://www.djangobook.com/en/beta/chapter12/

Regards,

Bedros

Cal Leeming [Simplicity Media Ltd]

unread,
May 10, 2011, 5:02:23 PM5/10/11
to django...@googlegroups.com, Sean Brant
Sean, are you suggesting that the OP rely on base36 encoding for
security? Please tell me you are joking.

Sean Brant

unread,
May 10, 2011, 5:08:07 PM5/10/11
to Cal Leeming [Simplicity Media Ltd], django...@googlegroups.com

On May 10, 2011, at 4:02 PM, "Cal Leeming [Simplicity Media Ltd]"<cal.l...@simplicitymedialtd.co.uk> wrote:

> Sean, are you suggesting that the OP rely on base36 encoding for security? Please tell me you are joking.

No not at all, I thought he stated this does not have to be secure.

If it does, then yeah my code is a bad idea. If security is a issue this should be behind a password.

Wesley Childs

unread,
May 12, 2011, 3:29:11 AM5/12/11
to django...@googlegroups.com

Why cant you do something like this to avoid exposing data if people are guessing primary keys....

if request.user == Users.objects.get(id=pk-url):
    Show data
Else:
    raise 404 or redirect to home page

The above requires a logged in a user but you get the idea of not allowing people to start guessing to expose data.

Wes

Ian Clelland

unread,
May 12, 2011, 1:13:52 PM5/12/11
to django...@googlegroups.com
On Thu, May 12, 2011 at 12:29 AM, Wesley Childs <childs...@gmail.com> wrote:

Why cant you do something like this to avoid exposing data if people are guessing primary keys....

if request.user == Users.objects.get(id=pk-url):
    Show data
Else:
    raise 404 or redirect to home page

The above requires a logged in a user but you get the idea of not allowing people to start guessing to expose data.


You can't do this, in this case, *because* it requires a logged-in user. Specifically, the OP is looking for a way to authenticate a user based on their knowledge of a 'secret' URL, but if the URLs are predictable, then discovering the secrets is trivial. Your solution is fine once the user has been logged in, although some people would say that it can still give away too much information*

Honestly, I can think of exactly two ways for the original poster to achieve his goal (and I've deployed systems using each of these):

1. Sign** the ID with a secret known only to the web server. Put the ID and the signature in the URL somewhere, and, when the user hits the view, sign the ID again, and verify that the signatures match. This doesn't hide the ID at all, but it ensures that nobody can forge a url with a different ID than the server gave them.

2. Generate a unique token for each record, randomly. Use a UUID, they're great for that. Then use the token in the URL, and look for the token in the database when the user comes back to the confirmation view. If your tokens are actually random, and large enough (say, 64 bits), then anybody trying to guess them will be wasting their time.


-- 
Regards,
Ian Clelland
<clel...@gmail.com>


* By looking at the database IDs, people can gauge how heavily the system is being used, or if they see a key for someone else's record, they can estimate when that record was created, by comparing it to their own data.

** And by sign, I mean HMAC.
Reply all
Reply to author
Forward
0 new messages