How to best store user information and user login and password
我使用的是MySQL,我假设最好将用户的个人信息、登录名和密码分为两个不同的表,然后在两个表之间引用它们。
注意:为了澄清我的帖子,我了解保护密码的技术(hash、salt等)。我只知道,如果我在生活的其他方面(投资、数据备份、甚至个人存储)遵循这些做法,那么在最坏的情况下(包括表或火灾),将信息拆分到表中可以保护您的附加数据。
不要存储密码。如果它曾经放在磁盘上,它可能会被偷。相反,存储密码散列。使用正确的哈希算法,如bcrypt(其中包括salt)。
编辑:OP已经回复说他理解上述问题。
不需要将密码存储在与登录名物理上不同的表中。如果一个数据库表受到破坏,那么访问同一数据库中的另一个表并不是一个很大的飞跃。
如果您足够深入地关注安全性和安全性,那么可以考虑将用户凭据存储在与域数据完全独立的数据存储中。一种常用的方法是将凭证存储在LDAP目录服务器中。这也可以帮助您以后进行的任何单点登录工作。
密码应存储为加密哈希,这是一个不可逆的操作,可防止读取纯文本。对用户进行身份验证时,密码输入将遵循相同的哈希过程,并对哈希进行比较。
避免使用快速而便宜的散列(如MD5或SHA1);目的是让攻击者计算彩虹表(基于散列冲突)变得昂贵;快速散列可以抵消这一点。对于身份验证方案,使用昂贵的哈希不是问题,因为它不会对哈希的单次运行产生任何影响。
除了散列之外,还要将散列与随机生成的值salt;nonce,然后将其存储在数据库中,并在散列之前与数据连接。这增加了计算碰撞时必须生成的可能组合的数量,从而增加了生成彩虹表的总体时间复杂性。
密码哈希列可以是固定长度;加密哈希应该输出可以编码为固定长度的值,所有哈希的值都相同。
尽可能避免使用自己的密码认证机制;使用现有的解决方案,如
有关如何处理密码以及您需要关注的内容的详细说明,请访问http://www.matasano.com/log/958/enough-with-the-rainbow-tables-what-you-need-to-know-about-secure-password-schemes。
最后一点要注意的是,如果攻击者能够访问您的数据库,那么您最关心的可能是他们可能访问的任何敏感或个人识别信息,以及他们可能造成的任何损坏。
把它们放在同一张桌子上没什么问题。事实上,它会快得多,所以我强烈推荐它。我不知道你为什么要分开。
我试着回答你原来的问题。把这些都放在一张桌子上很好,除非你有很多个人信息要收集。在这种情况下,把它分开可能是有意义的。这个决定应该基于你正在处理的个人信息的数量和访问的频率。
大多数时候我会在一张桌子上做类似的事情:
1 | UserID, FirstName, LastName, Email, Password, TempPassword |
但是…如果你收集的不止这些。假设你正在收集电话、传真、出生日期、传记等信息,如果这些信息中的大部分很少被访问,那么我可能会将它们放在自己的表格中,并将其与一对一的关系联系起来。毕竟,表中的列越少,对该表的查询就越快。有时简化访问最多的表是有意义的。当你确实需要访问个人信息时,加入了一个性能冲击,所以这是你必须考虑的事情。
编辑——你知道吗,我只是想到了一些事情。如果您在用户名或电子邮件字段上创建一个索引(无论您喜欢哪个字段),它几乎可以完全消除在用户表中创建这么多列的性能缺陷。我这么说是因为每当您登录时,如果用户名有索引,那么WHERE子句实际上会非常快速地找到用户名,而如果该表中有100列,则无所谓。所以我改变了我的看法。我会把它们放在一张桌子上。;)
在这两种情况下,由于安全性似乎是一个流行的主题,所以密码应该是散列值。我建议Sha1(如果你真的很担心的话,我建议Sha256)。temppassword还应该使用哈希,它只用于忘记密码功能。显然,使用哈希,您无法解密并向用户发送其原始密码。因此,您可以生成他们可以登录的临时密码,然后在登录后强制他们再次更改密码。
首先,如果你能以任何方式避免存储用户名和密码,那么说明(希望)显而易见;这是一个很大的责任;如果你的凭证存储被破坏,它可能会为同一个用户提供许多其他地方的访问权限(由于密码共享)。
如果必须存储凭据:
- 不要存储可逆形式;使用识别的算法(如sha-256)存储哈希。使用来自信誉良好、值得信赖的来源的加密软件-不要试图自己滚动,你很可能会弄错。
- 对于每个凭证集,存储一个salt和散列数据;这用于"填充"散列,这样两个相同的密码就不会产生相同的散列,因为这会提供相同的密码。
- 使用安全的随机生成器。弱随机性是导致与加密相关的安全失败的头号原因,而不是密码算法。
如果必须存储可逆凭据:
- 选择一个好的加密算法-AES-256、3DES(日期),或者一个公钥密码。使用来自信誉良好、值得信赖的来源的加密软件-不要试图自己滚动,你很可能会弄错。
- 对于每个凭证集,存储一个SALT(未加密)和加密数据;这用于"优化"加密密码,以使两个相同的密码不会产生相同的密码文本,因为这会使密码相同。
- 使用安全的随机生成器。弱随机性是导致与加密相关的安全失败的头号原因,而不是密码算法。
- 将加密/解密密钥与数据库分开存储在一个O/S安全文件中,只能由应用程序运行时配置文件访问。这样,如果您的数据库被破坏(例如通过SQL注入),您的密钥就不会自动受到攻击,因为这通常需要访问HDD。如果您的O/S支持绑定到配置文件的文件加密,请使用它——它只能起到帮助作用,而且通常是透明的(例如,NTFS加密)。
- 如果可行,存储用主密码加密的密钥本身。这通常意味着你的应用程序。将需要在启动时键入密码-在脚本的参数中提供密码是没有好处的,因为如果您的HDD被破坏,您必须假定可以查看密钥文件和脚本。
- 如果不需要用户名来定位帐户记录,请同时加密用户名和密码。
所有这些数据是否都与用户保持1:1的关系?如果您可以放弃允许用户拥有多个地址、电话号码等,那么您可能需要将个人信息分解成一个单独的表。
根据我的个人经验,在这种情况下,将个人信息和登录信息存储在单个数据库中是最佳做法。原因是,如果发生SQL注入,它将限制(除非渗透者知道数据库的内部布局)到数据所属的表,而不是提供对整个数据集合的访问。
但是,请注意,这可能会以执行更多查询为代价,因此会影响性能。
您应该将它们存储在同一个表中,并使用单向加密。MD5可以工作,但很弱,所以您可能会考虑类似于sha1或其他方法的东西。将这两个项目存储在单独的表中没有好处。