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