How secure can you code in Java?
Every software developer must follow certain standards and practices while coding and writing, secure code is one such practice. Everyone who loves to code must ensure their software is not vulnerable to exploits or being a principal cause of a cyber-attack.
Anyone can code, but if our code is not reliable enough, it cannot be used on a long run. There are numerous hackers who prey on a vulnerable software. By not coding securely, we let those cyberpunks compromise our applications.
To build secure Java applications we must adhere to certain principles:
- Follow the secure coding standards.
- Review code for security.
- Design a framework for attaining an unremitting process for secure software.
Follow the secure coding standards
Here are a few pointers with examples of mistakes developers often make:
1. Use the access modifiers available in Java to its fullest, by restricting the access to methods and classes when required. For example, we often use public access specifiers without a thought.
Do not make any functions and variables as public unnecessarily if they need not be used in other packages.
2. Avoid writing a complex code, as it could have hidden security loopholes and the process of debugging errors or bugs in your code. Often, coders write redundant methods and complicate the code.
3. Java automatically checks array bounds and buffer overflows, but the code can be made vulnerable is special case when one uses JNI to call native code.
4. To protect your software, validate all the inputs given by a user and avoid blindly trusting a function input. A developer might not be validating the input given by users.
Tip: If any user enters a non-positive value, it can cause trouble, so make sure to validate the input.
5. Do not provide unnecessary permissions or privileges to a file or folder. For example, providing all permissions to a file as in the code below might not be necessary. Relative paths can cause file to be written and executed inside unintended directories.
Tip: Provide only required permissions, otherwise anyone can modify the file and cause harm to the system.
6. Always communicate with external systems over SSL and verify certificate provided by the server. Often Java developers override setDefaultHostNameVerifier function with a non-strict version of allowing all host names without verification.
7. Try not to ignore compiler warnings, as few of them could be security related warnings. We often hear developers saying ‘It is just a warning’ but beware these might be the source of the problem at run-time.
8. It is always better to encrypt and encode your data. Always keep a look-out for unintentionally transferring confidential information in a plain message.
Tip: Sending a plain message directly is not a good practice, always encrypt and encode any message that is sent via mail or through the network. It is also appreciated if you can use effective techniques to hide email addresses from spam bots.
9. Learn to handle errors and exceptions correctly. Please ensure that you are handling a known error effectively. Known errors and exceptions can be handled beforehand using try-catch block, throw, throws etc.
10. There are plenty of useful Java libraries available, but use only the efficient, known and tested libraries.
11. Keep your error messages short and simple, don’t end up exposing your implementation through error display messages. Often errors and stack traces expose too much of information.
Tip: Providing precise or detailed error message is not a safe way to code, hide the implementation from user.
12. Beware of serializing objects containing sensitive data, as important information leaking could lead to loss of customers’ trust, creates huge financial predicament and other reputational damage.
13. Audit all user actions to know what they are up to, because even if something goes wrong and eventually affects your software, at least you must know what went wrong. For example, designing a logging mechanism that does not journal all the user actions provides less visibility to a possible security bug.
Tip: Don’t just log information, audit every crucial action performed by the users and raise alerts when an unintended action occurs.
14. Use PreparedStatement class of Java.sql package because it escapes special characters automatically, which prevents SQL injection.
An example that showcases input which is not processed before use.
Tip: Using an unprocessed SQL input directly could leak the sensitive data stored in your database, so it is advised to process such inputs with PreparedStatement.
15. Make use of the Security manager class provided by Java to enforce or grant permissions and restrict certain operations. The security manager is a class that allows applications to implement a security policy. It allows an application to determine, before performing a possibly unsafe or sensitive operation, what the operation is and whether it is being attempted in a security context that allows the operation to be performed (source: docs.oracle.com).
Review code for security
Reviewing the code is an essential step during development of your software, as it brings consistency between design and implementation of your project by identifying bugs and other performance concerns related to time and space complexity. Code review can be done manually or using automation tools.
Using automation tools is a good practice, but that alone is not sufficient to find flaws in your code and verify if it is secure, but a mix of human review along with automation can make your software less prone to manipulation using exploits.
Automation helps you test your application quickly and reveal its performance based on different contexts where it is used. They can detect most of the known vulnerabilities such as an SQL injection or a Cross-Site Scripting issue. But they cannot handle unfamiliar behaviors. Whereas humans can find those undecipherable errors through accurate design, data validation and uncover logical errors.
Here are the top 10 Static Code Analysis Tools for Java, C++, C# and Python- Raxis, RIPS Technologies, PVS-Studio, Kiuwan, Gamma, DeepScan, reshift, CodeScene Behavioral Code Analysis, Visual Expert, Veracode, Code Compare, Fortify Static Code Analyzer and Parasoft (source: softwaretestinghelp.com, last updated March 11 2020).
Design a framework for attaining an unremitting process for secure software
Automation frameworks are common in every field, each of them is used for a different purpose, but they all share a common goal, that is to reduce human work and plausible errors. Likewise, in Java, frameworks like JUnit can be used to write unit test cases for your code, Selenium to test the UI, REST Assured for integration testing of REST API’s etc.
A single framework might not be sufficient to automate tests related to your code. Each of the tools such as JUnit, TestNG, JWalk have their own limitations and at times, none of them might be compatible with your code and help us substantiate code security with ease.
The preeminent solution could be designing a framework that focuses on characteristics that are vital to your software combined with best security practices certification module.
Certain ideas that one can pitch on to create our own framework,
- Developing a single automation tool to cover all the required functionalities. For example, unit testing, integration testing, web-based testing and automation can be integrated and inter-related to diagnose and fix issues asap.
- Creating orchestration software for release automation and continuous delivery such that every stakeholder in the software development has an awareness of the quality of the software. Developers and testers can spend more time on security testing.
- Designing a mechanism to update all the libraries to its latest version. This ensures that our software uses libraries that have recent security fixes and performance enhancements.
- Understanding static code analysing tools and evolving the framework to include enhanced features with minimal changes, this can be achieved if we design the functionalities with loosely coupled architecture bearing resilience to changes, flexibility, re-usability and security.
In today’s world, large amount of information is transferred and processed by systems through internet, data protection against breaches is inevitable. To achieve this, secure coding practices must be followed by developers and the experienced coders must bring awareness about repeated coding issues or patterns resulting in insecure code to the ingenuous developers. Your code cannot be 100% secure, but these practices increase the percentage of “how secure you can code”.