【问题标题】:Converting MS SQL Hash Text to Postgres Hash Text将 MS SQL 哈希文本转换为 Postgres 哈希文本
【发布时间】:2019-02-19 03:52:21
【问题描述】:

我正在将我们所有的数据库从 MS SQL 服务器迁移到 Postgres。在这个过程中,我正致力于在 Postgres 中编写等效代码,以生成在 MS SQL 中获得的相同散列文本。

以下是我在 MS SQL 中的代码:

DECLARE @HashedText nvarchar(50) 
DECLARE @InputText nvarchar(50) = 'password'

DECLARE @HashedBytes varbinary(20) -- maximum size of SHA1 output

SELECT @HashedBytes = HASHBYTES('SHA1', @InputText)

SET @HashedText = CONVERT(nvarchar(50), @HashedBytes, 2)

SELECT @HashedText

这将产生值E8F97FBA9104D1EA5047948E6DFB67FACD9F5B73

以下是用 Postgres 编写的等效代码:

DO
$$
DECLARE v_InputText VARCHAR = 'password';
DECLARE v_HashedText  VARCHAR;
DECLARE v_HashedBytes BYTEA;

BEGIN 
  SELECT 
         ENCODE(DIGEST(v_InputText, 'SHA1'), 'hex')
  INTO
         v_HashedBytes;

  v_HashedText := CAST(v_HashedBytes AS VARCHAR);

  RAISE INFO 'Hashed Text: %', v_HashedText;
END;
$$;

这会产生值5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8

花了一些时间后,我了解到在 MS SQL 中将数据类型“NVARCHAR”替换为“VARCHAR”会产生与 Postgres 相同的结果。

现在问题出在 MS SQL 中,我们已经将密码散列并存储在数据库中,如上所示。我无法将 MS SQL 中的散列文本转换为 Postgres,也无法在 Postgres 中生成相同的散列文本,因为 Postgres 不支持 UTF-16 unicode。

所以,我只是想知道是否有以下解决方案的可能性?

  1. 将 MS SQL 中生成的十六进制值转换为十六进制值 等同于使用 VARCHAR 数据类型生成的数据类型(即 Postgres 中的值相同)
  2. 将 UTF8 文本转换为 UTF16 文本 Postgres(甚至通过任何类型的扩展)并生成十六进制值 这相当于在 MS SQL 中生成的值

【问题讨论】:

  • 你不应该使用SHA1 annymore,尤其是没有盐和/或胡椒的情况下,因为现有的SHA1 彩虹表可以在几秒钟内“解密”SHA1 散列。除了SHA1算法在 CPU 上是一种快速算法,但在 GPU 上也是如此,它可以在现代 GPU 硬件上轻松完成每秒 100 万次以上的计算。
  • 这是非常不安全的代码。对于初学者来说,密码似乎是以明文形式传输的。密码也需要被散列 多次 次,即使使用强大的散列算法(如 SHA25、SHA512)也是如此。 1000 次迭代是典型的。单个 SHA1 非常弱
  • 此外,真正的哈希是字节数组,而不是字符串。哈希存储在哪里,以什么形式?作为varbinary(20) 还是varchar? BTW VARCHAR 没有长度并不意味着任意长度。我认为默认长度是 30。您可能已经截断了哈希

标签: postgresql hash


【解决方案1】:

让我们依次看看你的建议:

  1. 将 MS SQL 中生成的十六进制值转换为与使用 VARCHAR 数据类型生成的值等效的十六进制值(与 Postgres 中的值相同)

这归结为将用户的密码从 UTF-16 转换为 UTF-8(或其他编码)并重新散列。要做到这一点,您需要知道用户的密码,理论上,您不知道 - 这就是首先对其进行哈希处理的目的。

在实践中,您使用的是未加盐的 SHA1 哈希,其中存在大型预先计算的表,并且通过 GPU 优化的算法可以进行暴力破解。因此,“灰帽”选项是破解所有用户的密码,然后重新散列它们。

如果您这样做,使用盐和更好的散列函数重新散列它们并将它们转换为 UTF-8 可能是明智的。

  1. 在 Postgres 中将 UTF8 文本转换为 UTF16 文本(甚至通过任何类型的扩展)并生成与 MS SQL 中生成的值等效的十六进制值

理论上,这更简单,您只需要一个例程来进行字符串转换。但是,正如您所发现的,Postgres 中没有对此的内置支持。

对于任何完全由 ASCII 字符组成的字符串,转换是微不足道的:在字符串的每个字节之前插入一个 NULL 字节(十六进制 00)。但这会破坏任何使用不在此范围内的字符的密码。

另一种方法是将生成哈希的责任移出数据库:

  1. 从数据库中检索哈希。
  2. 确保用户的输入在您的应用程序中以 UTF-16 表示,并计算其哈希值。
  3. 如果有效,您现在可以使用更好的算法生成新哈希(因为您知道用户刚刚输入的密码),并将其存储在数据库中,而不是旧哈希。
  4. 一旦所有活跃用户都至少登录过一次,您将没有 SHA1 哈希值,并且可以完全取消对它们的支持。

【讨论】:

  • 感谢您的所有回答!实际上我们使用了 SALT 文本,但是为了不暴露我们自己的 salt 出于安全原因,我没有把那个代码放在这里。 W.r.t.您关于在 Postgres 中的每个字符串字节之前插入 NULL 字节以转换为 UTF16 的建议,您能给我发送任何示例代码吗?我无法开发它。您在应用程序中从 UTF-16 生成哈希然后在所有活动用户至少记录一次后将其删除的替代解决方案听起来也很棒!
猜你喜欢
  • 1970-01-01
  • 2019-10-27
  • 2019-05-23
  • 2011-05-30
  • 2012-10-29
  • 2012-11-11
  • 1970-01-01
  • 1970-01-01
  • 2010-11-16
相关资源
最近更新 更多