To Build Your Code Quality (Chapter A): Secure Coding (Part 3)
Problem with Authentication
Continuing secure coding is for the group of authentication & Password Management Issue. On use standpoint view, authentication looks like very straightforward and not be something to consider. The users just come to the application, enter their username and password, then click submit. Then the application will verify them to determine if it is indeed the correct person and go from there. Sounds like not very complicated. But it is not that simple. The fact is that authentication has many implications in term of security. Some samples can cause breaks from a poor authentication approach that we have known
- If we application is separating messages when a wrong password entered versus when an unknown user enters our system, we are telling an attacker if they have the username correct or not. Then, it is a subject for attackers to perform enumeration attack. So the key thing is to keep all message in consistence
- Hashing is a common approach being used for authentication. However, some hashing algorithms poorly resulting bad password protections when attackers can brute force a password. Good practice is to use a good hashing algorithm which is known by the community
- Not setting up a maximum number of bad password attempts before we institute a lockout procedure, we are having our application to be attacked. By not having this mechanism, we are not only giving a great chance for attacker to penetrate the system and put our client’s data at risk, but we are opening a channel for more over loads on our system
There are good practices to build a good authentication for our application as follows:
- Never store the password in plain text
- Leverage short-lived unique links for passwords resets. We need use a unique token with an email verified for resetting a password when implementing this reset function
- There is no one even is inside company or a system admin to manipulate the passwords or impersonate the customer system admin
- The complexity of password needed to create a strong authentication. The combination of lowercase & uppercase, numbers, special characters and its length would create a stronger password to hard to be cracked
If we are building an application for healthcare, authentication can be more of complexity to protect patient data and to comply with some regulations. Here are additional requirements:
- User authentication is controlled by means other than username and password, e.g.: certificates, or token,..)
- Password is forced to change for a new user
- The application enforces password expiration and prevent users from reusing a password
- The application prohibits users from logging into the application on more than one workstation at the same time with the same ID
- The application automatically logs a user off the application after a predefined period of inactivity?
Problem with Authorization
Authentication is just a half of key in access control management. Deciding what a user can perform/operate or access is other part of the key. A fail in authorization will put client’s data at risk. Unfortunately, the kind of this fail is hard to track down. If a solid access control list is not implemented correctly or simply is not applied, a user can access to administration’s section that giving him/her more control. There are a couple of rules to do with authorization are:
- First, authorization checks must be executed at server-side and never happens at client-side only. If a user impersonates the client side, he still has another gate to pass through at server-side
- All permission state changes should require logging out, and logging back in. So even a privileged user with having ACLs, he is not able to change them in a single session. The session should be static when it comes to permission models to protect from internal threats
- Trust boundary can cause security false. A user has been authenticated and authorized still need to re-verify himself for each important transaction. If we trust in what has been done before can cause issues. For example: if we perform a money transfer transaction from a web banking system, it is required to re-verify an authorized user again (and even using multiple security factors). This becomes even more critical in microservices architectures where the systems are distributed
There are couple of mitigations for these risks. Firstly, we need to have a good control in place around how we review, and control access within our application. Code reviews, design reviews, and even acceptance criteria are needed to evaluate authorization during development. Secondly, we need define a good testing strategy for each build release, using role-based users in our tests and look at every transaction from both the positive and the negative perspective for every role. we can build a matrix to check all our access controls
Problem with Cryptography Issues
Using “unsafe” cryptographic routines is putting the system at risk. The term “unsafe” here refers to the algorithm being used in encryption has been cracked or has a flaw that has been identified. Many developers lack awareness in implementing algorithms for encryption, hashing, or digital signatures that it may no longer be considered safe. Using the latest and greatest algorithms is a good mitigation for this risk. No algorithm is perfect and unbreakable forever. We have to keep tabs on the algorithms that we use and their acceptance by the industry. Ultimately, upgrading is needed. Choosing wrong algorithm is also the most common reason causing issues. For instance: using SHA-2 to hash passwords is too easy to brute force successfully.
Many developers are misunderstanding how to use crypto algorithms or cipher mode. There are some examples of misleading information
- Using a random number that is not cryptographically secure or
- Reusing an Initialization Vector (IV) multiple times which can nullify the entire encryption process itself
- Using deterministic encryption to make sensitive data searchable without factoring for dictionary attacks
- In addition, often key sizes can fall into this arena because insufficient key size can ruin a great algorithm
Lack of security knowledge is a root of security problems. Anyone who have acknowledged security always understand how important to manage their keys in encryption. We can always spot out some developers who are using database (or file system or application config files) to store their keys. There is not an unique way for key management, but here are some good practices:
- Physically secure encryption systems
- Do not store encryption keys with the data they decrypt
- Maintain a secure and frequently updated off-site backup of encryption keys
- Manage encryption key life-cycle
- Encrypt keys as another layer of security
- Use multi-factor authentication for any master keys
- Keep recovery keys in escrow
- Make it possible to change keys periodically
Finally, for Cryptography issue is that rolling our own crypto is a poor idea. Many developers want to implement the crypto algorithms in their ways when they feel that they know crypto well enough. A good and trust algorithm needs to be validated, publicly used over a long time. Let’s leave this job for scientists or security researchers, unless we want to be them. A simple way to mitigate all risks above is that we have to open to ask questions when we don’t really know about it. If we wonder if an algorithm is cracked, ask. If we wonder if an algorithm is poor, ask. If we need to understand an API, ask. There are a lot of forums and experts out there ready to answer all our questions, StackOverFlow – a massive community of developers helping each other solve challenging problems. So they’re not likely to admit to having limited expertise when tasked with something they haven’t done before. Also, there are good libraries out there that we can use.