隐藏敏感信息的最简单方法

时间:2010-03-20 17:46:48

标签: encryption

我可以隐藏敏感标识符的最简单方法是什么,同时提供一些从外部识别数据的等效方法?

例如,假设我有一个包含记录的数据库表,其中一个是敏感的ID字段。

ID
2A
1S
etc...

然后我想要第二张唱片:

ID    PublicID
2A    AXXX44328
1S    KKKZJSAAS

这样当我获得PublicID时,我总能确定它引用的ID:

H(PublicID) = ID

但没有其他人能够这样做。

另请注意,我希望能够在至少两个不同的位置重现字符串。因此,如果我有两个服务器/数据库,则ID 2A必须独立地映射到每个服务器上的字符串AXX44328。

我怀疑这就像加密一样 - 丢掉公钥?

4 个答案:

答案 0 :(得分:3)

生成某种随机的唯一字符串就足够了,并将其作为公共ID存储在数据库中。在公共ID上索引表,您可以轻松检索给定公共ID的真实ID(和其他行值)。由于数据库是私有的,没有人可以根据公共ID计算出ID。

生成随机唯一字符串的一种简单方法是获取真实ID +某些盐值的哈希值(例如SHA-1),例如

my $public_id = sha1( $salt . $id );

$salt值应该是一个长的随机字符串,它只生成一次,保存在服务器上,永远不会公开显示。这使得攻击者很难(几乎不可能)通过暴力破解哈希来对公共ID中的真实ID进行逆向工程(如果ID很短且数字很简单,那么没有盐就可以很容易)

这种方法的优点是,只要$ salt值保持不变,相同的$ id将始终映射到相同的$ public_id。


如果这不是一个选项,请生成随机密钥并使用它加密真实ID,并将加密版本用作公共ID。然后,您可以稍后解密此ID以获取真实ID。

答案 1 :(得分:3)

如果您的ID相对较短(15字节或更少),那么我建议使用分组密码加密它们,即AES。 AES使用密钥 K ,密钥长度为128,192或256位(128位就足够了)。由于AES处理的是一个恰好16个字节的块,因此您必须稍微填充您的ID。 “通常”填充(称为“PKCS#5”)包括添加 n 字节( n> = 1 ),它们都具有值 n ,这样得到的长度是合适的(在这里,你想要长度为16)。

因此 ID (敏感数据)转换为 S (可以向公众展示的加扰字符串)是: S = AESencrypt_K(垫(ID))。反向操作是: ID = unpad(AESdecrypt_K(S))。如果 ID 是16个字节或更多,那么加密将使用多次AES调用,并且关于这些调用如何链接在一起存在细微之处。关键字是链接模式,通常的答案是“CBC”。

两种操作都需要知道密钥 K (相同的 K )。这意味着任何可以从 ID 计算 S 的人也可以从 S 计算 ID ,反之亦然。

现在,如果您需要某些实体能够从 ID 计算 S 而不给予他们执行反向操作的权力,那么事情就更复杂了。特别是,您必须没有确定性的过程:如果有一个 S 可以从 ID 计算出来,那么任何人都可以尝试详尽搜索<的可能值< em> ID ,直到找到与给定 S 的匹配项。所以你必须放松模型,因为给定的 ID 可能产生大量可能的加扰字符串 S',这样所有 S'可能被具有“正确”秘密值的人转换回 ID 。这是非对称加密的结果。通常的非对称加密算法是RSA。使用1024位RSA密钥(典型大小以确保正常安全性), ID 的大小最多可达117个字节,而 S'的长度为128个字节(大小增加对应于注入的随机数据,这使得该过程不确定)。如果128字节太多,您可以通过椭圆曲线上的El-Gamal加密获得更短的加密消息(最多约40个字节左右,最多20个字节 ID ),但是您可能很难找到现有的实施方案。

答案 2 :(得分:1)

您没有指定编程语言。这是PHP中的一个示例,类似于RJH对SHA1的建议,但是使用了适当的对称加密算法而不是SHA1,消除了(甚至是远程的)冲突的可能性:


define('KEY', 'S4mPhZg3rQga');

function encrypt($text)
{
    return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, KEY, $text, MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND)));
}

function decrypt($text)
{
    return mcrypt_decrypt(MCRYPT_RIJNDAEL_256, KEY, base64_decode($text), MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND));
}

// example usage:
$C = encrypt('1234');
echo("Public ID: $C\n");

$P = decrypt($C);
echo("Private ID: $P\n");

KEY的值应设置一次,两个服务器中的值相同,并且永远不应显示。您在显示数据时使用encrypt(),在从外部接受数据时使用decrypt()。无需实际存储PublicID,您只需动态计算即可。

答案 3 :(得分:1)

由于您希望能够在两个断开连接的数据库上重新创建标识符,因此您需要拥有某种共享密钥。

这是HMAC的理想场所。通过维基百科从RFC-2104窃取:

  

让:
  H(·)是加密散列函数
  K是填充到右侧的密钥,对散列函数的块大小加上额外的零   m是要验证的消息
  ∥表示连接
  ⊕表示专有或(XOR)
  opad是外部填充(0x5c5c5c ... 5c5c,一个块长的十六进制常量)
  ipad是内部填充(0x363636 ... 3636,一个块长的十六进制常量)

     

然后HMAC(K,m)由数学定义   HMAC(K,m)= H((K⊕opad)∥H((K⊕ipad)∥m))。

但是,您不必自己实施!使用您选择的语言标准库。例如,在Python中:

>>> import hmac
>>> hmac.new(key='abc123secret make me long', msg='This is my unique key #1')
<hmac.HMAC instance at 0xb77bdbac>
>>> _.hexdigest()
'c23a224afa917d13fbef58ee14884269'

现在您有一个可计算的唯一ID。预先计算为数据库中的主键。必要时查找!


作为旁注,请使用盐渍哈希(Google:"don't hash secrets")并使用 NOT 使用加密版数据。前者是因为消息扩展攻击。后者是因为您不必要地以仅仅回复密钥安全性的方式公开数据。

我会链接更多参考资料,但我是新用户。 : - \