你是谁?MySQL和MariaDB认证协议历史(2017)

2020-10-16 06:06:07

在美好的过去,当32MB的内存证明my-huge.cnf这个名字是合理的,当没有人知道谷歌和脸书根本不存在的时候,安全就是…。我该怎么说呢…。有点可爱。计算机病毒没有窃取数百万美元,也没有扰乱选举-它们玩扬基涂鸦,或者告诉你不要玩PC。人们使用telnet和ftp,尽管一些有安全意识的管理员已经知道ssh。

大约在这个时候,或多或少几年,MySQL诞生了。它也有用户,他们必须远离别人的数据,但允许他们使用自己的数据。这需要身份验证。

Michael Wideius(或称Monty)显然意识到一些用户对安全问题疑神疑鬼。即使在早期的MySQL版本中也可以找到证据:

/*偏执狂设置。如果您是偏执狂,请定义I_AM_PARANOID*/ #ifdef I_AM_Paranoid #定义DONT_ALLOW_USER_CHANGE 1 #定义NOT_USE_MYSQL_PWD 1 #endif。

这来自mysql-3.21的global.h。MySQL从未以明文形式将密码从客户端发送到服务器,这一点也就不足为奇了。它发送由密码散列生成的随机字节。从技术上讲,第一个MySQL身份验证协议(如MySQL-3.20,1996)的工作方式如下:

服务器已将密码散列存储在mysql.user表中。不过,散列函数相当简单:for(;*password;password++) { Tmp1=*密码; Hash^=(hash&;63)+tmp2)*tmp1)+(hash<;<;8); Tmp2+=tmp1; }。

在身份验证期间,服务器使用8个随机字母串(称为置乱)开始握手。

客户端计算了该加扰的散列(如上所述),以及密码的散列。这两个数字的异或产生一个32位种子,用于初始化伪随机数生成器。该生成器生成“随机”8个字节,并将它们发送到服务器。

服务器基本上重复了同样的操作-它知道加扰,它有来自mysql.user表的密码散列。因此,它还初始化了一个随机数生成器,生成了8个字节,并将它们与客户端发送的内容进行了比较。

这是个不错的协议。它有明显的优点,例如,密码从来不是明文发送的。也从来没有明码储存过。但是,说真的,32位?即使在1996年,这也是不够的。这就是为什么下一个主要的MySQL版本-3.21-使用64位散列。除此之外,协议保持不变。并且它仍然存在于MySQL-5.6和MariaDB-10.2中(尽管不是默认设置)。幸运的是,它已从MySQL-5.7中删除。我真希望现在没人用它。

正如我们在2000年初突然意识到的那样,该协议的主要缺陷是它以明文形式存储密码。没有开玩笑。它在某种程度上存储了散列,但是客户端只需要散列来进行身份验证,而不需要密码。也就是说,如果有人可以从mysql.user表中读取密码散列,那么只需对客户端库进行很小的修改,就可以直接使用这些散列并以任何人的身份登录。

此外,这个散列函数相当可疑。虽然我们不知道如何逆转它,但我们仍然不完全信任它。事实上,它后来被破解了,但那时我们已经有了替代品。

对于新的协议,我们(即我、康斯坦丁·奥西波夫、彼得·扎伊采夫和其他几个人)设定了以下目标:

这就是双SHA1(或NEW或MYSQL_NATIVE_PASSWORD)协议是如何创建的。它最早是在MySQL-4.1中引入的,至今仍是使用最广泛的MySQL身份验证协议。每个MySQL和MariaDB版本都支持它。它的工作方式如下:

客户端计算以下内容:其中⊕是异或,||是字符串连接。并将其发送到服务器。

服务器不知道SHA1(密码),但是它知道置乱和SHA1(SHA1(密码)),所以它可以计算表达式的第一部分,并且通过XOR可以得到SHA1(密码)。

现在,它所需要做的就是计算上一步的SHA1(密码)的SHA1,它可以将结果与存储在mysql.user表中的内容进行比较。任务完成。

该协议实现了所有目标-嗅探身份验证握手或窃取mysql.user表不会帮助攻击者冒充用户。尽管如此,它仍然不是完美的。服务器收到了SHA1(密码)(因此它可以显示在核心转储中,可以从服务器内存中提取,等等),这足以模拟用户。此外,如果有人能够嗅探身份验证握手并窃取mysql.user表,他将能够重复服务器所做的所有步骤,提取SHA1(密码)并模拟合法用户。虽然这是一个缺陷,但它不是一个大问题-当一个人有密码散列时,通常更容易暴力强行执行它们。我有一种感觉,除非我们求助于公钥密码术,否则这个缺陷无论如何都是不可能修复的。

我们的用户依赖于双SHA1身份验证。生活还在继续。MySQL被Sun收购,Sun被Oracle收购。MariaDB大受欢迎。而且,与所有这些无关的是,SHA1逐渐被认为越来越不安全。一定要做点什么。MySQL是第一个提供替代产品的。实现一个新的身份验证插件的任务被委托给Kristofer Pettersson。我当时不在MySQL中,所以我不知道他在和谁讨论这个问题,他的目标是什么。但基本情况很清楚-远离SHA1并消除最后一个缺陷。他正确地决定使用公钥密码术。因此,新的MySQL5.7身份验证协议(sha256password插件)使用SHA256(SHA2的256位版本)和RSA。它的工作原理是这样的:

客户端从预先分发给客户端的文件中读取服务器的公共RSA密钥。

客户端计算密码和加扰的XOR(根据需要重复以覆盖整个密码),使用服务器的公钥对其进行加密,然后发送到服务器。

服务器使用其秘密RSA密钥解密数据,对结果进行加扰异或以提取客户机的纯文本密码,计算其SHA2,并将其与mysql.user表中存储的值进行比较。

相当直截了当。只有一个麻烦。必须将服务器的公钥分发给所有客户端。而且每个客户端都需要拥有它想要连接的所有服务器的公钥,并根据需要对其进行调整。我可以看到它可能在哪里变得相当烦人,这可能就是为什么如果客户机没有服务器的公钥,服务器在身份验证期间以一次往返为代价提供它的原因。当然,任何有安全意识的人都不应该依赖这一点,客户端如何知道公钥是可信的呢?中间人可以用他自己的公钥替换它,他将能够获得纯文本形式的客户端密码!再说一次,这并不是说它特别糟糕,但是服务器仍然以纯文本形式获得密码。就像在所有以前的身份验证协议中一样。

但MariaDB甚至都没有。我们仍然依赖久经考验的旧的双SHA1协议。银行在抱怨,但它仍然足够安全。尽管如此,根据最近的消息,我们也开始寻找替代方案。请注意,即使考虑到最近的研究,双SHA1仍然是安全的。研究表明,现在不只一个人可以生成SHA1冲突,这意味着一个人可以生成两个具有相同SHA1散列的密码。这对SHA1不利,但并不会真正削弱我们的身份验证。仍然是…。这表明SHA1没有那么多时间了,最终可能会有人找到破解它的方法。

我还使用公钥加密构建了新的身份验证协议。其目标是不是流量嗅探,不是mysql.user表,不是两者一起,即使是完全受损的服务器也无法恢复密码。而且这种行为应该和以前一样--没有要分发的文件,协议中没有新的往返。结果是一个使用ED25519-椭圆曲线数字签名算法的协议,该算法在2 255-19阶有限域上使用爱德华兹曲线(这就是该算法被称为ED-255-19的原因)。曲线和算法本身都是由著名的丹尼尔·J·伯恩斯坦(或简称DJB)发明的。他和他的团队还创建了一些ed25519的参考公共域实现,其中一个在OpenSSH中使用。新的MariaDB身份验证协议也使用这些参考ed25519实现之一,其工作方式如下:

用户的密码是密钥。我们计算SHA512(密码),并应用一些数学魔术将其转换为公钥。此公钥由服务器存储在mysql.user表中。

就这样!。比使用双SHA1简单得多。而且它是尽可能安全的,密码没有存储在服务器上,也没有发送到任何地方,服务器甚至在任何时候都看不到它,也不能从它拥有的信息中恢复它。这里的中间人也没有。没有文件。往返次数相同。在给定mysql.user表的情况下,用户仍然可以暴力破解密码,但我们对此无能为力。

这个新协议首先作为插件在MariaDB-10.1.22中引入,在未来的版本中将更方便地集成到服务器中。