单字符签名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 URL
。 Blob URL
对于创buildURL的document
应该是唯一的。 然后用户可以使用Blob URL
作为服务器“B”的请求标识符。 当用户请求“B”撤销Blob URL
。
每次调用URL.createObjectURL()
, Blob URL
都是唯一的,用户创build唯一标识符,其中Blob URL
的生存期是创buildBlob URL
的document
的生命周期,或者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));