如何最好地存储用户信息和用户登录名和密码

Posted

技术标签:

【中文标题】如何最好地存储用户信息和用户登录名和密码【英文标题】:How to best store user information and user login and password 【发布时间】:2021-12-25 14:46:48 【问题描述】:

我正在使用 mysql,我假设最好将用户个人信息及其登录名和密码分开到两个不同的表中,然后在两者之间引用它们。

注意:为了澄清我的帖子,我了解保护密码的技术(哈希、盐等)。我只知道,如果我遵循我生活中其他部分(投资、数据备份,甚至个人存储)的做法,那么在最坏的情况下(包括表格或火灾),在表格之间拆分信息可以保护您的附加数据。

【问题讨论】:

澄清一下;您想知道如何在数据库中正确存储密码,还是只想知道是否应该将用户配置文件数据与基本帐户数据分开?我回答的是前者,但在重新阅读问题后,你似乎想要后者。 大多数答案都集中在散列和加盐密码的方法上。这是有价值的信息,但没有解决 OP 的问题。 是的,我将使用 sha1 和 salting 存储密码。 【参考方案1】:

不要存储密码。如果它曾经放在磁盘上,它可能会被盗。相反,存储密码哈希。 Use the right hashing algorithm,如 bcrypt(包括盐)。

编辑:OP已回复说他理解上述问题。

无需将密码存储在与登录名不同的物理表中。如果一个数据库表被破坏,访问同一个数据库中的另一个表并不是一个很大的飞跃。

如果您非常关注安全性和深度安全性,您可能会考虑将用户凭据存储在与您的域数据完全分开的数据存储中。一种常用的方法是将凭据存储在 LDAP 目录服务器中。这也可能有助于您以后进行的任何单点登录工作。

【讨论】:

+1 除了 SHA 建议之外的所有内容。 SHA 和 MD5 属于相同的、不足的散列算法类别——从安全的角度来看,它们与自适应散列相比都相形见绌,如下 Rob 所述。 没有真正回答这个问题。 @musicfreak:我不同意,因为问题的表述方式可能暗示 OP 没有考虑用户管理的这一方面,这比是否存储用户名重要几个数量级和密码散列在单独的表中。一个好的答案可以解决更大的问题。当然,你可以不同意。 实际上问题是问您是否应该为个人信息创建一个表(我假设名字和姓氏、电话号码等)和一个单独的登录表(用户名/密码组合) .这实际上是一个很好的问题。但我在这里看到的大多数答案都与安全性无关。 是的,我最初的问题与您的表格是否受到损害有关,我宁愿提供一份数据而不是两份数据。【参考方案2】:

密码应存储为加密哈希,这是一种不可逆的操作,可防止读取纯文本。在对用户进行身份验证时,对输入的密码进行相同的哈希处理并进行哈希比较。

避免使用快速且廉价的哈希,例如 MD5 或 SHA1;目标是让攻击者计算彩虹表(基于哈希冲突)变得昂贵;快速哈希抵消了这一点。使用昂贵的散列对于身份验证场景来说不是问题,因为它不会对散列的单次运行产生影响。

除了散列之外,还用随机生成的值对散列进行加盐;一个随机数,然后将其存储在数据库中并在散列之前与数据连接。这增加了计算碰撞时必须生成的可能组合的数量,从而增加了生成彩虹表的整体时间复杂度。

您的密码哈希列可以是固定长度;您的加密哈希应该输出可以编码为固定长度的值,这对于所有哈希都是相同的。

尽可能避免使用自己的密码验证机制;使用现有的解决方案,例如bcrypt

可以在http://www.matasano.com/log/958/enough-with-the-rainbow-tables-what-you-need-to-know-about-secure-password-schemes 找到有关如何处理密码以及您需要关注的内容的精彩说明。

最后一点,请记住,如果攻击者获得了对您数据库的访问权限,那么您最关心的应该是他们可能访问的任何敏感或个人身份信息,以及他们可能造成的任何损害。

【讨论】:

博文已移至chargen.matasano.com/chargen/2007/9/7/… @nikoss 该错误应该已修复。阅读链接的错误报告中的倒数第二条评论。【参考方案3】:

将它们放在同一张桌子上并没有错。事实上,它会更快,所以我强烈推荐它。我不知道你为什么要拆分它。

【讨论】:

我严重怀疑它会更快,因为检查名称/密码和用户数据将在任何应用程序的非常不同的部分,并且在非常不同的时刻完成。想一想:您是否需要每次登录拒绝的有效数据?接受后,每次阅读个人资料时都需要检查密码吗?当然,我通常不会打扰,并将它们放在一起。但这只是为了简单,而不是性能。 不,因为您需要在获取用户数据时执行 JOIN。要么这样,要么你会有很多重复的信息(例如,用户名和 ID 都存储在两者中,等等),这两者都不是最佳的。无论哪种方式,都没有理由将它分成两个不同的表。它只是没有任何意义,无论是性能还是简单性。 +1 这是(到目前为止)回答 OP 问题的唯一答案。 尽管 Javier 正在考虑性能问题。如果您正在收集大量个人信息,而不必在每次用户登录时都加载,那么将这些信息放在自己的表中可能是有意义的。 对不起,我这么说的原因是,当您可以将更多行放入更少量的数据中时,每个查询都会更快。如果您的用户表中有 100 列,而您在 95% 的时间里只检索其中两列,那么您可能会遇到设计问题。【参考方案4】:

我将尝试回答您最初的问题。除非您只需要收集大量个人信息,否则将所有内容放在一张桌子上就可以了。在这种情况下,将其拆分可能是有意义的。该决定应基于您处理的个人信息量以及需要访问的频率。

我会说大多数时候我会在一张桌子上做这样的事情:

UserID, FirstName, LastName, Email, Password, TempPassword

但是...如果您收集的远不止这些。假设您正在收集电话、传真、出生日期、传记等。如果大多数信息很少被访问,那么我可能会将其放在自己的表格中,并通过一对一的关系将其连接起来。毕竟,表上的列越少,对该表的查询就越快。有时简化最常访问的表是有意义的。尽管每当您确实需要访问该个人信息时,JOIN 都会对性能造成影响,因此您必须考虑这一点。

编辑——你知道吗,我只是想到了一些事情。如果您在用户名或电子邮件字段(无论您喜欢哪个)上创建索引,它几乎可以完全消除在用户表中创建如此多列的性能缺陷。我这么说是因为每当您登录时,如果用户名有索引,WHERE 子句实际上会非常快速地找到用户名,并且该表中是否有 100 列也没关系。 所以我改变了看法。我会把它们都放在一张桌子上。 ;)

在任何一种情况下,由于安全似乎是一个热门话题,密码应该是一个哈希值。我建议使用 SHA1(如果您真的很担心,建议使用 SHA256)。 TempPassword 也应该使用散列,它只用于忘记密码功能。显然,使用哈希您无法解密并向用户发送其原始密码。因此,您可以生成一个他们可以用来登录的临时密码,然后强制他们在登录后再次更改密码。

【讨论】:

不要存储临时密码。这是一个洞。 临时密码也应该是 SHA1 哈希。那怎么是个洞? 只是说明一下,临时密码的原因是为了防止您在使用忘记密码功能时无意中覆盖了您的原始密码。它仍然是安全的。【参考方案5】:

所有这些数据都会与用户保持 1:1 的关系吗?如果您可以预见允许用户拥有多个地址、电话号码等,那么您可能需要将个人信息拆分到单独的表格中。

【讨论】:

【参考方案6】:

首先,声明(希望)显而易见,如果您可以以任何方式避免存储用户名和密码,请这样做;这是一项重大责任,如果您的凭据存储遭到破坏,它可能会为同一用户提供对许多其他地方的访问权限(由于密码共享)。

如果您必须存储凭据:

不要存储可逆形式;使用公认的算法(如 SHA-256)存储哈希。使用信誉良好、可信赖来源的加密软件 - 不要试图自己动手,您可能会弄错。 对于每个凭据集,将盐值与散列数据一起存储;这用于“初始化”哈希,以便两个相同的密码不会产生相同的哈希 - 因为这表明密码是相同的。 使用安全的随机发生器。弱随机性是与加密相关的安全失败的第一大原因,而不是密码算法。

如果您必须存储可逆凭据:

选择一个好的加密算法 - AES-256、3DES(过时)或公钥密码。使用信誉良好、可信赖来源的加密软件 - 不要试图自己动手,您可能会弄错。 对于每个凭据集,将盐(未加密)与加密数据一起存储;这用于“启动”加密密码,以便两个相同的密码不会产生相同的密文 - 因为这表明密码是相同的。 使用安全的随机发生器。弱随机性是与加密相关的安全失败的第一大原因,而不是密码算法。 将加密/解密密钥与您的数据库分开存储在一个操作系统安全文件中,该文件只能由您的应用程序运行时配置文件访问。这样,如果您的数据库被破坏(例如通过 SQL 注入),您的密钥不会自动受到攻击,因为这通常需要访问 HDD。如果您的操作系统支持与配置文件绑定的文件加密,请使用它 - 它只会有所帮助,而且通常是透明的(例如 NTFS 加密)。 如果可行,请存储使用主密码加密的密钥本身。这通常意味着您的应用程序。将需要在启动时键入该密码 - 在脚本的参数中提供它没有好处,因为如果您的硬盘被破坏,您必须假设可以查看密钥文件和脚本。 如果用户名不是查找帐户记录所必需的,请同时加密用户名和密码。

【讨论】:

【参考方案7】:

根据我的个人经验,在这种情况下,将个人信息和登录信息存储在各个数据库中是最佳做法。原因是如果发生 SQL 注入,它仅限于(除非渗透者知道数据库的内部布局)数据所属的表,而不是提供对整个数据集团的访问。

但是,请注意,这可能是以需要执行更多查询为代价的,因此会影响性能。

【讨论】:

或者你可以是一个细心的程序员,并首先防止 SQL 注入攻击。 ;) 当然 =P 当然,对于实施的每一项对策,都有一个规避措施。因此,不妨减少损失,让获取无关信息变得更加困难。【参考方案8】:

您应该将它们存储在同一张表中,并使用单向加密。 MD5 可以工作,但很弱,所以您可以考虑使用 SHA1 或其他方法。将这 2 个项目存储在单独的表中没有任何好处。

【讨论】:

没有单向加密这回事;该术语是加密哈希。 MD5 和 SHA1 是快速散列算法,对于密码散列不是一个好主意。您应该使用存储在数据库中的随机 nonce 对哈希进行加盐。 en.wikipedia.org/wiki/One-way_encryption 实际上,选择使用一个术语而不是另一个术语并不像所传达的想法那么重要,许多人使用术语“单向加密”并被普遍理解。

以上是关于如何最好地存储用户信息和用户登录名和密码的主要内容,如果未能解决你的问题,请参考以下文章

数据库中的登录名和密码存储

如何在应用程序中保存用户登录名和密码

sqlserver登录名和用户名的区别和联系

如何在数据库里查询用户名和密码

Delphi中登录时怎么在数据库中查找用户名和密码?

模拟用户登录爬取淘宝数据