我一直在讨论关于nonce生成和PHP的各种问题,但没有找到关于管理nonce的"一次"方面的细节的任何讨论.
这是我的情况.
我有一些PHP需要访问web服务,并且对webservice的请求需要我的PHP生成一个nonce并签署请求(即,我不是从webservice请求nonce).那部分很容易.
我正在努力寻找一个好的解决方案,以防止在有多个会话进行时重用nonce.
在我看来,我可以做三件事.
一种是将nonce/timestamp对存储在数据库中,然后实现逻辑以检查数据库中是否存在现有的nonce,使旧的等效期满等.这也需要一个TRANSACTION或者LOCK TABLE用于线程安全.呸.
二,是将存储器中的nonce存储在APC中的nonce(在我的情况下不能使用memcached),并让TTL处理到期.在这种情况下,线程安全是否需要将逻辑包装在sem_acquire()/ sem_release()或apc_add()真正的线程安全?我的这个主要关注的是如何处理这种情况,如果apc_add()还是apc_store()实际上失败,因为缓存已满.
三,是使用Cache_Lite而不是APC.
还有其他选择吗?据我所知,OpenID使用Cache_Lite管理nonce,所以我怀疑这是最好的解决方案,但我想在提交之前检查所有选项.
谢谢.
一种是将nonce/timestamp对存储在数据库中,然后实现逻辑以检查数据库中是否存在现有的nonce,使旧的等效期满等.这还需要TRANSACTION或LOCK TABLE来保证线程安全.呸.
没有表锁定,您可以这样做.只要您使用的数据存储符合ACID,它就会为您完成所有艰苦的工作.这意味着如果您使用的是MySQL,请使用InnoDB表.
创建一个表,其中包含nonce,创建时间,最长生命周期以及消耗时间的字段.使nonce成为主键或唯一.要分配随机数,请插入表中.如果出现重复键错误(或使用事务并获得死锁或类似问题),请捕获它并生成新的nonce.
如果你正在使用足够的随机性生成器openssl_random_pseudo_bytes并且正在为nonce收集足够的字节,那么碰撞的可能性非常小.
当您需要将随机数标记为已消耗时,请对nonce行执行简单的UPDATE,同时还要求使用消耗的列为空.更新将返回已修改的行数(如果您正在使用事务,则返回死锁).如果修改后的行数为零或者您遇到了死锁,那么其他内容已经将nonce标记为已消耗,并且您可以向用户返回相应的错误.
请记住,正确的数据库引擎旨在处理这种废话.不要重新发明轮子.