2009-06-03 161 views
30

我正在使用Mysql,并且我认为最好将用户个人信息及其登录名和密码分隔成两个不同的表,然后在两个表之间引用它们。如何最好地存储用户信息和用户登录名和密码

注意:为了澄清我的文章,我了解保护密码(散列,盐等)的技术。我只知道,如果我遵循我生活中其他部分的实践(投资,数据备份,甚至是个人存储),在最坏的情况下(包括表或火),信息在表格之间分裂,可以保护您的额外的数据。

+0

只是为了澄清;你想知道如何正确地在数据库中存储密码,或者你是否想知道用户配置文件数据是否应与基础数据分开?我为前者回答,但重读这个问题时,你似乎想要后者。 – Rob 2009-06-03 23:09:56

+1

大多数答案都关注散列和腌制密码的方法。这是值得的信息,但没有解决OP的问题。 – 2009-06-03 23:20:55

+0

是的,我将使用sha1和salting来存储密码。 – Tim 2009-06-04 12:47:27

回答

35

不要存储密码。如果它坐在磁盘上,它可能会被盗。相反,存储密码散列。 Use the right hashing algorithm,就像bcrypt(其中包含一个盐)。

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

没有必要将密码存储在与登录信息不同的表中。如果一个数据库表被破坏,那么访问同一数据库中的另一个表并不是一个大的飞跃。

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

14

将它们放在同一张表中没有任何问题。事实上,它会更快,所以我强烈推荐它。我不知道你为什么想分裂它。

+1

我严重怀疑它会更快,因为检查名称/密码和userdata将在任何应用程序的非常不同的部分,并在非常不同的时刻完成。想想:你需要每次登录拒绝的有效数据吗?在您接受后,您是否每次阅读个人资料时都需要检查密码? 当然,我通常不打扰,把它放在一起。但这只是为了简单,而不是表现。 – Javier 2009-06-03 22:43:02

+2

不,因为每当你获得用户数据时你都需要加入JOIN。无论是那样的还是你都会有很多重复的信息(例如,用户名和ID都存储在这两个中)等,这两者都不是最优的。无论哪种方式,没有理由将其分成两个不同的表格;无论是出于性能还是简单性,它都没有任何意义。 – 2009-06-03 23:02:22

+1

+1这是回答OP问题的唯一答案(迄今为止)。 – 2009-06-03 23:18:01

0

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

7

我会尝试回答你原来的问题。除非你有很多个人信息要收集,否则将它全部放在一张桌子上是没问题的。在这种情况下,分解它可能是有意义的。应根据您处理的个人信息数量以及需要访问的频率做出该决定。

我想说的大部分时间我会做这样的事情在一个表:

UserID, FirstName, LastName, Email, Password, TempPassword 

但是......如果你收集远不止这些。假设你正在收集电话,传真,出生日期,传记等等。如果大多数信息很少被访问,那么我可能会把它放在自己的表中,并将它与一对一的关系联系起来。毕竟,您在一张桌子上拥有的列数越少,对这张桌子的查询就越快。有时候简化最常访问的表格是有意义的。虽然每当您需要访问个人信息时,JOIN的性能都会受到影响,所以您必须考虑这一点。

编辑 - 你知道吗,我只是想到了一些东西。如果您在用户名或电子邮件字段中创建索引(无论您希望如何),它几乎可以完全消除在用户表中创建太多列的性能缺陷。我说,因为无论何时登录WHERE子句,如果它有一个索引,实际上会非常快速地找到用户名,如果该表中有100列,则无关紧要。 所以我改变了我的看法。我把它放在一张桌子上。;)

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

3

首先,说明(希望)显而易见的,如果你可以以任何方式避免存储用户名和密码,这是一项重大责任,如果您的凭证存储被违反,它可能为同一用户提供对许多其他地方的访问(由于密码共享)。

如果必须存储凭据:

  • 不要存放可逆的形式;使用SHA-256等公认的算法存储散列。使用来自信誉良好的可靠来源的加密软件 - 不要试图自己滚动,你可能会弄错它。
  • 对于每个凭证集,存储salt以及散列数据;这用于“填充”散列,以便两个相同的密码不会产生相同的散列 - 因为这会泄露密码相同。
  • 使用安全的随机生成器。弱随机性是加密相关安全失败的首要原因,而不是密码算法。

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

  • 选择一个好的加密算法 - AES-256,3DES(日期),或公共密钥密码。使用来自信誉良好的可靠来源的加密软件 - 不要试图自己滚动,你可能会弄错它。
  • 对于每个证书集,存储salt(未加密)以及加密的数据;这用于“加密”加密密码,使得两个相同的密码不会产生相同的密文 - 因为这会泄露密码相同。
  • 使用安全的随机生成器。弱随机性是加密相关安全失败的首要原因,而不是密码算法。
  • 将加密/解密密钥与您的数据库分开存储在O/S安全文件中,只能访问您的应用程序运行时配置文件。这样,如果您的数据库被破坏(例如通过SQL注入),您的密钥不会自动受到攻击,因为这需要访问硬盘。如果您的O/S支持与配置文件绑定的文件加密,请使用它 - 它只能提供帮助,而且通常是透明的(例如NTFS加密)。
  • 如果可行,请使用主密码来存储自己加密的密钥。这通常意味着你的应用。在启动时需要输入密码 - 从脚本的参数中提供密码是没有用的,因为如果你的硬盘被破坏了,你必须假定密钥文件和脚本都可以被查看。
  • 如果用户名不必定位帐户记录,则同时加密用户名和密码。
17

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

避免使用诸如MD5或SHA1之类的快速便宜的散列;目标是让攻击者计算彩虹表(基于散列冲突)的代价高昂;一个快速哈希抵消这一点。使用昂贵的散列对于验证场景来说不是问题,因为它对散列的单次运行没有影响。

除了散列之外,还可以用散列值随机生成一个值;一个随机数,然后存储在数据库中并在散列之前与数据串联。这增加了计算冲突时必须生成的可能组合的数量,并因此增加了生成彩虹表的总体时间复杂度。

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

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

有关如何处理密码以及需要关注的问题的详细说明,请参见http://www.matasano.com/log/958/enough-with-the-rainbow-tables-what-you-need-to-know-about-secure-password-schemes

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

2

根据我个人的经验,将个人信息和登录信息存储在个人数据库中是最佳实践。原因是应该发生SQL注入,它是有限的(除非入侵者知道你的数据库的内部布局)到数据所属的表,而不是提供对整个数据集的访问。

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

2

所有这些数据是否总是与用户有1:1的关系?如果您可以预先允许用户拥有多个地址,电话号码等,那么您可能需要将个人信息分解到单独的表格中。

相关问题