7 Practical Secure Coding Practices
Software Security is important more than ever. This article provides multiple live secure coding examples one has to apply while developing modern-day software.
Join the DZone community and get the full member experience.
Join For FreeIntroduction
Software Security is important more than ever in today's world. If we embed the security in the development phase of the application it not only benefits the overall security adherence but also creates multiple security checkpoints at multiple levels of software. This article provides multiple live secure coding examples one has to apply while developing modern-day software. This article uses Java to show case-live examples; these principles can be adopted with any language of choice.
1. Escape the Input
There are types of attack called injection attacks, where the attacker embeds an execution command/Query impersonating it as normal literal input.
This confuses the execution engine and eventually fools it into giving more info/control to the attacker. To avoid such types of attack, it is advised to escape the user input so that it won’t be interpreted as a command but a literal. It is advised to escape the data stored in the database as the reverse is also true. Imagine user provide input which is JavaScript to steal the cookies from a browser in some post for example. Now when this is rendered on other users' screens in the browser and if we don’t escape the stored value of the post. JavaScript will be executed and give the attacker more info/control. Below is one such example to escape the input query for the database in Java.
Example:
Potential Risk
String query = "SELECT user_id FROM user_data WHERE user_name = '"
+ req.getParameter("userID")
+ "' and user_password = '" + req.getParameter("pwd") +"'";
try {
Statement statement = connection.createStatement( … );
ResultSet results = statement.executeQuery( query );
}
Avoids Risks
Codec ORACLE_CODEC = new OracleCodec();
String query = "SELECT user_id FROM user_data WHERE user_name = '"
+ ESAPI.encoder().encodeForSQL( ORACLE_CODEC, req.getParameter("userID"))
+ "' and user_password = '"
+ ESAPI.encoder().encodeForSQL( ORACLE_CODEC, req.getParameter("pwd")) +"'";
2. Avoid ID as a Sequence
In some scenarios, an attacker tries to get more information than he/she should be having. For example, if the user of an API is allowing to view users with ID 1-100. Now, if the system used the sequence for ID, the next user will be 101. This attacker can exploit this vulnerability to get information about things that he/she is not entitled to.
Example:
Potential Risk
xxxxxxxxxx
String sqlIdentifier = "select TESTING_SEQ.NEXTVAL from dual";
PreparedStatement pst = conn.prepareStatement(sqlIdentifier);
synchronized( this ) {
ResultSet rs = pst.executeQuery();
if(rs.next())
long myId = rs.getLong(1);
Avoiding Risk
xxxxxxxxxx
// This example is for Oracle
String sqlIdentifier = "select TESTING_SEQ.NEXTVAL from dual";
PreparedStatement pst = conn.prepareStatement(sqlIdentifier);
synchronized( this ) {
ResultSet rs = pst.executeQuery();
if(rs.next())
long myId = rs.getLong(1) + UUID.random();
3. Apply Minimalist Approach
In order to reduce the attack surface, the system should adopt a policy of minimal footprint exposure. What essentially it means that system should expose just right no more no less. Let’s take an example here if there is a business requirement where the system needs to respond with 200 HTTP code for the existence of resources, but if we provide a REST API with a get operation. This will increase the attack surface for the attacker. Instead, the system should only have a head method of HTTP protocol that gives info about existence, and not more.
Example:
Potential Risk
xxxxxxxxxx
//Get is allowed where we need to just check user exist
http://localhost:8080/User/id/1
Avoiding Risk
xxxxxxxxxx
http://localhost:8080/User/id/1
Head
4. Least Privileges Principle
Let’s say, somehow, one of the users in the customer care department access has been compromised, she has access to order data API. But he/she has been assigned a role of a super admin. In this case, where he/she should be having permission to view, but because of super admin now the attacker can exploit it to launch series of attacks on the system. In order to reduce the attack surface, your API access should only be given based on need and role. There should not be a concept of a super user who can access everything.
5. HTTPS/SSL 2-Way Possibly
Never expose your endpoint/site on HTTP; any ways, most of the browsers now show warning on this, use 2 way SSL for integration end point and HTTPS for sites and end to end encryption.
Data level encryption is another aspect one can start for financial/other sensitive information. As HTTPS will only protect the channel of communication from attackers but if that channel key is compromised it is difficult to protect the data. Thus people suggest using a strong encryption algorithm to encrypt data records as well as traveling over the wire.
6. Do Not Use Insecure or Weak Cryptographic Algorithms
As computing power is increasing, weak keys are no longer secure against the brute force way of breaking things. There are certain cryptographic algorithms not allowed or black-listed by reputed organizations. Below is one such reference from the post where a list of cryptographic algorithms considered insecure.
Examples of Deprecated Cryptographic Algorithms
- SHA-1
- 1024-bit RSA or DSA
- 160-bit ECDSA (elliptic curves)
- 80/112-bit 2TDEA (two-key triple DES)
- MD5 never was an acceptable algorithm for government use, along with many other older algorithms.
7. Whitelisting of Dynamically Executed Code
If you have code that executes as part of flow coming in from user of API/APP or generated after user input. The system needs to whitelist the commands that we will be executing.
For example, if the system is exposing a service to list the directories on the server, then whitelist ls/dir commands and escape the input flags incoming from the user.
Conclusion
We can divide most of the secure coding practices into 4-5 paradigms including but not limited to encryption, encoding, whitelisting, least privileges, and never trust user input. If a development team adopts these 5 broad paradigms one can substantially reduce the risk of software security being compromised. In this article, we have seen multiple ways we can adopt in our day-to-day life to make the software more secure.
Opinions expressed by DZone contributors are their own.
Comments