The primary key is usually there to uniquely identify each row. There
are a couple of ways to generate them:

  One is to always create  a new integer id (sequentially or random)
when you insert a new row. This means  that if you insert the same data
 again, the row will always be duplicated. Usually you don't want this.


  Then the primary key integer must somehow 'represent' the whole data
row. So you   would want for the key to be a function of the whole data
row, such that when the data is the same the row ID is the same and
when the data is different the row ID is different. The answer to your
problem is to use a message digest (actually a  message authentication
code function).

  For example if your data row is in the tuple 'row' then  you can do:
hex_digest_key=md5.new("|".join(row)).hexdigest(), you would have to
import the md5 module before doing this.

What that will do is your row will be contcatenated into one string
with each field separated by "|" then the md5 hash of that string will
be taken and the result returned to you in hexadecimal form. You'll get
back something like hex_digest_key='5d41402abc4b2a76b9719d911017c592'.
Then you can turn that into an integer by doing int(hex_digest_key,16)
-- and you can use that integer as your primary key.

  But since one of the problems you want to solve is the user's ability
to predict the next key, you cannot just use a simple message digest
function. If the user finally figures out that you are running an MD5
algorithm, the user can also run the same algorithm and generate the
same message digest -- If that is a problem,  then use a MAC (Message
Authentication Code) function. It works almost like a message digest
except you concatenate a secret key to the input so MD5 is run on the
row_as_text+secret_key.

Unless the user knows your secret key, they could not generate a
primary key from a given row even if they know you used MD5 and even if
the know the data content  of  your row.

 NOTE: When using a message digest (and friends) it is important to
realize that there will be some collision between the keys if the
number of all possible digests (as limited by the digest algoritm) is
smaller than the number of the possible messages. In practice if you
have large enough integers (64)  you shouldn't see any collisions
occur, but it is still good to be aware of them...

Hope this helps,
-Nick Vatamaniuc

Simon Wittber wrote:
> I'm building a web application using sqlalchemy in my db layer.
>
> Some of the tables require single integer primary keys which might be
> exposed in some parts of the web interface. If users can guess the next
> key in a sequence, it might be possible for them to 'game' or
> manipulate the system in unexpected ways. I want to avoid this by
> generating a random key for each row ID, and have decided to use the
> same approach for all my single key tables.
>
> Are there any best practices for implementing this?
>
> If the random module is suitable, does anyone have any good ideas on
> how this could be implemented?
>
> Some questions which came to mind are:
>     Would I need to save and restore the random module state when
> generating id's for each table?
>     What would be an appropriate seed?
>     How many random integers can I generate before a repeat becomes
> probable?
>
> I've got my own ideas for implementing this, but am interested to see
> how/if anyone else has tackled the same problem.
> 
> 
> -Sw.

-- 
http://mail.python.org/mailman/listinfo/python-list

Reply via email to