Secure Java Coding
Disclaimer
Largely based on a talk given by Andrew Lee-Thorp, Principal Consultant Synopsis.
Common Vulnerabilities
(see also the blog > security-shepherd)
- Clear text storage of sensitive information in memory (https://cwe.mitre.org/data/definitions/316.html)
- Basic Cross Site Scripting (https://cwe.mitre.org/data/definitions/80.html)
- SQL injection (https://cwe.mitre.org/data/definitions/89.html)
- Information exposure through error messages (https://cwe.mitre.org/data/definitions/209.html)
- Use of broken or risky cryptographic algorithms (https://cwe.mitre.org/data/definitions/327.html)
- External control of filename or path (https://cwe.mitre.org/data/definitions/73.html)
- Improper restriction of XML external entity reference (XXE) (https://cwe.mitre.org/data/definitions/611.html)
- Insufficient entropy (https://cwe.mitre.org/data/definitions/331.html)
- URL redirection to untrusted site (open redirect) (https://cwe.mitre.org/data/definitions/601.html)
- Improper neutralization of CRLF sequences in HTTP headers (HTTP response splitting) (https://cwe.mitre.org/data/definitions/113.html)
Defense Strategies
For injection attacked check all inputs:
1) Validation
2) Parameterization
3) Output encoding
4) Data normalization
- Validation
- Exact match
- Whitelist
- Blacklist
2. Parameterization
Use apis that parameterize the values instead of string concatenation, eg. SQL PreparedStatements.
3. Output Encoding
When input validation is restricted, encode the data after processing and before responding:
- XML encoding
- Javascript encoding
4. Data Normalization
Convert data to its canonical form. Eg. file paths, split to root path and expected format.
String baseDir = "/root/foo/bar/";
String path = baseDir + filePath;
File f = new File(path);
String canonical = f.getCanonicalPath();
if (!canonical.startsWith(baseDir)) {
System.out.println("this is an attack!");
}
Still need to validate the input afterwards.
General Prevention Methods
Input -> (normalize) -> (validate) -> process -> (parameterize db queries, encode results)
1 Clear text in memory
Can dump the java heap of a running program to reveal sensitive data. Using immutable objects prevents clearing out of memory occupied by these objects using updates. Instead use mutable objects, eg use char array in place of String and clear the array after processing.
2 Injection Attacks
Cross-site scripting (XSS)
Bypassing the Same Origin Policy, usually malicious java script executed on the browser to extract information, modify page, hijack the session, redirect to fake sites. The same origin policy requires protocol, host and port to be the same within the site.
Stored XSS
Malicious data in a forum post. When viewed the script now runs on the users browser.
Reflected XSS
URL has a parameter (eg erromsg) which is sent to victim via a email.
DOM-Based XSS
If the DOM is changed by a script looking at t URL this can then be exploited.
Prevention
Encode the result before presentation. (See OWASP Java encoder)
Validate the input before processing.
Use CSP (Content Security Policy), set this in the http response header. See https://developers.google.com/web/fundamentals/security/csp/
3 SQL Injection
Basically avoid concatenation of user input with sql statements, instead use prepared statements (parameterized).
This also applies to stored procedures and ORM frameworks like hibernate.
In situations where parameterized queries are not possible than validate/encode the input.
4 Information Exposure
Information leaking details of the server, the code in stack traces that can be exploited by attackers.
Use a general error page and use this when exceptions occur.
Do not show details of servers.
5 Cryptographic Algorithms
Symmetric: DES3, AES
Asymmetric: RSA, DSA, ECC
Avoid using weak block cipher modes such as ECB, CBC (http://www.crypto-it.net/eng/theory/modes-of-block-ciphers.html)
Avoid using weak algorithms such as RC4, DES.
Consider use of randomly generated Initialization Vector.
Consider encryption limits.
Use strong hashing use SHA-256, 384, 512, SHA3-224, SHA3-512 instead of MD5 or SHA-1.
Consider using random padding for RSA encryption (PKCS#1 v1.5)
For AES (Advanced Encryption Standard) use authenticated mode eg AES-GCM (Galios Counter Mode) with IvParameterSpec (java) to get the IV. For code examples see https://javainterviewpoint.com/java-aes-256-gcm-encryption-and-decryption/
RSA
For RSA use 2048 or or larger keys.
For encryption use use RSA-OAEP padding rather than PKCS#1
For signature can use PCKCS#1 or PSS padding
6 Files and Directories
Prevent injection of input that can access operating system, execute remote code modify files etc.
Use canonical path to convert to standard form and check directory.
String baseDir = "/root/foo/bar/";
String path = baseDir + filePath;
File f = new File(path);
String canonical = f.getCanonicalPath();
if (!canonical.startsWith(baseDir)) {
System.out.println("attack!");
}
7 XML Entities
Can include local files to access sensitive data
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [ <!ELEMENT foo ANY > <!ENTITY xxe SYSTEM "file:///etc/passwd" >]> <creds>
<user>&xxe;</user>
<pass>mypass</pass>
</creds>
Can scan ports
<!DOCTYPE scan [<!ENTITY test SYSTEM "http://10.26.18.1:22">]> <scan>&test;</scan
Secure parsing using features to prevent external entity injection (XXE).
Either disable completely or set individually if not possible:
saxReader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
private static final String EXTERNAL_ENTITIES = "http://xml.org/sax/features/external-general-entities";
private static final String EXTERNAL_DTD = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
...
...
SAXParserFactory parserFactory = SAXParserFactory.newInstance();
parserFactory.setNamespaceAware(true);
SAXParser parser = null;
try {
parserFactory.setFeature(EXTERNAL_ENTITIES, false);
parserFactory.setFeature(EXTERNAL_DTD, false);
parserFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
parser = parserFactory.newSAXParser();
} catch (ParserConfigurationException e) {
throw new SAXException(e);
}
8 Passwords
Use password store never hard code.
Hash the password with a salt stored alongside the hash, use adaptive hash (slows down to brute force search) functions (Bcrypt, Scrypt, PBKDF2, Argon2).
9 Entropy
Randomness for keys, sessions, nonces etc. Use SecureRandom not Random and not setSeed with a custom one but call it periodically.
10 HTTP Response Splitting
Prevent injection of CRLF into http header and allowing additional malicious headers, modification of cookies, addition of javascript.
Attack could be like so:
http://www.vulnerablesite.com/authors?author=JoeHacker\r\n\r\nHTTP/1.1%20200%20OK\r\n
Which would circumvent the normal response.
Any input from the user that is added to the header is a security flaw if not cleansed.