我正在使用C#开发一个客户端应用程序,它将与服务器(php页面)进行通信以获取凭据和一些关键服务。我想知道在客户端的机器上存储一个良好的哈希密码是否危险?通过“well hashed”,我的意思是使用一个众所周知的安全散列函数随机种子。出于本讨论的目的,假设源是免费提供的(因为所有二进制文件都可以进行逆向工程)。
我的想法是,我会在用户的计算机上存储用户名和散列密码,并且该用户名和散列将以纯文本形式通过未加密的http连接发送到服务器以进行验证。这当然不会阻止黑客在不知道源密码的情况下使用别人的用户名和密码哈希(通过一些代码调整)。
黑客如何使用我当前的逻辑欺骗别人的登录凭据的示例:
我正在制作的产品不会成为下一个ebay,facebook或stackexchange,而且预算很低。我不需要一些顶级的东西,并且不关心盗窃,因为我计划使用“支付你想要的”模式。我主要是为了好奇而发帖。
答案 0 :(得分:12)
首先,我要说你没有能力安全地实施这个系统。我也不是。 几乎没有人。 你需要一名安全专业人员来完成这项工作;如果你试图推出自己的安全性,那么你就会犯错,你会产生一个可以被攻击者攻陷的系统。
这样做:你已经清楚地发现了系统的弱点。您正在存储等效的密码;如果攻击者获得等效的密码,那么他们是否有密码并不重要;他们有足够的信息冒充用户。
解决方案很明确。 如果您这样做会受到伤害,请不要这样做。如果不能信任存储它的系统能够抵御攻击,则不要存储等效的密码。
如果您一直想存储等效的密码,那么将其存储在存储器中,攻击者比文件系统更难以获取访问权限。如果您确实代表用户存储危险内容,则可以使用Windows数据保护API将其存储在使用用户凭据加密的加密存储中:
http://msdn.microsoft.com/en-us/library/ms995355.aspx
但最好不要在第一时间存储等效的密码。
假设您没有存储等效的密码。你还没有完成。你仍然需要考虑重播攻击。假设攻击者窃听了不安全的通道。用户输入密码,进行散列并发送到服务器。窃听者记录了哈希密码,现在他们已经拥有了密码。
要解决此问题,服务器会向客户端发送一个随机数。这个号码永远不会再被使用;这只是一次性的。客户端使用随机数编码散列密码,然后使用服务器的公钥加密结果。加密的xor'd消息将发送到服务器。
服务器使用其私钥对散列进行解密,并使用先前发送的随机数对其进行xors,并确定解密的散列与其存储的等效密码相匹配。现在,窃听者无法重播所捕获的密码,因为他们永远不会再看到相同的随机数。
现在,如果客户端不知道服务器的公钥,这很容易受到中间人攻击!如果服务器将公钥发送到客户端,那么中间人可以拦截服务器的公钥并用他的公钥替换它。现在,中间人可以提供公共密钥和“随机”挑战,客户端将放弃等效的密码。
像我说的那样,这很难。不要试图自己做。 找专业人士。答案 1 :(得分:5)
将哈希密码存储在用户的计算机上会使他们面临(相当大的)风险 - 即使访问您的站点不是特别有价值,许多用户也会对许多站点使用相同的用户名和密码。如果他们中的任何一个使用相同的(如您所说,众所周知的)哈希函数,那么访问该数据可以让攻击者访问这些其他网站。
对于简单,低预算的方法,我会使用简单的挑战/响应系统。当用户要求登录时,向他们发送一个随机数。他们将密码输入到客户端程序中,该程序将其哈希,并使用散列密码作为密钥来加密随机数,然后将该结果发送到服务器。服务器使用其存储的用户密码哈希来加密相同的随机数。当它从用户获得结果时,它会比较两者。当且仅当两者匹配时,用户才有正确的密码。
如果您的目的是避免用户必须始终输入密码,请将随机数和加密的随机数存储在他们的计算机上。只要他们收到同样的挑战,他们就可以发送相同的回复。当/如果挑战发生变化,他们需要重新输入密码来加密新挑战。恢复存储的数据使攻击者只能访问您的网站,并且只能在相当短的时间内访问(并且更快地更改挑战也是如此)。
这样可以避免传输密码(即使是以散列形式)。唯一的例外是在初始设置期间,当您需要将哈希密码输入服务器时。为此,您有几个选择,但PK加密可能是最明显的 - 您向他们发送密钥并发送使用该密钥加密的数据。如果其他人拦截数据,它就没用了(当然,除非他们破解加密)。
就如何生成随机数而言,通常的方法非常简单:从服务器上的/dev/random
等源生成一个真正的随机数。使用(散列版本)作为加密算法的密钥,您在计数器模式下运行 - 即您有一个计数器(您不必保密),您使用该密钥加密(您保留该密钥)秘密)。每当您需要产生新的挑战时,您需要递增计数器,对其进行加密并发送结果。
答案 2 :(得分:2)
我非常不鼓励尝试创建自己的身份验证方案。如果您使用经过时间检验的模式,那么您更有可能会覆盖您未考虑过的边缘案例。这是我的建议和原因:
不允许使用哈希值而不是完整密码登录。这样,即使攻击者获得存储在服务器上的密码哈希值,他们也无法使用它们登录。
尽量避免存储密码,甚至是散列密码。如果你想轻松登录,@ Mitch的建议是一个很好的妥协,但我建议你加密那个过期的令牌,并可能将过期的令牌绑定到一些额外的证据(例如,如果令牌使用不同的IP发送,则令牌无效)地址)。
绝不以纯文本格式传输凭据。即使传输的凭证被散列,如果捕获了流量,也可能发生重放攻击。 SSL并不是非常难以实现,它将为您提供额外的奖励,使客户能够验证他们正在与正确的服务器通信,这有助于防止中间人攻击。
切勿在服务器上存储用户密码。存储盐渍哈希。确保哈希是一个大的哈希值,以减少暴力攻击成功的可能性(例如,SHA-256)。
我知道你正在努力寻求一种便宜,易于开发的解决方案。而不是实施劣质安全性来实现该目标,而是尝试使用预先构建的,经过时间考验的身份验证库。这是一种节省时间/金钱而不影响质量的方法。
答案 3 :(得分:2)
正确存储 哈希密码并不危险。反向加密哈希并找到将产生哈希值的密码在计算上是不可行的。
然而,一切都取决于“正确”这个词。首先,如果用户选择了较差的密码,则不需要反转散列函数。破解首先尝试按常用密码排序的常用密码列表。如果散列算法不使用某种密钥加强(数千次迭代)使其计算成本昂贵,则可以强制使用相当大的密码空间(8或9个字符)。如果哈希算法不使用盐,则预先计算的字典是可行的。
我不确定我是否完全理解你的帖子,但听起来你知道你有效地使用这个哈希作为密码。中间人或攻击设备的人将能够访问您的应用程序而无需恢复原始密码。好处是他们不会拥有用户的“真实”密码,而这些密码可能会用于许多其他应用程序。
将密码存储在用户的大脑中并让他们每次都输入密码会更安全。但是,如果您没有使用SSL等安全协议,那么在其他地方花费太多精力进行安全性似乎并不值得。让用户负责保护自己的设备并防止存储密码被盗是合理的。但是他们发送它的网络是他们无法控制的。我从运输安全开始。
答案 4 :(得分:2)
我在上面所做的一切都不是为了让安全系统更加聪明。在我看来,最好的政策是对这类事情“说不”。
好消息是,你甚至可能不必费心。您是否考虑过使用第三方库来允许您的用户通过OpenID登录(如StackOverflow本身似乎那样)?我承认以前从未这样做过,但我相信它可能是一个强大而轻巧的选项,可能对你有用:
祝你好运。答案 5 :(得分:0)
这是黑客的天堂!
任何与安全相关的文件只能由维护网站的人员访问,而不管使用何种加密方法。
否则,你很有诱惑力。
:)