13

注意:我最初将其发布到Information Security,但我开始认为它在这里可能更相关,因为它实际上是关于确定我应该如何处理请求而不是保护信息。

情况

系统A

我有一个A为用户提供请求的系统。该服务器执行某些操作,然后将用户重定向到 system B。在该重定向期间,服务器A可以为用户提供一个 32 字符的字母数字信息字符串以传递给 system B。需要该信息的 31 个字符,但可以将一个字符用作校验和。这个字符串或多或少可以被认为是一个请求 ID。

系统B

当系统B收到用户的请求时,可以通过解析31个字符的字符串,查询数据库,与系统A对话来验证请求(和类似ID的字符串)是否有效。该系统可以绝对确定地验证请求是有效的并且没有被篡改,但是它在计算上非常昂贵。

攻击者:

该系统很可能会看到许多欺骗 ID 的尝试。这会被后来的检查过滤,所以我不担心单个字符完美地签署了 ID,我确实希望避免在处理这些请求时花费更多的资源而不是需要的资源。

我需要的

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

我试过的

我已经研究过使用 Luhn 算法(与用于信用卡的算法相同),但我希望能够使用密钥来生成字符,以使攻击者更难以欺骗校验和。

作为创建签名方案的第一次尝试,我使用 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 字节长的输入,在 set 中产生一个输出{x | x ∈ ℕ, x < 62},其中猜测输出比计算私钥更有效。(可变长度输入的奖励积分)

这最终将在 NodeJS/JavaScript 中实现,但并不依赖于语言。


免责声明:如果这个问题过于模糊和理论化,我深表歉意。如果需要,请发表评论以进行澄清。显然,我可以通过多种方式解决这个问题,但在这种情况下,我正在寻找尽可能直接的解决方案。

4

2 回答 2

1

如果您想要一个带有私钥的“确定性哈希函数”,那么我相信您可以使用 sha256(或您的加密库中的任何其他哈希函数)并将密钥附加到输入:

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

然后,取哈希值的最后几位,将其从十六进制字符串转换为整数,将整数除以 62,得到余数,根据余数确定字符。

这不会为每个字符提供完美的 1/62 分布概率(十六进制字符串应该对每个值具有均匀分布,但不是除以 62 后的余数),但应该非常接近。

于 2017-10-03T19:20:42.500 回答
0

一种方法是Blob URL在用户访问时创建一个 initial documentBlob URL应该是document创建 URL的唯一的。然后,用户可以将Blob URL用作服务器“B”的请求标识符。当用户向“B”提出请求时,撤销Blob URL.

Blob URL每次调用都是唯一的,URL.createObjectURL()用户创建唯一标识符,其中的生命周期是创建Blob URL的生命周期,或者被撤销的生命周期。除了创建 的用户之外,任何个人从访问者的浏览器复制 的机会很小,除非个人计算机上存在其他问题。documentBlob URLBlob URLBlob URLBlob 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”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));
于 2017-10-04T04:33:22.540 回答