在数据库中存储用户名和密码是否安全?

3

我让人们在一个团队中提交用户名和密码,我需要知道将此代码提交到数据库中是否安全,或者即使在数据库中使用是否安全。

MySQLCon.Open()
Dim SQLADD As String = "INSERT INTO members(username,password) VALUES(@memberToAdd, @memberPassword)"
COMMAND = New MySqlCommand(SQLADD, MySQLCon)
COMMAND.Parameters.AddWithValue("@memberToAdd", memberToAdd.Text)
COMMAND.Parameters.AddWithValue("@memberPassword", membersPassword.Text)
COMMAND.ExecuteNonQuery()
MySQLCon.Close()
MySQLCon.Dispose()

我使用参数来避免SQL注入攻击。

----------------------------------------------------------------------------------

这并不是重复的问题,因为它是通过不同的方式询问和存储密码。它使用MD5对密码进行哈希。


6
不要存储密码本身,而应该存储加盐哈希后的密码。很多大公司的未经哈希处理的密码已经被窃取,所以这种事情也可能发生在你身上。 - Eric J.
@EricJ。我很困惑,从未听说过这个。 - AfterShotzZHD
1
https://dev59.com/emw05IYBdhLWcg3wYw5s - Eric J.
@EricJ,这并没有帮助我,反而让我更加困惑了。 - AfterShotzZHD
不太确定还能用多简单的方式来解释了... - Douglas Barbin
2个回答

10

使用基本安全措施存储密码的流程非常简单:

  • 对密码进行哈希处理并加盐
  • 为每个用户/密码使用不同的盐
  • 将盐与哈希密码一起存储在数据库中
  • 当用户尝试登录时,通过相同的方法运行尝试的密码并进行比较。

如果他们输入了正确的密码,则哈希密码将匹配。哈希保护用户免受攻击,同时也保护清洁工从显示成员表的屏幕旁边经过时无意中窥视到密码。

创建盐和哈希密码

' salt size is 32 (0-31
Private Const SaltSize As Integer = 31
...

Dim dbPW As String = TextBox1.Text
Dim dbSalt = CreateNewSalt(SaltSize)
' eg: "dsEGWpJpwfAOvdRZyUo9rA=="

Dim SaltedPWHash As String = GetSaltedHash(dbPW, dbSalt)
' examples:
' using SHA256: bbKN8wYYgoZmNaG3IsQ2DPS2ZPIOnenl6i5NwUmrGmo=
' using SHA512: 
' 0vqZWBIbOlyzL25l9iWk51CxxJTiEM6QUZEH1ph+/aNp+lk4Yf8NYv8RLhYtbqCNpOqO3y8BmM+0YWtbAhE+RA=="

将密码哈希值和盐作为用户记录的一部分存储。 盐不是秘密,但在用户更改密码时更改它。

比较登录尝试

' check if PW entered equals DB
Dim pwTry = TextBox2.Text
' hash the login attempt using the salt stored in the DB
Dim pwLogin = GetSaltedHash(pwTry, dbSalt)

' compare the hash of what they entered to whats in the DB:
If String.Compare(SaltedPWHash, pwLogin, False) = 0 Then
    ' okay!
    Console.Beep()
End If

如果用户输入相同的密码,应该得到相同的哈希值,就这么简单。哈希代码并不是非常复杂:

哈希方法

Private Function GetSaltedHash(pw As String, salt As String) As String
    Dim tmp As String = pw & salt

    ' or SHA512Managed
    Using hash As HashAlgorithm = New SHA256Managed()
        ' convert pw+salt to bytes:
        Dim saltyPW = Encoding.UTF8.GetBytes(tmp)
        ' hash the pw+salt bytes:
        Dim hBytes = hash.ComputeHash(saltyPW)
        ' return a B64 string so it can be saved as text 
        Return Convert.ToBase64String(hBytes)
    End Using

End Function

Private Function CreateNewSalt(size As Integer) As String
    ' use the crypto random number generator to create
    ' a new random salt 
    Using rng As New RNGCryptoServiceProvider
        ' dont allow very small salt
        Dim data(If(size < 7, 7, size)) As Byte
        ' fill the array
        rng.GetBytes(data)
        ' convert to B64 for saving as text
        Return Convert.ToBase64String(data)
    End Using
End Function
  • 使用类似GUID(System.Guid.NewGuid.ToString)作为盐看起来很诱人,但是使用密码随机数生成器并不难。
  • 与哈希密码类似,由于编码方式的不同,返回字符串较长。
  • 每当用户更改密码时,请创建一个新的盐。不要使用全局盐,这样做会使目的失效。
  • 您也可以将密码哈希多次。关键部分在于使其需要长时间才能尝试所有各种组合,以防止攻击。
  • 这些函数是Shared/static类成员的理想候选者。

还要注意,由Kenneth链接的文章也值得一读。


请注意,文章提到:盐应存储在用户帐户表中,并与哈希值一起存储。这并不意味着您必须在数据库中有一个Salt列。链接的文章中展示了以下内容:

Dim dbPW As String = TextBox1.Text
Dim dbSalt = CreateNewSalt(SaltSize)

' get the salted PW hash
Dim SaltedPWHash As String = GetSaltedHash(dbPW, dbSalt)
' store salt with the hash:
SaltedPWHash = String.Format("{0}:{1}", dbSalt, dbPW)
' salt + ":" + hashed PW now ready to store in the db

将密码哈希值中的盐分离出来:

Dim SaltAndPWHash = rdr.Item("PWHash").ToString()

Dim split = SaltAndPWHash.Split(":"c)    ' split on ":"
Dim Salt = split(0)                      ' element(0) == salt
Dim StoredPWHash = split(1)              ' element(1) == hashed PW

你需要两部分:在你对尝试登录的密码进行哈希处理后,将其与split(1)进行比较。


1
这是一个可接受的解决方案。如果您使用了慢哈希方法来避免暴力攻击,例如PBKDF2或bcrypt,那就更好了。 - Kenneth
是的,但我想尽可能地简单,以便那些(像OP一样)以前从未听说过“哈希”这个词的人可以理解。 - Ňɏssa Pøngjǣrdenlarp
1
@Plutonix我认为在数据库中存储salt并让黑客看到使用了什么salt是不好的。 - AfterShotzZHD
这是非常正常的。如果你阅读一些资料,你会发现盐并不需要保密。它不是第二个密码,但可以使某些攻击方法无效。例如,请参见这个(还有评论!)还有这个,其中提到你不能真正保密地保存盐,除非使用另一个密钥 - Ňɏssa Pøngjǣrdenlarp
@Plutonix,Console.beep是表示密码正确还是错误?哪个更好?SHA512Managed还是SHA256Managed? - AfterShotzZHD
蜂鸣声表示它们匹配,如果不匹配,则String.Compare()返回非零值。SHA256Managed将返回一个更长的哈希值,正如第一个块中的注释所示。 - Ňɏssa Pøngjǣrdenlarp

1
不,你不应该在数据库中存储明文密码。原因是如果你的数据库被黑客攻击/盗取/破坏,所有用户的密码都会暴露给黑客。相反,你应该执行以下操作: - 当用户注册时,在数据库中保存他的用户名和密码的哈希版本 - 当用户尝试登录时,从数据库获取用户名,对提供的密码进行哈希处理,并将其与数据库中的哈希密码进行比较。 哈希是一种将字符串转换为不同字符串的方法,其中只能单向转换(也就是说,相同的输入始终会生成相同的输出,但如果你只有输出,则无法获得输入)。 要了解如何哈希字符串,请阅读以下文章,其中包含不同语言的代码示例:https://crackstation.net/hashing-security.htm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接