You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js中如何混淆顺序生成的用户ID?实现整数双向一一映射

Great question—this is a common need for obfuscating sequential user IDs while maintaining a strict 1:1 bidirectional mapping, which stops bad actors from enumerating all user accounts in your system. Below are the most robust, practical implementations I’d recommend, ordered by how well they balance simplicity, security, and performance:

1. Simplified Feistel Cipher (Best for Most Use Cases)

This is my go-to choice for ID obfuscation. Feistel ciphers are symmetric, reversible, and don’t require heavy cryptography libraries—perfect for mapping sequential integers to seemingly random ones without collisions.

How it works:

Split your integer ID into two equal-sized "halves" (e.g., for a 64-bit ID, split into two 32-bit chunks). Run several rounds (4-8 is usually enough) of:

  1. Use a secret key to transform the right half with a simple function (e.g., hash, linear math, or bitwise operations).
  2. XOR the transformed right half with the left half.
  3. Swap the left and right halves (skip the swap on the final round).
    To decrypt, just run the same rounds in reverse order.

Example Python Implementation:

class FeistelIDObfuscator:
    def __init__(self, key: int, rounds: int = 6):
        self.key = key
        self.rounds = rounds
        self.block_size = 32  # Split 64-bit ID into two 32-bit blocks
        self.mod = 1 << self.block_size  # 2^32

    def _round_function(self, val: int) -> int:
        # Simple but non-trivial round function—customize this for extra security
        return (val * self.key + 0xDEADBEEF) % self.mod

    def encode(self, original_id: int) -> int:
        left = original_id >> self.block_size
        right = original_id & (self.mod - 1)
        
        for _ in range(self.rounds):
            new_left = right
            new_right = left ^ self._round_function(right)
            left, right = new_left, new_right
        
        # Final swap back (since we swapped every round except last)
        return (right << self.block_size) | left

    def decode(self, obfuscated_id: int) -> int:
        left = obfuscated_id >> self.block_size
        right = obfuscated_id & (self.mod - 1)
        
        for _ in range(self.rounds):
            new_right = left
            new_left = right ^ self._round_function(left)
            left, right = new_left, new_right
        
        return (right << self.block_size) | left

Pros & Cons:

  • ✅ Easy to implement without external dependencies
  • ✅ Customizable security (more rounds = harder to crack)
  • ✅ Works for any integer size (adjust block_size as needed)
  • ❌ Slightly slower than linear methods (but negligible for ID workloads)

2. Linear Congruential Permutation (LCP)

If you need blazingly fast performance and don’t require military-grade security, LCP is ideal. It uses mathematical properties to create a permutation (1:1 mapping) of integers.

How it works:

Choose three parameters:

  • m: A prime number larger than your maximum possible user ID
  • a: A primitive root modulo m (ensures every input maps to a unique output)
  • b: An integer coprime with m (i.e., gcd(b, m) = 1)

The mapping is:

  • Encode: obfuscated_id = (a * original_id + b) % m
  • Decode: original_id = (inv_a * (obfuscated_id - b)) % m
    Where inv_a is the modular inverse of a modulo m (you can precompute this once).

Example Python Implementation:

def modinv(a: int, m: int) -> int:
    # Compute modular inverse using extended Euclidean algorithm
    g, x, _ = extended_gcd(a, m)
    if g != 1:
        raise ValueError("Modular inverse does not exist")
    return x % m

def extended_gcd(a: int, b: int) -> tuple[int, int, int]:
    if a == 0:
        return (b, 0, 1)
    else:
        g, y, x = extended_gcd(b % a, a)
        return (g, x - (b // a) * y, y)

# Example parameters (adjust m to be larger than your max user ID)
M = 1000003  # Prime number
A = 123457   # Primitive root modulo M
B = 98765    # Coprime with M
INV_A = modinv(A, M)

def encode_lcp(original_id: int) -> int:
    return (A * original_id + B) % M

def decode_lcp(obfuscated_id: int) -> int:
    return (INV_A * (obfuscated_id - B)) % M

Pros & Cons:

  • ✅ Extremely fast (single arithmetic operations)
  • ✅ Minimal code
  • ❌ Less secure if parameters are leaked (easy to reverse-engineer)
  • ❌ Requires knowing your maximum possible ID upfront to choose m

3. AES in ECB Mode (Cryptographically Secure)

If you need unbreakable (for all practical purposes) obfuscation, use AES in ECB mode. Since AES is a block cipher, each unique input block maps to a unique output block—perfect for 1:1 integer mapping.

How it works:

  1. Convert your integer ID to a fixed-length byte array (e.g., 16 bytes for AES-128).
  2. Encrypt the byte array with AES-ECB using a secret key.
  3. Convert the encrypted byte array back to an integer.
    Decryption reverses these steps.

Example Python Implementation (using pycryptodome):

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad

class AESIDObfuscator:
    def __init__(self, key: bytes):
        # Key must be 16, 24, or 32 bytes for AES-128, AES-192, AES-256
        self.cipher = AES.new(key, AES.MODE_ECB)

    def encode(self, original_id: int) -> int:
        # Convert integer to 16-byte padded bytes
        id_bytes = original_id.to_bytes(16, byteorder='big')
        encrypted_bytes = self.cipher.encrypt(pad(id_bytes, AES.block_size))
        return int.from_bytes(encrypted_bytes, byteorder='big')

    def decode(self, obfuscated_id: int) -> int:
        encrypted_bytes = obfuscated_id.to_bytes(16, byteorder='big')
        decrypted_bytes = unpad(self.cipher.decrypt(encrypted_bytes), AES.block_size)
        return int.from_bytes(decrypted_bytes, byteorder='big')

Pros & Cons:

  • ✅ Cryptographically secure (effectively unbreakable with a strong key)
  • ✅ Standardized algorithm
  • ❌ Requires a cryptography library
  • ❌ Slightly slower than the other methods (still fast enough for most apps)

Critical Notes:

  • Keep keys secret: No matter which method you choose, leaking the key will let attackers reverse-engineer all IDs.
  • Test for collisions: Verify that every original ID maps to a unique obfuscated ID (all methods above guarantee this if implemented correctly).
  • Handle overflow: If using 64-bit IDs, make sure your language supports unsigned integers or handles overflow correctly.

内容的提问来源于stack exchange,提问作者nagy.zsolt.hun

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:37:24