Adding a custom hashAlgorithmType in C# ASP.NET

2019-03-22 00:11发布

I've got a page that I need to beef up security on. I'm using the built-in MembershipProvider functionality and currently have hashAlgorithmType set to SHA512. I've got the BCrypt.NET library (http://bcrypt.codeplex.com/) and it seems to be working nicely when I call its functions from code but I'm having the worst time figuring out how to create the appropriate <cryptographySettings> section in Web.config to let me create a hashAlgorithmType.

I found the following code snippet on the web:

<mscorlib>
    <cryptographySettings>
        <cryptoNameMapping>
            <cryptoClasses>
                <cryptoClass   MyHash="MyHashClass, MyAssembly
              Culture=neutral, PublicKeyToken=a5d015c7d5a0b012,
              Version=1.0.0.0"/>
                <cryptoClass   MyCrypto="MyCryptoClass, MyAssembly
              Culture=neutral, PublicKeyToken=a5d015c7d5a0b012,
              Version=1.0.0.0"/>
            </cryptoClasses>
            <nameEntry name="System.Security.Cryptography.HashAlgorithm"
                       class="MyHash"/>
        </cryptoNameMapping>
        <oidMap>
            <oidEntry OID="1.3.36.3.2.1"   name="MyCryptoClass"/>
        </oidMap>
    </cryptographySettings>
</mscorlib>

Call me a noob if you want, but I apparently don't have the requisite knowledge to make heads or tails of that. All I need is a method to tell the membership provider that something like <hashAlgorithmType="bcrypt"> corresponds to something like string hashed = BCrypt.HashPassword(password, BCrypt.GenerateSalt(12)); to encrypt and bool matches = BCrypt.CheckPassword(candidate, hashed); to decrypt. Please tell me there's an easy answer. I can rewrite the login system from scratch if I have to, but I already have a working implementation that I'd really like to just change the hashing algorithm of.

3条回答
Luminary・发光体
2楼-- · 2019-03-22 00:41

To be able to register a custom hashAlgorythmType, the first thing you need is a type that actually implements HashAlgorythm. If BCrypt implements it, it's your lucky day, but apparently it does NOT implement it, so this is your problem.

There is really no work around for it, as implementing HashAlgorithm is a requirement for being able to register it like this.

So what you are going to need to do is either write a wrapper around BCrypt to implement HashAlgorithm, or, of this is not possible, modify BCrypt itself to implement it.

Unless you are really-really lucky and BCrypt is written in a way that easily lend itself to such a modification, it can require some non-trivial efforts.

查看更多
啃猪蹄的小仙女
3楼-- · 2019-03-22 00:56

I believe that config pattern must be applied to the machine.config file; which isn't necessarily a great move if you need to be able to roll out this code easily.

You can programmatically register the BCrypt encryption primitive(s) with the CryptoConfig class through a call to AddAlgorithm with a name that can you can later use.

So long as the BCrypt hash provider implements HashAlgorithn you should be able to register it simply, you can also test this by calling HashAlgorithm.Create(string) with the name you use to verify that it builds the algorithm correctly.

The membership provider should then be able to use it without issue. Here's a good article about this topic.

Update

(deep breath) - apologies if this is tl;dr.

Okay, so having read around about BCrypt.Net's password hashing - it's obviously good, and follows accepted practise. It is, also, completely incompatible with how the HashAlgorithm class works because it requires additional state in order to work it's magic, and can't simply be extended to implement the HashAlgorithm contract.

Thus, you have a choice - stick with MembershipProvider and use SHA512 as you already are - you're talking about beefing up security on a page, so I'm thinking there might be issues with authentication itself, rather than the storage of passwords (which must, of course, still be done properly) - so consider simply making sure that the authentication traffic is sent over HTTPS if it's not already.

Using password stretching algorithms blindly has its own issues - see the responses to my own recent SO on this topic - if you do the stretching on the server you could potentially end up causing a DOS attack on the site!

The other option is, as you've suggested, to manage the membership entirely yourself - thus you can use whichever types you want and manage the necessary storage of the password information manually.

My sites now use an algorithm very similar to PBKDF2 that I lifted from Bruce Schneier and Niels Ferguson's book Practical Cryptography, for which I use 512 bit random salt and SHA512 (storage is cheap) plus many thousands of iterations to hash a clear text. The server benchmarks itself once per appdomain to establish 'levels' of protection that equate to millisecond ranges - thus over time newly hashed passwords will receive a constant level of protection even if the hardware improves. The library is standalone, too, and I've been able to deploy it to SQL Server 2008 R2 to provide CLR SPs if we have to generate password records at the SQL level.

But this only protects the passwords - you then need an authentication mechanism that can protect the act of logging in; plus another system for protecting the authenticated session token (.Net's Authentication Cookie system is actually pretty good for this).

Following on from that SO I have now spent a week implementing SCRAM primitives that I have then plugged into my MVC web services for authentication, and I plan to do the same to enable login from the web browser using Javascript (locking out non-JS clients). The key there being the client is doing all the hash calculations; thus I've stuck to SHA because mature implementations are readily available in practically any environment (e.g. we have iPhone apps too - and they need to authenticate as well).

In your case, however, with the existing investment in the MembershipProvider, I would consider 512 bits of SHA plus SSL plus Asp.Net's auth cookie sufficient - so long as the database is really secure(!) and you've got no SQL injection holes in the site.

查看更多
等我变得足够好
4楼-- · 2019-03-22 01:04

For a BCrypt implementation of HashAlgorithm, see my answer to a similar question here.

You would need to create a signed assembly with the sample code in my answer, and then modify your settings as needed:

<cryptoNameMapping>
  <cryptoClasses>
    <cryptoClass MyHash="BCryptHasher, MySignedAssemblyName
                 Culture=neutral, PublicKeyToken=<my public key for singed assembly>,
                 Version=1.0.0.0"/>
  </cryptoClasses>
  <nameEntry name="System.Security.Cryptography.HashAlgorithm" class="MyHash"/>
</cryptoNameMapping>
查看更多
登录 后发表回答