用户ID混淆

本文关键字:混淆 ID 用户 | 更新日期: 2023-09-27 18:19:40

我想以前有人问过这个问题,但在这里还没有找到合适的答案,也没有时间提出我自己的解决方案。。。

如果我们有一个具有int identity主键的用户表,那么我们的用户在网站上注册时具有连续的ID。

我们网站上的用户公共资料页面URL:

www.somesite.com/user/1234

其中1234是实际的用户ID。没有任何漏洞可以看到用户的ID本身,但它确实让任何人都能够检查有多少用户在我的网站上注册。。。手动增加数字最终会使我进入一个无效的配置文件。

这就是为什么我把一个可逆的ID映射到一个固定长度的看似随机的数字的主要原因:

www.somesite.com/user/6123978458176573

你能给我指一个做这个映射的简单类吗?当然,重要的是,这个映射是可逆的,否则我必须将映射与其他用户的数据一起保存。

我想避免GUID

GUID的索引搜索速度较慢,因为它们不是连续的,所以SQL必须扫描整个索引以匹配特定的GUID,而只是特定的计算索引页。。。

如果我有ID+GUID,那么我总是需要获取原始用户ID来进行任何有意义的数据操作,这再次降低了速度。。。

数学可逆整数排列似乎是最快的解决方案。。。

用户ID混淆

我会100%采用"向表中添加GUID列"的方法。为每个当前用户生成一个需要几秒钟的时间,并更新插入过程以为每个新用户生成一。这是最好的解决方案。

然而,如果你真的不想采取这种方法,你可以使用许多模糊处理技术。

简单地对数字的字符串表示进行Base64编码是一种(糟糕的)方法

    static public string EncodeTo64(string toEncode)
    {
      byte[] toEncodeAsBytes
            = System.Text.ASCIIEncoding.ASCII.GetBytes(toEncode);
      string returnValue
            = System.Convert.ToBase64String(toEncodeAsBytes);
      return returnValue;
    }
    static public string DecodeFrom64(string encodedData)
    {
      byte[] encodedDataAsBytes
          = System.Convert.FromBase64String(encodedData);
      string returnValue =
         System.Text.ASCIIEncoding.ASCII.GetString(encodedDataAsBytes);
      return returnValue;
    }

糟糕的是,任何拥有半盎司技术知识的人(黑客/脚本儿童往往拥有丰富的技术知识)都会立即将结果识别为Base64,并轻松进行反向工程。


编辑:这篇博客文章用Rails混淆URL中的ID提供了一个非常可行的例子。转换为C#会给你一些类似的东西:

static int Prime = 1580030173;
static int PrimeInverse = 59260789;
public static int EncodeId(int input)
{
    return (input * Prime) & int.MaxValue;
}
public static int DecodeId(int input)
{
    return (input * PrimeInverse) & int.MaxValue;
}

输入-->输出
1234-->1989564746
5678-->1372124598
5679-->804671123

另一位作者的这篇后续文章解释了如何通过随机XOR来确保这一点,以及如何计算PrimePrimeInverse——我只是使用了原始博客中预先录制的内容进行演示。

  1. 使用UUID

  2. 在用户表中为创建另一列,例如64位整数,并用一个随机数填充(每次新用户注册时,生成它并检查它是否唯一)。数字看起来比UUID更好,但需要更多的编码。

  3. 使用数学。)您可以生成一对数字XY,例如X*Y = 1 (mod M)。例如X=10000000019LY=1255114267LM=2^30。然后,您将有两个简单的功能:

long encode(long id)
{  return (id * X) & M; }
long decode(long encodedId)
{  return (encodedId * Y) & M; }

它将产生几乎随机编码的id。这很简单,但很容易破解。如果有人愿意破解它,他将能够猜测你的数字,并看到编码值。然而,我不完全确定它的复杂性,但正如我所记得的,它不是很容易破解。

我可以建议您改用UUID吗。当您向数据库中添加新用户时,这可以是可索引的,并在存储过程中生成。这意味着要么向数据库表添加一个新列,要么添加一个包含UUID但以用户ID作为相关键的新表。

编辑

如果你真的想避免GUID,那么为什么不在用户访问其配置文件页面时使用"用户名"呢。毕竟,我想,在用户输入有效信息并将数据保存到数据库中之前,您不会为用户分配ID。