PasswordHash的比较是在客户端级别还是数据库级别进行的?

时间:2014-06-19 02:52:59

标签: c# winforms tsql sql-server-2008-r2

我需要澄清一些关于用户身份验证的事情,因为我想知道它的正确完成,

有人告诉我,身份验证是一个关注安全性的过程。因此,应尽可能从客户端隐藏身份验证过程,并且客户端应仅接收标志值(1 =密码正确且经过身份验证,-1 =密码错误)和/或经过身份验证的用户的用户名。所以它应该是一个应该在后端发生的SQL操作。因此,详细过程应该是,客户端表单将用户名和散列/加密密码发送给SQL,SQL进行身份验证,并将带有用户名的1 / -1作为返回值和输出发送给客户端。

但是当我在网上搜索时,在用户身份验证上,情况并非如此,我在网上看到的所有线程,无论是应用程序是Windows还是网页,开发人员都会进行两项操作:

  1. 在SQL Server中,用户名搜索密码的saltHash值,然后将saltHash值和PasswordHash一起返回到客户端表单/或业务层

  2. 在客户端或BLL中,使用输入的密码和返回的saltHash值生成PasswordHash,然后将此passwordHash与返回的passwordHash进行比较。如果匹配密码正确,如果密码不正确。

  3. 这实际上是开发人员编写代码以在登录事件中对用户进行身份验证的方式吗?如果是这样,基本上密码比较发生在客户端(无论是在表单中还是在业务层中),那么通过将实际的saltHash和passwordHash暴露给客户端会不会带来巨大的安全风险?

    如果有人可以给我写一些代码来演示SQL和C#的登录/认证过程,那将是一件令人高兴的事!

    PS-当你回复时请不要使用LINQ,LINQ to SQL或实体框架。目前我不知道他们。还在学习它们。请从Ado .NET回复

    感谢

4 个答案:

答案 0 :(得分:4)

这是一个更大的利弊讨论,很难说它一般。客户端哈希的优点:

  • 由于加密安全哈希是计算密集型的,通过将它们推送到客户端,服务器的负载会减少。
  • 服务器永远不会看到实际的密码,并且由于用户在站点之间共享密码,如果您的系统遭到入侵,您可以声称密码没有泄露。

服务器端哈希的优点:

  • 计算哈希的代码不适用于多个客户端,即适用于各种移动设备,如Windows Phone,Android和IOS以及浏览器。有时,当存在兼容性差异时,也需要为浏览器编写专门的代码。
  • 哈希可以更“安全”,例如你可以为每个用户提供随机盐,这使得如果数据库遭到破坏,某些人在暴力攻击密码时计算成本很高。如果发生违规并且用户更改密码,这将为您提供更多时间通知用户。

其他一些指导原则:

  • 绝不在DB中存储加密密码或纯文本密码。您不能保证有权访问数据库的每个人都不会查看密码,被黑客攻击或犯错并妥协。
  • 此类流量必须始终通过TLS或SSL,以防止许多攻击(如窃听,MITM,重播等)。
  • 始终对所有加密操作使用加密函数(例如SHA2用于散列,PBKDF2用于导出盐等)。

以下是有关如何针对客户端与服务器方案进行密码哈希处理的一些指导原则。

如果服务器上有散列:

  • 当用户首次注册时:
    • 生成随机盐
    • 使用此盐哈希密码
    • 将salt和密码哈希存储在DB
  • 当用户登录时
    • 从数据库中读取盐
    • 计算密码哈希
    • 与数据库中的内容进行比较

如果客户端上有散列:

  • 当用户首次注册时:
    • 根据客户端
    • 上的某些用户属性(例如用户名)生成salt
    • 使用客户端上的salt
    • 散列密码
    • 将密码哈希发送到服务器,并存储数据库
  • 当用户登录时
    • 根据相同的用户属性生成salt(例如,您可以始终使用用户名)
    • 使用客户端上的salt
    • 散列密码
    • 将密码哈希发送到服务器,与数据库中的密码进行比较

答案 1 :(得分:2)

客户端/服务器应用程序和Web应用程序之间的方法可能相同,但是直接访问SQL数据库的Windows应用程序是另一回事。您可能确实希望避免泄露哈希密码,但盐并不需要是私有的。您可以为用户和哈希客户端获取salt,然后比较服务器端。

我不知道SQL是否有实际的密码哈希算法(mcrypt,PBKDF2等),或者仅限于像SHA系列这样的纯加密算法,但是服务器外部散列的好处是你可以选择你的哈希算法。你也可以围绕它构建一些逻辑。例如,您可以存储针对单个用户使用的哈希算法,然后如果它在将来中断,您可以在下次登录时将其更新为更安全的算法。

您还必须意识到,无论您做什么,除了SQL身份验证之外,其实际安全性都很小。修改程序以忽略SQL服务器响应的内容并继续进行,就像登录成功一样,这是相当简单的。如果您需要实际的安全性,那么您需要一个位于客户端和数据库之间的应用程序服务器。通过简单的身份验证来完成程序,查看它的作用并直接或在其他程序中使用该信息也是微不足道的。

关于重用,将认证分离到单独的模块并在两个应用程序中重用该模块将是更好的方法。 ASP.NET内置了一些robust authentication,因此我会将其视为使用或作为示例。 Crypto.HashPassword()已经使用了当前接受的最佳做法,只要您为每个用户提供相对较长(例如8个字符)的随机盐。

答案 2 :(得分:0)

我会使用以下方法获取随机盐,但我不能在登录用户事件中使用它,因为即使用户输入正确的信用证,它也将返回失败的身份验证。这是因为登录表单中输入的密码将使用随机盐进行哈希处理,此盐与此用户的数据库中的内容不同

    private static byte[] GetSalt()
    {
        RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
        byte[] b = new byte[32];
        rng.GetBytes(b);
        return b;
    }

答案 3 :(得分:0)

这是用户表结构

 CREATE TABLE [dbo].[Users](
[UserId] [int] NOT NULL IDENTITY(1,1) PRIMARY KEY,
[LoginName] [varchar](256) NOT NULL UNIQUE,
[UserName] [varchar](256) NOT NULL,
[EmailAddress] [varchar](256) NULL,
[IsActive] [bit] NOT NULL,
[UserPasswordHash] [varbinary](64) NULL,
[UserPasswordSalt] [varbinary](32) NULL
)
GO