Managing Nonces in Apache/PHP
I have been going through the various questions here about nonce generation and PHP, but not found any discussions about the details of managing the "once" aspect of the nonce.
Here is my situation.
I have some PHP that needs to access a webservice, and requests to the webservice requi开发者_如何学Cre my PHP to generate a nonce and sign the request (ie, I am not requesting the nonce from the webservice). That part is easy.
I am struggling with a good solution for preventing the reuse of a nonce when there can be multiple sessions going on.
As I see it, there are three things I could do.
One, is to store nonce/timestamp pairs in the database, and then implement the logic to check the database for an existing nonce, expire old ones, etc. This would also require a TRANSACTION
or LOCK TABLE
for thread safety. Yuck.
Two, is to store the nonces in store the nonces in APC (can't use memcached in my case), and let the TTL handle expiration. In this case would thread-safety require wrapping the logic in sem_acquire()
/ sem_release()
or is apc_add()
truly thread-safe? My main concern with this is how to handle the situation if apc_add()
or apc_store()
actually fail because the cache is full.
Three, is to use Cache_Lite instead of APC.
Are there any other options? As far as I can tell, OpenID manages nonces with Cache_Lite, so I suspect this is the best solution, but I want to check into all options before I commit.
Thanks.
One, is to store nonce/timestamp pairs in the database, and then implement the logic to check the database for an existing nonce, expire old ones, etc. This would also require a TRANSACTION or LOCK TABLE for thread safety. Yuck.
You can do this without table locking. As long as the data store you are using is ACID compliant, it will do all the hard work for you. This means using an InnoDB table if you're using MySQL.
Create a table with fields for the nonce, creation time, maximum lifetime, and when it was consumed. Make the nonce either the primary key or unique. To allocate a nonce, insert into the table. If you get a duplicate key error (or use a transaction and get a deadlock or similar problem), catch it and generate a new nonce.
If you're using an adequate randomness generator like openssl_random_pseudo_bytes
and are gathering enough bytes for the nonce, the chances of a collision is pretty tiny to begin with.
When you need to mark a nonce as consumed, perform a simple UPDATE for the nonce row also requiring that the consumed column is null. The update will return the number of rows modified (or a deadlock if you're using a transaction). If the modified row count is zero or you catch a deadlock, then something else has already marked the nonce as consumed, and you can return an appropriate error to the user.
Remember, proper database engines are designed to handle this sort of nonsense. Don't reinvent the wheel.
精彩评论