3

我有一个系统需要安排一些东西并将标识返回到某些外来对象的计划任务。用户基本上这样做:生成无法猜测的独特标记

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 
+0

大多数(伪)随机数字gerators将允许您跟踪生成的东西,通过始终使用相同的种子初始化发生器。这将产生完全相同的数字序列,因为您在同一台机器上使用它。因此,通过让种子应该是恒定的,以及生成多少个标识符的结果,可以检查是否以前生成了任何给定的数字。如果你可以重置标识符(比如当所有的计划都没有计划)时,这可能是一个简单的方法,但如果你需要跟踪一大组数字,则会变得很慢。 – Trinidad 2011-01-27 12:18:04

+0

在安全系统上实现Unschedule()的代码是什么?客户无法检查的一种?否则,你不能指望保持客户端无法发现的秘密价值。 – 2011-01-27 12:33:56

+0

@GregS:是的,基本上。客户端代码旨在运行沙盒。 @Trinidad:系统需要能够处理大量的数字。我至少会说每秒10000个数字。 (虽然Unschedule预计将是一个罕见的事件)。 – porgarmingduod 2011-01-27 12:37:45

回答

3

根据您拥有多少活动ID,64位可能太少。通过birthday paradox,你最终会得到32位标识符可能期望的保护级别。

此外,创建这些的最好方法可能是使用一些腌制的散列函数,如SHA-1或MD5或任何您的框架已有的,随机选择的salt(保密),至少生成无论如何,正是由于上面提到的原因,128位。如果你使用创建更长散列值的东西,我并不认为有任何理由来截断它们。要创建标识符,您可以在不存储它们的情况下检查标识符,例如使用相同的64位模式(总共128位)并使用某个常量密钥对其进行加密,使用AES或某些其他密码块大小为128位(或任何你选择的)。如果和当用户发送一些指称的密钥时,解密并检查您的易于识别的模式。

0

这是同一个问题作为处理普通的Web应用程序会话标识符。可预测的会话ID很容易导致会话劫持。

看看会话ID如何生成。这里一个典型的PHPSESSID cookie的内容:

bf597801be237aa8531058dab94a08a9 

如果你想死啊确保没有蛮力攻击是可行的,做计算落后:有多少尝试可以每秒饼干吗?在随机时间点使用多少个不同的唯一ID?共有多少个ID?饼干需要多长时间才能覆盖,比如1%的ID空间?相应地调整位数。

0

你让你的标识符足够长,所以它不能被合理地猜出。另外,让Unschedule等待1秒,如果令牌没有被使用,那么暴力攻击就不再可行了。就像其他答案一样,Web应用程序中的会话ID完全是同一个问题,我已经看到会话ID,其中64个随机字符长。

0

你需要在分布式或局部环境的这种模式?

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

handle = new Object(); // in Java 

没有其他客户端可以伪造这个。

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

1

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

编辑:

随着UUID,您的验证方法,也只是给定的UUID和存储的一个之间的比较。由于两个UUID之间发生碰撞的可能性非常低,所以您不必担心误报。在你的例子中,似乎同一个对象正在进行加密和解密,没有第三方读取存储的数据。如果是这种情况,那么除了传递的数据不容易猜测之外,通过传递加密数据不会获得任何收益。我认为一个UUID会给你相同的好处,而不需要加密操作的开销。