首页 > 解决方案 > Oracle 中信用卡号的较短哈希值

问题描述

我以下面的方式使用 STANDARD_HASH 来散列信用卡号。它返回 40 个字符的哈希值。这对于有 16 位数字的信用卡号码来说似乎太过分了。我想节省导出空间。如何在实现这些目标的同时创建更短的哈希:

  1. 具有与 STANDARD_HASH 相同级别的安全性和不可逆性
  2. 保持两个卡号接收相同哈希的可能性非常小(尽管如果这种情况发生几次,没关系)
  3. 导出到 CSV 时,在字符或空间方面具有最短的哈希结果
  4. 使用尽可能少的数据库资源执行此操作
  5. 使用对数据库的只读访问权限执行此操作

如果存在实现目标 2 和 3 的方法,那么我希望可以通过使用此方法对 STANDARD_HASH 的输出进行散列来实现目标 1。

SELECT STANDARD_HASH(TRIM('  123456789123456789  ' )) FROM DUAL;

TRIM 删除空格,然后 STANDARD_HASH 返回长度为 64 的哈希。

这是 db<>fiddle 上的相同示例: https ://dbfiddle.uk/?rdbms=oracle_18&fiddle=7cd086f1b60f69eb3bc6f54d4a211844

数据库版本为“Oracle Database 18c Enterprise Edition”。

标签: oraclehash

解决方案


64 的长度不是结果的长度,而是它的显示方式。STANDARD_HASH 返回一个 RAW 值,显示为十六进制。

您可以使用https://docs.oracle.com/database/121/TTPLP/u_raw.htm#TTPLP71498上的 UTL_RAW 函数将此原始值转换为可用的值

例如

  SELECT UTL_RAW.CAST_TO_VARCHAR2 (STANDARD_HASH(TRIM('  123456789123456789  ' ))) FROM DUAL;

请注意,当您在小提琴中尝试此操作时,您会发现一些 ? 代表不可打印的字符,因此在您的导出中允许这样做。

编辑添加:STANDARD_HASH 默认使用 SHA1 - 但 MD5 存在漏洞 - 最好将额外参数添加到 STANDARD_HASH 以使用更长的 SHA -请参阅https://docs.oracle.com/database/121/SQLRF/functions183 .htm#SQLRF55647

  SELECT UTL_RAW.CAST_TO_VARCHAR2 (STANDARD_HASH(TRIM('  123456789123456789  ' ), ‘SHA256’)) FROM DUAL;

编辑以解决 5 点:

  1. 它使用相同的 STANDARD_HASH 所以是相同的
  2. SHA1 容易发生冲突,所以如上交换到 SHA256 或更高
  3. STANDARD_HASH 使用行业标准的散列算法。就是这样。请注意,就其本质而言,散列返回二进制值,因此您有责任将它们转换为适当的格式 - 例如对于 CSV 文件,您可以转换为 Base64(请参阅Oracle 中的 Base64 编码和解码
  4. 5. 没有额外的资源

编辑以回应附加评论:

是的,您所说的完整 SELECT 看起来是正确的:

select utl_raw.cast_to_varchar2(utl_encode.base64_encode(
     STANDARD_HASH(TRIM('  123456789123456789  ' ), 'SHA1')))  FROM dual;

Base64 一次对 3 个字节组进行操作,并为每个短字节附加“=”。SHA1 哈希总是 20 字节,所以总是短 1 字节。

因此,您可以将尾随的“=”修剪掉-尽管我建议您不要这样做(精益代码胜过过早的优化)。例如,如果您随后决定从 SHA1 升级到 SHA256,则会生成具有不同字节数的散列,因此最后可能会出现 0 或 2 个“=”,因此会出现奇怪的错误。

是的,“+”和“/”是 Base64 输出中的有效字符(以及 0-9 和大小写字母 - 因此总共 64 个字符,加上 =),但重要的是逗号和双引号不是 - 所以是的,Base64 字符串可以安全地转换为 CSV 格式。

仅供参考,Base64 的快速总结(因为我猜你喜欢我总是喜欢对我正在处理的内容有一个概述)

Base64 用于将二进制数据流转换为可打印的字符串。现在 3 个字节的二进制数据是 24 位,当然可以看作 4 批 6 位(我们可以忽略字节边界)。任何 6 位集合都有 2^6 = 64 个可能的值(因此是 Base64 名称),它们表示为 64 个字符:

  • 大写字母
  • 小写字母(所以是的,区分大小写)。
  • 数字 0-9
  • “+”和“/”

因此 Base64 输出中的每个字符代表二进制数据的下 6 位。


推荐阅读