Castle ActiveRecord / NHibernate - 密码加密或散列
处理您不想以明文形式存储在数据库中的密码的正确方法是什么? 我在 NHibernate / Castle ActiveRecord 中有哪些选项?
更新: 我对其他人如何使用 NHibernate / Castle ActiveRecord 处理这个问题感兴趣。 如果 NHibernate 或 Castle ActiveRecord 中内置了任何东西。
What is the proper way to work with Passwords you don't want to store in clear text in a database? What are my options in NHibernate / Castle ActiveRecord?
UPDATE:
I was interested in how others handle this with NHibernate / Castle ActiveRecord.
And if there was anything built into NHibernate or Castle ActiveRecord.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
对密码进行哈希处理。 不要加密 - 它很复杂和/或不安全。 在任何可以想象的情况下,在普通的业务线应用程序或网站中根据其他一些可验证的标准重置密码都是可以的。 我不确定您是否熟悉对密码进行哈希处理的原理,因此我将从基础知识进行解释...
当用户最初选择其密码时,您将运行单向哈希算法在文字上。 这会产生一个签名 - 如果您将相同的字符串输入哈希算法,则始终会产生一个输出。 关键是您无法从哈希中返回密码(因此是单向的)。 然后您存储哈希值,而不是密码。 当用户回来时,他们必须再次输入密码,您使用相同的算法对其进行散列,并将结果值与数据库中的值进行比较 - 如果它们匹配,您就知道用户再次输入了相同的字符串,但您仍然不知道不知道,或者需要知道,它是什么。 这比基于加密的解决方案安全得多,在加密解决方案中,如果您知道密钥,则始终可以恢复明文,根据定义,服务器必须知道密钥才能验证密码输入。
在 .NET 中对字符串进行哈希处理的一种简单方法是使用 System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(),尽管其名称很长,但它是为使用 ASP.NET 表单身份验证的用户提供的一个简单函数,但在其他地方也同样有用。 您可以指定 MD5 或 SHA1 作为您的哈希算法(或者如果未来的框架版本支持的话,实际上也可以指定其他哈希算法)。 我推荐 SHA1,因为众所周知 MD5 有弱点,但 SHA1 可能也有弱点。
然而——这个计划有一个缺陷。 如果多个用户选择相同的密码,他们将具有相同的哈希值。 如果黑客可以访问您的数据,他们可以运行暴力攻击,对常见字符串进行哈希处理,并将其与您存储的数据进行比较。 如果他们受到攻击,他们就会使用该密码破解所有帐户。 由于用户倾向于选择蹩脚的密码,并且讨厌被迫选择他们记不住的安全密码,这使得基于简单密码哈希的系统变得有点脆弱。
你应该做的是加盐哈希值。 这仅意味着在原始数据(密码)前面或后面添加随机字符串。 这种盐需要尽可能随机,长度至少有几个字符(我建议至少 5 个),最好是随机长度。 您将盐(未混淆)与散列盐+密码组合一起存储在数据库的列中。 当用户返回时,您以相同的方式将盐添加到他们的输入中,然后像以前一样进行哈希比较。
这降低了暴力攻击的有效性,因为即使每个用户具有相同的密码,他们也应该具有不同的哈希值。 您可以安全地将盐存储在数据库中,因为当您知道字符串的某些部分时,从其哈希中计算出字符串与您一无所知时一样困难,只要密码本身比盐长并且足够长并且足够强大,需要很长时间才能通过暴力破解(我想说,至少 6 个字符,至少有一个大小写更改,以及一个数字或非字母数字)。
如果有人可以在无限时间内无限制地访问您的数据,他们最终会破解散列密码。 但最终可能需要数月或数年。 如果您知道自己已被泄露,您可以在问题出现之前更改每个人的密码。
Hash the password. Don't encrypt - it's complex and/or unsafe. There's no conceivable circumstance in which it wouldn't be OK to reset the password based on some other verifiable criterion in an ordinary line-of-business app or Web site. I'm not sure from the question whether or not you're familiar with the principle of hashing a password, so I'll explain from the basics...
When the user selects their password initially, you run a one-way hash algorithm on the text. This produces a signature - an output that will always be produced if you input the same string into the hash algorithm. The key is that you can't get back to the password from the hash (hence one-way). You then store the hash, not the password. When the user comes back they have to type in their password again, you hash this using the same algorithm and compare the resulting value to what's in the DB - if they match, you know the user enterered the same string again, but you still don't know, or need to know, what it is. This is much more secure than solutions based on encyrption where you can always recover the plaintext if you know the key, which by definition has to be known to the server in order to validate the password input.
A simple way of hashing a string in .NET is to use
System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile()
, which despite its lengthy name is a simple function provided for those using ASP.NET Forms Authentication, but just as useful elsewhere. You can specify MD5 or SHA1 as your hash algorithm (or indeed other hash algorithms if supported by future framework versions). I recommend SHA1 because MD5 is known to have weaknesses, but then SHA1 probably does too.However - there's a flaw in this scheme. If multiple users choose the same password, they will have the same hash. If a hacker gets access to your data, they can run a brute-force attack hashing common strings and comparing these against your stored data. If they get a hit, they've cracked all the accounts using that password. Since users tend to pick crappy passwords and hate being made to pick secure ones they can't remember, this makes a system based on simple password hashes a little brittle.
What you should do is salt the hash. This just means prepending or suffixing the original data - the password - with a random string of characters. This salt needs to be as random as it can be and at least a few chars in length (I recommend 5 as a minimum) and preferably of random length. You store the salt (unobfuscated) in a column in the DB alongside the hashed salt + password combination. When the user returns you prepend or suffix the salt to their input in the same way, and then do the hash comparison as before.
This reduces the effectiveness of a brute force attack because every user should have a different hash even if they have the same password. You can safely store the salt in the DB because working out a string from its hash is just as hard when you know some of the string as it is when you know none of it, provided the password itself is longer than the salt and long enough and strong enough to take a long time to crack by brute force (at least 6 chars with at least one case change and a number or non-alphanumeric, I'd say).
If someone has unlimited access to your data for unlimited time, they'll eventually crack the hashed passwords. But eventually could be months or years. And provided you know you've been compromised, you can get everyone's password changed well before it becomes a problem.
最好的方法是使用 UserType。 这是一个实现透明密码的加密。
我会将此类常见问题复制到 ActiveRecord wiki。
The best way is to use a UserType. Here's one that implements transparent password encryption.
I'll copy common questions like this to the ActiveRecord wiki.
我建议不要使用 UserType 进行单向散列,除非您有一个计划可以防止在后续调用 NullSafeSet() 时不断重新散列散列密码。
相反,我建议您在密码属性上使用支持字段,在设置器中应用哈希方法并设置映射以使用字段访问。
I would suggest not using UserType for the one-way hashing, not unless you have a plan that will preventing continually rehashing a hashed password on subsequent calls to NullSafeSet().
Instead, I would recommend that you use a backing field on your Password property, apply the hash method in the setter and setup your mapping to use the field access.
您应该对密码进行加密或哈希处理。 散列更安全(当然取决于算法)。 因为它无法逆转; 但是,加密可以更有效,因为您可以有一个检索密码选项。 使用散列,您必须生成一个新密码。
对于 nHibernate / castle,您应该在业务对象内处理算法,恕我直言,与持久性机制分开。
You should either encrypt or hash a password. Hashing is a bit more secure (depending on the algorithim of course). Because it can't be reversed; however, encryption can be more functional since you can have a retrieve password option. With hashing you have to generate a new password..
As for nHibernate / castle you should handle the algorithim inside your business objects IMHO seperated from the persistance mechanism.
抱歉,也许这对你来说已经无关紧要了,但我希望可以帮助别人。
使用 uNhAddins 是我发现的最简单的方法,您只需要关心 HBM 即可。
检查此 hbm 示例
希望有帮助
sorry maybe it is irrelevant anymore for your, but i hope can help someone else.
Using uNhAddins is the easiest way I found, you only need to care about the HBM that's all.
check this hbm example
Hope that help