The modern world is full of technology, applications, and data. In the last decade we can read about all sorts of company data breaches such as Target, Chase Bank, Sony Playstation Network, and many more. While there may always be a way for a person with malicious intent to get what they want we should always secure our applications and sensitive data. We don’t ever want an application to become compromised and we don’t want our data breached but if it does happen it should not be through simple preventable technological exploitation. Below I will discuss several security measures that should be applicable to every application and database we work with on a daily basis.
One of the first line security lessons I learned was proper password hashing. I learned this very early on in my career and assumed that everyone in the world already did this but through my lens of industry insight I have realized that this is not always the case. User passwords should be hashed which means one-way encrypted and irreversible. Not you, a super administrator, nor any executive partner should ever have the ability to find out a user’s password. If the capability exists to find out a user’s password, then passwords are no longer safe in the event of a data breach.
When hashing passwords there should always be some sort of unique flair performed on each hash to make each password distinguishably different from any other password. This is usually called a ‘salt’. If two users have their password set to “password1” with just a simple SHA-1 or MD5 hash and no salt, then both user’s hashed passwords will look the same. For example, User1’s stored hashed password using the SHA-1 hash function would be “e38ad214943daad1d64c102faec29de4afe9da3d” and User2’s stored hashed password using the SHA-1 hash function would also be “e38ad214943daad1d64c102faec29de4afe9da3d”. This makes it possible for someone to have a preset collection of common passwords in multiple hashes and compare it to passwords retrieved in some sort of data breach. This collection of preset common passwords already hashed in all of the common hashing functions is called Rainbow Tables. That is something you can query your favorite online search engine on your own time if you’d like. When using a salt to add some extra unique flair to a password, it doesn’t matter if User1 and User2 have the same password being “password1”. After the password is hashed they will come out completely unique and different with no way of comparing the two. Anyone with access to the database would never assume that User1 and User2 have the same password in any way. You can always use a hash and a salt on your own and that is a great way to secure user passwords but I recommend using a known and reputable hashing function like Bcrypt or Scrypt. The major benefits of using Bcrypt are that it is still unbroken after 10+ years, uses a salt so each hash is unique, and is slow enough to make brute force attacks nearly impossible while fast enough to be usable. You can read more on Bcrypt here. You can find a .NET library that includes Bcrypt and Scrypt here.
The best way to handle the resetting of a password should be through an expiring email link. When the URL is reached the user will be authenticated to make a password update. Some developers like the idea of generating a temp password and emailing the user a temp password for their next login. The temp password approach meets all the same goals as the email link and it simply comes down to preference. I personally prefer an expiring email link because I don’t want anyone having a non-hashed password even if it is only a temporary one-use password. It may seem overly cautious but I wouldn’t want anyone to be able to compare a non-hashed password with a hashed password. A person with enough time, determination, and skillset could potentially make use of the two pieces of information even though it’s a long shot.
Passwords should never be emailed to a user. Not only does this mean that you aren’t one-way hashing the passwords, but this also leaves the user a potential greater vulnerability if their email is compromised. If a user uses the same password on your site and several other sites and you email the password, then you have given away information that could affect the user’s other website logins as well. If you email the user a link, then no password is ever revealed and it keeps the user information safe with the responsibility still limited to only your application. The main point here however is DO NOT EMAIL PASSWORDS.
Encrypt Application/System Logins and Assign Only Necessary Permissions
Every application has to have some sort of connection string, user accounts, and SQL Server logins. These kinds of accounts should always be given minimal but appropriate privileges for their use. Sometimes, however, an application feature calls for an edge case that would need an account with “extra privileges,” which if not assigned properly, could give access to more than needed and can be harmful in the wrong hands. All login information used to access these accounts should be encrypted. For example, if you have a configuration file with unencrypted login information and the file is compromised then the accounts are compromised. If the login information is encrypted, then the malicious person accessing the file would also need to be able to decrypt the login information before the accounts are compromised. This could either prevent account compromise all together or at least delay the malicious person giving administrators time to notice the security issue and reset accounts before anything goes wrong. Where we draw the line of security is tough but we should make sure all technological bases are covered and prevent malicious activity as much as possible.
Always make sure to sanitize any user input into an application and/or database. To sanitize an input is to remove special characters that could be used in malicious ways to allow a user to perform unintended actions on an application, database, or even server. User input should be sanitized on multiple levels as well. You may need to sanitize client side, server side, and database input information. It could prove harmful if someone figured out a way to bypass the first layer of input sanitizing and was able to submit malicious data just because we thought there was only one way to submit it. If you don’t sanitize your data, then you are open to attacks like SQL Injection and we have all heard of little Bobby Tables from XKCD.
Encode Dynamic Data
Encoding data is similar to sanitizing, but instead of removing malicious special characters from input on the way into the server, it is removing malicious special characters on the way out of the server. I say it’s “removing” but what I mean is that it is replacing the characters in question with safe versions of those characters. In web applications, dynamic data is displayed in the browser on just about every page/request. If the data happens to be malicious data, it leaves the application open to XSS (Cross Site Scripting) attacks. Someone is then essentially able to run their own code on your application on other users’ machines and potentially gain access to user accounts and more. Encoding is a good idea even if all inputs are sanitized. If for some reason a malicious user has access to the database and changes some data (data that is expected to be clean safe data because it was sanitized on the way in) to be malicious, then when rendering a web page, it could run the malicious code and leave an application compromised. Microsoft .NET framework has built in functions for encoding data located in the System.Web.Security.AntiXss library.
Limit information to user
Every page of every application we write either displays information to users or allows users to input information into the system. We want to make sure that in both scenarios that we do not leave any careless holes or unintended information available for user interaction. If a user is submitting data, the application should only allow the submittal of the expected properties to a server. This can be done with DTO’s (Data Transfer Objects), ViewModels, special single purpose classes or any other synonym for those terms, and it can also be handled through validation. There are times as developers where we want to populate a field behind the scenes and won’t allow a user to change it like in a CreateDate or UpdateDate field. If a special DTO or ViewModel isn’t being used when letting a user submit data, it is potentially possible for the user, if savvy enough, to change fields that may not be intended to be changed. Also, the data should be limited when passing across the network from a client from a server. It is very easy to forget that some fields should never been seen by users because it may reveal some information meant to remain hidden. If someone is monitoring network traffic and wants to see every bit of data passed from server to client and back, then they may see hidden information that isn’t used or displayed on the page but was in fact passed to the client for potential future usage. This could give away hidden keys, values, and maybe even sensitive data if not prevented.
TL; DR of this section is: Whitelist data input and output. Don’t blacklist.
Another piece of information that developers will usually send to a client is error/exception information. A developer should send some sort of feedback to users if something goes wrong but it should never be generated by the application in the sense of an exception or call stack. This kind of information being alerted to the client is common because it helps developers understand what the problem is, but it can also give a malicious user some information they can use to their benefit and has the potential to be bad for the security of our application and data.
Up to this point we have discussed the most basic and common security measures and the more niche ones will be covered in the next part. The best we as developers can do is ensure that our applications and our data are technologically secure. There are still other ways to access sensitive data like social engineering and informants but those are training responsibilities. We should know our technological responsibilities as developers and should always strive to provide the best security to clients, end users, and ourselves. Stay tuned for part 2 of this topic where we will discuss even more security-ensuring practices to keep you and your clients’ application and data secure.
If you enjoy this topic or enjoy talking about development of any kind you should check out our available positions at Sparkhound. Sparkhound is full of people with aligned interests and motivation to provide the best possible solution to any scenario. There are plenty of good minds to lean on and we like to have fun too! Feel free to contact me at firstname.lastname@example.org and/or contact Sparkhound for any further discussions, questions, or feedback. Woot!