单字符签名scheme(最低安全性)

注意:我最初把这个发布到信息安全 ,但是我开始认为它可能更有意义,因为它确实是确定我应该怎样处理请求,而不是保护信息。

情况

系统A

我有一个向用户提供请求的系统A 此服务器执行某些操作,然后将用户redirect到系统B 在这个redirect过程中,服务器A可以给用户一个32个字符的字母数字string信息传递给系统B 需要31个字符的信息,但是可以使用一个校验和。 这个string可以或多或less的被认为是一个请求ID。

系统B

当系统B收到用户的请求时,可以通过parsing31个字符的string,查询数据库和与系统A通话来validation请求(和类IDstring)是否有效。该系统可以用绝对确定请求是有效的并且没有被篡改,但是这在计算上是非常昂贵的。

攻击者:

这个系统很可能会看到许多欺骗ID的尝试。 这是由后来的检查过滤,所以我不担心一个字符完全签署的ID, 我想避免花费更多的资源来处理这些请求比需要。

我需要的

我正在寻找一个校验和/签名scheme,可以用单个字符给我一个很好的想法,请求是否应该继续进行validation过程,或者应该立即丢弃为无效。 如果一条消息被丢弃,我需要100%确定它是无效的,但是如果我保留无效的消息也没问题。 我相信一个理想的解决scheme将意味着1/62无效请求被保留(攻击者必须猜测检查字符),但是作为放弃一半无效请求的最小解决scheme就足够了。

我所试过的

我已经看过使用Luhnalgorithm(与信用卡相同的algorithm),但我希望能够使用密钥来生成angular色,以使攻击者更难以伪造校验和。

作为创build签名scheme的第一次尝试,我用31个字节的键逐个对31个字节的ID进行异或,将所得到的字节相加,转换为十进制并将数字相加,直到小于62,然后映射它到集合[a-bA-Z0-9]的字符(下面的伪代码)。 问题是,虽然我敢肯定,这不会丢弃任何有效的请求,我不知道如何确定这将通过无效的ID或如果密钥可以检索使用最终值的频率。

 Set alphabet to (byte[]) "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; Set keystring to "aLaklj14sdLK87kxcvalskj7asfrq01"; Create empty byte[] key; FOR each letter in keystring Push (index of letter in alphabet) to key; Create empty byte[] step1; FOR each (r, k) in (request, key) Push r XOR s to step1; Set step2 to 0; FOR each b in step1 Add (int) b to step2; WHILE step2 > 62 Copy step2 to step3; Set step2 to 0; Convert step3 to String; Split step3 between characters; FOR each digit in step3 Add (int) digit to step2; END WHILE RETURN alphabet[step2] 

正式表态

一个确定性的散列函数,其中给定一个私钥和长度为31个字节的input,得到集合{x | x ∈ ℕ, x < 62}的输出 {x | x ∈ ℕ, x < 62} ,其中猜测输出比计算私钥更有效。 (可变长度input的奖励积分)

这将最终在NodeJS / JavaScript中实现,但不是真正的语言依赖。


免责声明:如果这个问题太模糊和理论化,我很抱歉。 如有需要,请澄清意见。 显然,我有办法解决这个问题,但在这种情况下,我正在寻找一个尽可能直接的解决scheme。

如果你想要一个“确定性的散列函数”与私钥,那么我相信你可以使用SHA256(或在你的encryption库中的任何其他散列函数)与附加到input的密钥:

 sha256(input+key).toString('hex'); 

之后,取出散列值的最后几位,将其从hexstring转换为整数,将整数除以62,得到余数,并根据余数确定字符。

这不会给你完美的1/62分配概率(hexstring对于每个字符应该是均匀分布的,而对于每个字符除以62后应该是一样的),但是应该非常接近。

一种方法是在用户访问初始document时创build一个Blob URLBlob URL对于创buildURL的document应该是唯一的。 然后用户可以使用Blob URL作为服务器“B”的请求标识符。 当用户请求“B”撤销Blob URL

每次调用URL.createObjectURL()Blob URL都是唯一的,用户创build唯一标识符,其中Blob URL的生存期是创buildBlob URLdocument的生命周期,或者Blob URL被吊销。 除了创buildBlob URL的用户之外,除非在个人计算机上存在其他问题,否则除了创buildBlob URL的用户之外,访问者浏览器从Blob URL复制的机会很小。

 const requestA = async() => { const blob = new Blob(); const blobURL = URL.createObjectURL(blob); const A = await fetch("/path/to/server/A", { method:"POST", body:JSON.stringify({id:blobURL}) }); const responseA = await A.text(); // do stuff with response return [blobURL, responseA]; } 

服务器“A”将创build的Blob URL传递给服务器“B”

 const requestB = async(blobURL) => { const blob = new Blob(); const blobURL = URL.createObjectURL(blob); const B = await fetch("/path/to/server/B", { method:"POST", body:JSON.stringify({id:blobURL}) }); const responseB = await B.text(); return responseB } requestA() .then(([blobURL, responseA] => { // do stuff with `responseA` console.log(responseA); // return `requestB` with `blobURL` as parameter return requestB(blobURL) }) .then(responseB => console.log(responseB) // do stuff with `responseB`) .catch(err => console.error(err));