Previously, I had written a few things for .NET framework about how to implement basic security concepts on your applications that are working in .NET environment. In this post I want to walk you though implementing the same security concepts in your applications that are based on the .NET Core framework. As always there will be two topics that I will be covering in this post of mine .NET Core is different in this matter as compared to .NET framework, one of the major reasons being that there is no “SHA256Managed” (or any other _Managed types in the framework). So the framework is different in this manner. This post will cover the basic concepts and will help you to understand and get started using the methodologies for security.
Figure 1: Data security in your applications is the first step for giving clients confidence
First of all, I will be covering the parts of hashing, and I will give you a few of my tips and considerations for hashing the passwords using .NET Core in your applications. Before I started writing this post, I remembered when I was working in Mono Project and the platform was very easy to write for. I was using Xamarin Studio as IDE and the Mono was the runtime being used at that time, in my previous guide the focus was on the Mono programming on Ubuntu, whereas in this post I will be covering the concepts of the same but with .NET Core. .NET Core is really beautiful, although it is not complete, yet it is very powerful. I am using the following tools at the moment so in case you want to set up your own programming environment to match mine, you can use them.
- IDE: Visual Studio Code.
- C# extension: For C# support and debugging
- Terminal: Ubuntu provides a native terminal that I am using to execute the command to run the project after I have done working with my source code.
Figure 2: Visual Studio being used for C# programming using .NET Core
You can download and install these packages on your own system. If you are using Windows, I am unaware as to what Visual Studio Code has to offer, because since the start of Visual Studio Code I have just used it on Ubuntu and on Windows systems my preference is always Visual Studio itself. Also, I am going to use the same project that I had created and I am going to start from there, A Quick Startup Using .NET Core On Linux.
So, let’s get started,
Hashing passwords
Even before starting to write this, I am considering the thunderstorm of comments that would hit me if I were to make a small and simple mistake in the points here, such as:
- Bad practices of hashing.
- Not using the salts.
- Bad functions to be used. Etc.
However, I will break the process down since it is just a small program that does the job and there is exaggeration here. Instead of talking about that, I will walk you through many concepts of hashing and how hackers may try to get the passwords where hashing helps you out.
Until now I have written 3 to 4 articles about hashing, and I can’t find any difference in any of these codes that I have been writing. The common difference is that there are no extra managed code things around. .NET Core removed everything redundant in the code samples. So we are left with the simple ones now that we would be using.
What I did was that I just created a simple minimal block of the SHA256 algorithm that would hash the string text that I am going to pass. I used the following code,
-
- using(var sha256 = SHA256.Create())
- {
-
- varhashedBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes("hello world"));
-
- var hash = BitConverter.ToString(hashedBytes).Replace("-", "").ToLower();
-
- Console.WriteLine(hash);
- }
This code is a bit different from the one being used in .NET framework. In the case of .NET framework the code starts as:
- using (var sha256 = new SHA256Managed()) {
-
- }
That is the only difference here,the rest of the stuff is almost the same. The conversion of bytes into string text is up to you. You can either convert the bytes to hexadecimal strings or you can use the BitConverter helper to convert that to the text that is being represented.
The result of this code is,
Figure 3: Result of the above shown code in C# being executed in Ubuntu terminal on .NET Core runtime
There is one another constraint here, “
Encoding.UTF8“, if you use another encoding for characters then the chances are your hashed string would be different. You can try out other flavors of the character encodings such as:
- ASCII
- UTF-8
- Unicode (.NET framework takes Unicode encoding as UTF-16 LE)
- Rest of the encodings of Unicode etc.
The reason is that they provide a different byte ordering and this hashing function works on the bytes of the data that are passed.
Tips and considerations
There are generally two namespaces, one of them is the very old familiar .NET’s namespace, System.Security.Cryptography, whereas another one is Microsoft.AspNet.Cryptography which is a part of ASP.NET Core and is to be released. Anyways, here are a few of the tips that you should consider before handling the passwords.
Passwords are fragile-handle with care
I can’t think of any online service, offline privacy application, API hosts where passwords are not handled with care. If there is, I would still act as I never knew of it. Passwords must always be hashed before saving in the database. Hashing is done because hashing algorithms are created with one thing in mind, that they are hard (if not impossible) to convert back to plain-text passwords. This makes it harder for the hackers to get the passwords back in real form. To explain this fact, I converted the code into a functional one and printed the hash with a little change in the text.
- private static string getHash(string text)
- {
-
- using(var sha256 = SHA256.Create())
- {
-
- varhashedBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(text));
-
- returnBitConverter.ToString(hashedBytes).Replace("-", "").ToLower();
- }
- }
I will execute this function and get the hashed string back for the text.
- string[] passwords = {
- "PASSWORD",
- "P@SSW0RD",
- "password",
- "p@ssw0rd"
- };
- foreach(var password in passwords)
- {
- Console.WriteLine($ "'{password}': '{getHash(password)}'");
- }
Although they seem to look alike, have a look at the avalanche effect that happens due to such small changes. Even have a look at the differences in the capital case and small case.
Figure 4: Password hashes being shown in the terminal
This helps in many ways, because it is harder to guess what the possible plain-text alternate would be for this hashed string. Remember the constraints again,
- The character encoding is UTF-8; others would provide a different character encoding bytes ordering.
- Hash algorithm being used in SHA256, others would produce even different results.
If you don’t hash out the passwords, hackers may try to use most common attacks on your database system to gain privileges of access. A few common type of attacks are:
- Brute force attack
- Dictionary attack
- Rainbow table attack
Rainbow table attack works in a different manner, it tries to convert the hash back to the plain-text based on the database where a password/hash combination is present. Brute force and dictionary attacks use a guessing and commonly used passwords respectively, to gain access. You need to prevent these attacks from happening.
Besides there are cases where your password hashing is useless. Such as when you want to use MD5 hashing algorithms. MD5 algorithms can be easily cracked and the tables for entire password lookup are already available and hackers can use those tables to crack your passwords that are hashed using MD5. Even SHA256, SHA512 don’t work as you are going to see in the following section. In such cases you have to add an extra layer of security.
Bonus: how to break it?
Before I continue further, I wanted to share the point of these passwords and their hashes being weaker. There are many hacking tools available, such as reverse look ups. Let us take our first password and see if that can be cracked. I used CrackStation service to crack the password and convert it back to its original text form,
Figure 5: SHA256 based password converted back to its original form
See how inefficient even these tricks happen to be? In a later section I will show you how to salt the passwords and what the effect is. Although we had hashed it using SHA256, the reverse lookup table already has that password of ours. Hackers would just try to use that hash and get the real string value in the plain-text to be used for authentication purposes.
Slower algorithms
On networks where hackers are generally going to attack your websites with a script you should have a hashing algorithm that is (not very) significantly slow. About half a second ora 3rd of a second should be enough. The purpose is:
- It should add a delay to the attacker if they are trying to run a combination of passwords to gain access.
- It should not affect the UX.
There are many algorithms that keep the iterations to a number of 10,000 or so. The namespace that I had talked of, Microsoft.AspNet.Cryptography has the objects that allow you to specify the iteration, salt addition etc.
Remember: For online applications, do not increase the iteration count. You would indirectly cause a bad UX for the users who are waiting for a response.
Add salt to the recipe
I wonder who started the terminology of salt in cryptography. He must have a good taste in computers, I’d say. I did cover most of the parts of adding the salts in the article that I have added in the references section, please refer to that article. However, I would like to share the code that I have used to generate a random salt for the password. Adding the salt would help you randomize the password itself.
Suppose a user had a password of, “helloserver”, another one had the same password too. By default the hash would be alike but if you add a random salt to it, it would randomize the password.
In .NET Core, you can use the “RandomNumberGenerator” to create the salt that can be used for the password.
- private static string getSalt()
- {
- byte[] bytes = new byte[128 / 8];
- using(varkeyGenerator = RandomNumberGenerator.Create())
- {
- keyGenerator.GetBytes(bytes);
- returnBitConverter.ToString(bytes).Replace("-", "").ToLower();
- }
- }
This would create a few random bytes and then would return them to be used for the passwords.
- string[] passwords = {
- "PASSWORD",
- "P@SSW0RD",
- "password",
- "p@ssw0rd"
- };
- foreach(var password in passwords)
- {
- string salt = getSalt();
- Console.WriteLine($ @ "{{
- 'password': '{password}',
- 'salt': '{salt}',
- 'hash': '{getHash(password + salt)}'
- }
- }
- "
- );
- }
This shows how the passwords with “
random salt” differ.
Figure 6: Passwords with their salts being hashed
Have a look at the hashes now. The hashes differ from what they were before. Also, notice that the function returns a different salt every time which makes it possible to generate different hashes for even the similar passwords. One of the benefits of this is, that your passwords would be secure from a rainbow table attack.
Test: We saw that unsalted passwords are easy to be reverse looked up. In this, case, we salted the password and we are going to test the last of our password to see if there is a match.
Figure 7: Password not found
Great, isn’t it? The password was not matched against any case in the password dictionary. This gives us an extra layer of security because hacker won’t be able to convert the password back to their original form by using a reverse look up table.
Using salt: the good way
There is no good way of using the salt, there is no standard to be followed while adding the salt to the password. It is just an extra “random” string to be added to your password strings before they are hashed. There are many common ways, some add salt to the end, some prepend it some do the both.
Do as you please. There are however a few tips that you should keep in mind while salting the passwords.
- Do not reuse the salts.
- Do not try to extract the salts from the passwords or usernames.
- Use suitable salt size; 128-bit?
- Use random salt.
You should consider using a good library for generating the salts.
- Store the salts and passwords together. Random salts won’t be created again (in a near future).
References
- Avalanche effect
- Hashing Passwords using ASP.NET’s Crypto Class
- Guide for building C# apps on Ubuntu: Cryptographic helpers
- What are the differences between dictionary attack and brute force attack?
Final words
In this post, I demonstrated the hashing techniques in .NET Core, although the procedure is similar and very much alike. There are a few differences that the objects are not similar. The object instantiation is not similar and in my own opinion, this is also going to change soon.
I gave you a good overview of password hashing, how to crack them (actually, how an attacker may crack them) and how you can add an extra layer of security. Besides, you should consider adding more security protocols to your own application to secure it from other hacking techniques too.