Quantify Cyber Risk Now

header ads

A Primer on Secure Code Practice in JAVA | Lucideus Research

This article presents certain guidelines for Java developers which may be helpful in making the application in question a little more secure. These rules are not enough to develop an enterprise level application, but it’s a good start and requires a fairly good knowledge of Java.

An application should be developed giving priority to its security and users’ data. It is a good practice to design APIs while keeping security in mind.

Allocate behaviours and provide interfaces. Fields of objects should be private and accessors avoided. The interface of a method, class, package, and module should form a coherent set of behaviours.

Limit access to classes, methods and variables
Every class, method, and variable that is not private provides a potential entry point for an attacker. By default, everything should be private. Make something non final if there is a good reason to not. Making a class final prevents a malicious subclass from adding finalizers, cloning, and overriding random methods. A class that does not permit subclassing is easier to implement and be verified for security. Malicious subclasses that override the ‘Object.finalize’ method can resurrect objects even if an exception was thrown from the constructor. Design classes and methods for inheritance or declare them final. Left non-final, a class or method can be maliciously overridden by an attacker.

Private Variables
Make all variables private which should be accessed via getter and setter methods, if they are required to be accessed from outside classes. Getter and setter methods should be defined as final, which will prevent attacker from defining their own malicious code into them.

Make Public Static Fields Final
Callers can trivially access and modify public non-final static fields. Neither accesses nor modifications can be guarded against, and newly set values cannot be validated. Fields with subclass-able types may be set to objects with malicious implementations. Always declare public static fields as final. If using an interface instead of a class, the modifiers "public static final" can be omitted to improve readability, as the constants are implicitly public, static, and final. 

Ensure Public Static Final Field Values are Constants
Only immutable or unmodifiable values should be stored in public static fields. Many types are mutable and are easily overlooked, in particular arrays and collections.

import static java.util.Arrays.asList;
        import static java.util.Collections.unmodifiableList;
        public static final List<String> names = unmodifiableList(asList(
            "Fred", "Jim", "Joe"

The of() and ofEntries() API methods, which were added in Java 9, can also be used to create immutable collections:

       public static final List<String> names =
                                    List.of("Fred", "Jim", "Joe"); 

Package Scope
Classes, methods and fields which are not explicitly labeled with access specifiers are accessible within the package they are defined. Attackers can exploit this and introduce an extended class of their own into the package and use it to access the things.

Avoid Duplication
Duplication of code and data causes many problems. Both, code and data tend to not be treated consistently when duplicated, e.g., changes may not be applied to all copies.

Object Construction
During construction, objects are at an awkward stage where they exist but are not ready for use. Avoid exposing constructors of sensitive classes.
Construction of classes can be more carefully controlled if constructors are not exposed. Define static factory methods instead of public constructors.

Prevent Constructors from Calling Methods that can be Overridden
Constructors that call overridable methods give attackers a reference to this (the object being constructed) before the object has been fully initialized. To prevent this, make sure constructors call either private or final methods to do the work.

Serialisation and Deserialisation
Java Serialisation provides an interface to classes that sidesteps the field access control mechanisms of the Java language. As a result, others can get a hold of the internal state of the objects including private fields with which the objects can be converted into byte array, that can be read. Once an object has been serialised, the Java language access controls can no longer be enforced and attackers can access private fields in an object by analysing its serialised byte stream. Therefore, do not serialize sensitive data in a serialisable class.

                                                    Approaches for Handling this
Declare Sensitive fields transient
Make your object impossible to serializable by declaring a private final writeObject method and throw an exception with a suitable message, such as “object can not be serialized”.
private final void writeObject(ObjectOutputStream out) throws java.io.IOException 
throw new java.io.IOException("Object cannot be serialized");

Making a class serializable effectively creates a public interface to all fields of that class. Serialization also effectively adds a hidden public constructor to a class, which needs to be considered when trying to restrict object construction.

Deserialization creates a new instance of a class without invoking any constructor on that class. Therefore, deserialization should be designed to behave like normal construction.
The classes may still be deserializable even if they aren’t serializable. A sequence of bytes can be created which can be utilized to deserialize the instance of class. Think of deserialization as another kind of public constructor for the class.

To prevent this, implement a private final readObject method throwing an exception with a suitable message from the body.

Attacks using maliciously crafted inputs to cause incorrect formatting of outputs are well-documented. Such attacks generally involve exploiting special characters in an input string, incorrect escaping, or partial removal of special characters. 

Avoid Dynamic SQL
It is well known that dynamically created SQL statements including untrusted inputs are subject to command injection. This often takes the form of supplying an input containing a quote character (') followed by SQL.

In several DAO classes, the instances such as the following code were found, which could lead to SQL injection attacks.

 StringBuilder query = new StringBuilder();
query.append( "select * from user u where u.name in (" + namesString + ")" );
        Connection connection = getConnection();
    Statement statement = connection.createStatement();
    resultSet = statement.executeQuery(query.toString());

For parameterised SQL statements using Java Database Connectivity (JDBC), use java.sql.PreparedStatement or java.sql.CallableStatement instead of java.sql.Statement.
It not only makes the code less vulnerable to SQL injection attacks, but also makes it more efficient.

StringBuilder query = new StringBuilder();
query.append( "select * from user u where u.name in (?)" );
        Connection connection = getConnection();
    PreparedStatement statement = connection.prepareCall(query.toString());
statement.setString( 1, namesString );
resultSet = statement.execute();

Input Validation
Validating external inputs is an important part of security. In general, method arguments should be validated but should not return values. However, in the case of an upcall, (invoking a method of higher level code) the returned value should be validated.

Making classes immutable prevents the issues associated with mutable objects, such as in concurrent situations. Whenever you access a mutable object from separate threads, you have to deal with locking. This reduces throughput and makes your code dramatically more difficult to maintain. Hiding constructors allows more flexibility in instance creation and caching. This means making the constructor private or default access.

Immutable classes themselves should declare fields as final and protect against any mutable inputs and outputs.

Create copies of mutable output values
If a method returns a reference to an internal mutable object, then client code may modify the internal state of the instance. Unless the intention is to share state, copy mutable objects and return the copy.
To create a copy of a trusted mutable object, call a copy constructor or the clone method:

public class CopyOutput 
            private final java.util.Date date;
            public java.util.Date getDate()
            return (java.util.Date)date.clone();

When designing a mutable value class, provide a means to create safe copies of its instances. This allows instances of that class to be safely passed to or returned from methods in other classes.

This functionality may be provided by a copy constructor, or by implementing cloneable interface, which is a marker interface. Define a clone() method that should handle CloneNotSupportedException. And in most cases, from our clone() method, we call the clone() method of the superclass.
Copy constructor is preferred for its following advantages over clone() method.
  • Doesn’t force the developer to implement any interface or throw any exception
  • Doesn’t require any type casting
  • Doesn’t require developer to depend on an unknown object creation mechanism
If a class is final and does not provide an accessible method for acquiring a copy of it, callers could resort to performing a manual copy. This involves retrieving state from an instance of that class and then creating a new instance with the retrieved state.

Secure Java coding is not easy. There is no full proof method or approach that can solve all the problems. The aforementioned rules will surely help in reducing the number of ways in which things can go wrong.

Image Source

Post a comment