生成无法猜到的唯一令牌

时间:2011-01-27 11:58:36

标签: language-agnostic encryption cryptography uniqueidentifier

我有一个系统需要安排一些东西并将标识符返回到某些外来对象的计划任务。用户基本上会这样做:

identifier = MyLib.Schedule(something)
# Nah, let's unschedule it.
MyLib.Unschedule(identifier)

我在内部代码中经常使用这种模式,并且我总是使用普通整数作为标识符。但是,如果标识符由不受信任的代码使用,则恶意用户可以通过执行单个Unschedule(randint())来破坏整个系统。

我需要代码的用户只能取消计划他们实际安排的标识符。

我能想到的唯一解决方案是生成64位随机数作为标识符,并跟踪当前分发的标识符,以避免可怕的不可能重复。还是128位?我什么时候可以说“这是随机的,不会发生重复”,如果有的话?

或者更好的是,有更合理的方法吗?有没有办法生成标识符令牌,生成器可以轻松跟踪(避免重复),但与收件人的随机数无法区分?

编辑 - 基于接受的答案的解决方案:

from Crypto.Cipher import AES
import struct, os, itertools

class AES_UniqueIdentifier(object):
    def __init__(self):
        self.salt = os.urandom(8)
        self.count = itertools.count(0)
        self.cipher = AES.new(os.urandom(16), AES.MODE_ECB)
    def Generate(self):
        return self.cipher.encrypt(self.salt + 
                                   struct.pack("Q", next(self.count)))
    def Verify(self, identifier):
        "Return true if identifier was generated by this object."
        return self.cipher.decrypt(identifier)[0:8] == self.salt

5 个答案:

答案 0 :(得分:3)

根据您拥有的活动ID数量,64位可能太少。通过birthday paradox,您最终可以获得32位标识符所期望的保护级别。

此外,创建这些的最佳方法可能是使用一些盐渍哈希函数,例如SHA-1或MD5或您的框架已经拥有的任何东西,随机选择的盐(保密),以及那些至少生成128的哈希函数无论如何,完全出于上述原因。如果你使用创建更长哈希值的东西,我真的没有理由截断它们。

要创建标识符,您可以在不存储标识符的情况下进行检查,使用易于检测的内容,例如两次使用相同的64位模式(总共128位),并使用AES或其他方法使用某些常量密钥对其进行加密块大小为128位的密码(或者您选择的任何密码)。如果用户发送了一些所谓的密钥,请解密并检查您的易于点模式。

答案 1 :(得分:1)

听起来像你可能在想这个问题。这听起来像是GUID/UUID的应用程序。 Python甚至有a built in way to generate them。 GUID / UUID的重点是碰撞的几率是天文数字,通过使用字符串而不是加密的令牌,您可以跳过验证步骤中的解密操作。我认为这也可以消除您在密钥管理方面可能遇到的一系列问题,并提高整个过程的速度。

修改

使用UUID,您的验证方法只是给定UUID与存储的UUID之间的比较。由于两个UUID之间发生碰撞的可能性非常低,因此您不必担心误报。在您的示例中,似乎同一对象正在执行加密和解密,而没有第三方读取存储的数据。如果是这种情况,那么通过传递加密数据就不会获得任何东西,除了你传递的位不容易猜到。我认为UUID会给你带来同样的好处,而不会产生加密操作的开销。

答案 2 :(得分:0)

这与在普通Web应用程序中处理会话标识符的问题相同。可预测的会话ID很容易导致会话劫持。

了解如何生成会话ID。这里是典型PHPSESSID cookie的内容:

bf597801be237aa8531058dab94a08a9

如果你想确定没有暴力攻击是可行的,那么向后计算:一个黑客每秒可以做多少次尝试?在随机时间点使用了多少个不同的唯一ID?总共有多少个id?饼干覆盖需要多长时间,比如ids总空间的1%?相应地调整位数。

答案 3 :(得分:0)

你的标识符足够长,所以无法合理猜测。另外,如果令牌未被使用,让非计划等待1秒,因此蛮力攻击不再可行。就像其他答案所说的那样,Web应用程序中的会话ID完全是同一个问题,我已经看到了64个随机字符长的会话ID。

答案 4 :(得分:0)

您是否需要在分布式或本地环境中使用此模式?

如果你是本地语言,大多数OO语言应该支持对象标识的概念,所以如果你创建一个不透明的句柄 - 只需创建一个新对象。

handle = new Object(); // in Java

没有其他客户可以伪装。

如果您需要在分发环境中使用它,您可以在每个会话中保留一个句柄池,以便外部会话永远不会使用被盗的句柄。