如何基于字符串创建Firestore安全文档ID

时间:2019-05-24 08:55:40

标签: firebase firebase-authentication google-cloud-firestore userid

在讨论了有关base64对于Firestore ID不安全here的问题进行讨论之后,我想知道如何将字符串编码为Firestore“安全”文档ID。

这是问题所在:

  • 我正在通过自定义身份验证服务登录用户。
  • 该服务所提供的用户名可能包含/ ,对于声明为here
  • 的Firestore文档ID 不安全

我在另一个问题中询问了base64,它不安全,因为它包含/

因此,在不丢失外部服务提供的用户名的熵的情况下,对字符串进行编码的一种安全方法可能是安全的。这意味着可能会有一个用户名,例如dimi/test1,另一个用户名是dimitest1,因此仅去除字符是不可行的。

此外,由于该服务提供了开放的API,并且我的服务通过URL公开了文档ID,因此我不希望通过我的应用程序URLS公开其他服务的用户名。

有什么建议吗?

3 个答案:

答案 0 :(得分:2)

使用encodeURI()后跟SHA256。这会将文档ID限制为

Must be valid UTF-8 characters
Must be no longer than 1,500 bytes
Cannot contain a forward slash (/)
Cannot solely consist of a single period (.) or double periods (..)
Cannot match the regular expression __.*__

encodeURI用于有效的UTF-8字符。

SHA256的固定长度为256位(或32个字节),因此不超过1,500个字节限制。

根据https://stackoverflow.com/a/12618366/3073280,SHA256个字符为[a-fA-F0-9]。

最后,您提到它将需要熵。 SHA256扩散良好。

答案 1 :(得分:1)

编辑

要非常快速地将字符串转换为uniqueID,请使用crypto.createHash()。对于给定的字符串输入,结果将是相同的。

您可以使用MD5或SHA256,因为两者都需要相同的时间(平均2.2秒)来计算100万个唯一ID。

代码如下:

const crypto = require('crypto');

function uniqueId(string, algorithm = 'md5') {
  return crypto.createHash(algorithm).update(string).digest('hex');
}

console.log('started');
console.time('generateIDsMD5')
for (let i = 0; i < 1000000; i++) {
  uniqueId('a string ' + i);
}
console.timeEnd('generateIDsMD5');

console.time('generateIDsSHA256')
for (let i = 0; i < 1000000; i++) {
  uniqueId('a string ' + i, 'sha256');
}
console.timeEnd('generateIDsSHA256');

// For instance, It will take around 2.2s average
// to generate 1Million Unique IDs with MD5 or SHA256 encryption

console.log('MD5 string ', uniqueId('a string ' + 1));
console.log('MD5 sameString ', uniqueId('a string ' + 2));
console.log('MD5 sameString ', uniqueId('a string ' + 2));
console.log('SHA256 string ', uniqueId('a string ' + 1, 'sha256'));
console.log('SHA256 sameString ', uniqueId('a string ' + 2, 'sha256'));
console.log('SHA256 sameString ', uniqueId('a string ' + 2, 'sha256'));
console.log('finished');

上级答案

我改编了Firebase中的代码,并通过一些自定义测试将其直接在您的node.js上可用。 100万个ID最多需要3s,100.000个ID最多需要300ms,这是您考虑的日常使用方法。

如果在node.js环境中运行,它使用crypto被认为非常安全。

下面是使用示例包装的函数:

const crypto = require('crypto');

function autoId(bytesLength) {
  const chars =
    'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
  let autoId = '';
  while (autoId.length < bytesLength) {
    const bytes = crypto.randomBytes(40);
    bytes.forEach(b => {
      // Length of `chars` is 62. We only take bytes between 0 and 62*4-1
      // (both inclusive). The value is then evenly mapped to indices of `char`
      // via a modulo operation.
      const maxValue = 62 * 4 - 1;
      if (autoId.length < bytesLength && b <= maxValue) {
        autoId += chars.charAt(b % 62);
      }
    });
  }
  return autoId;
}

console.log('started');
console.time('generateIDs')
for (let i = 0; i < 1000000; i++) {
  autoId(20);
}
console.timeEnd('generateIDs');
// For instance, It will take around 3s average
// to generate 1 Million Unique IDs with 20 bytes length

console.log('example 20bytes ', autoId(20));
console.log('example 40bytes ', autoId(40));
console.log('example 60bytes ', autoId(60));
console.log('finished');

只需使用node thisfile.js,您就会看到结果。

由于firebase主要是开源的,我们可以在node.js中找到用于在此处生成ID的官方uniqueId生成器:​​https://github.com/googleapis/nodejs-firestore/blob/4f4574afaa8cf817d06b5965492791c2eff01ed5/dev/src/util.ts#L52

重要

如果您要加入2个ID,请不要使用任何斜杠/,因为您知道这是不允许的,而应使用下划线_或根本不使用斜杠,因为您可以控制长度ID,因此您应该知道如何相应地拆分ID(40字节包含2个ID,例如20字节)。

Document Ids中的firestore限制为1500个字节,因此您有很多玩法。

更多信息:https://firebase.google.com/docs/firestore/quotas#limits

答案 2 :(得分:0)

我使用Base58,这是我能研究的最安全的