用户ID混淆

时间:2012-01-06 09:26:07

标签: c# obfuscation

  

我希望之前有人问过这个问题,但我们在这里找不到合适的答案,也没有时间提出我自己的解决方案......

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

我们在网站网址上有用户公开个人资料页面:

www.somesite.com/user/1234

其中1234是实际用户ID。没有什么容易看到用户的ID 本身,但它确实让任何人都能够检查我的网站上注册了多少用户...手动增加数量最终让我无效的个人资料。

这是我将可逆ID映射到具有固定长度的看似随机数的主要原因:

www.somesite.com/user/6123978458176573

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

我想避免使用GUID

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

如果我有ID + GUID,那么我总是需要获取原始用户ID来进行任何有意义的数据操作,这又会导致速度下降......

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

3 个答案:

答案 0 :(得分:15)

我会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并轻松进行逆向工程。


修改:此博客帖子Obfuscating IDs in URLs with Rails提供了相当可行的示例。转换为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

This follow up post by another author解释了如何使用随机XOR更多地保护这一点,以及如何计算PrimePrimeInverse - 我刚刚使用了预先制作的原创博客的演示。

答案 1 :(得分:1)

  1. 使用UUID

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

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

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

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

答案 2 :(得分:0)

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

修改

如果你真的想避免使用GUID,那么为什么不在访问他们的个人资料页面时使用用户“用户名”。毕竟,我想在你输入有效信息并且数据已保存到数据库之前,你不会为用户分配ID。