Many vulnerabilities can be remediated where they begin -- in code.
SQL injection (SQLi)
Problem: A SQL injection attack consists of insertion or "injection" of a SQL query via the input data from the client to the application. A successful SQL injection exploit can read sensitive data from the database, modify database data, execute administration operations on the database, recover the content of a given file present on the DBMS file system, and in some cases issue commands to the operating system. OWASP
Solutions: Use parameterized queries, use stored procedures, validate input, or escape tainted input. OWASP SQLi Cheat Sheet
Prepared statements with variable binding (parameterized queries) force developers to first define all the SQL code, then pass each parameter to the query. This allows the database to distinguish between code and data, regardless of what user input is supplied. Prepared statements ensure that an attacker is not able to change the intent of a query, even if they insert SQL commands. OWASP
String sql = "SELECT * FROM User WHERE userId = ?";
PreparedStatement stmt = con.prepareStatement(sql);
stmt.setString(1, userId);
ResultSet rs = prepStmt.executeQuery();
String query = "SELECT account_balance FROM user_data WHERE user_name = ?";
try {
OleDbCommand command = new OleDbCommand(query, connection);
command.Parameters.Add(new OleDbParameter("customerName", CustomerName Name.Text));
OleDbDataReader reader = command.ExecuteReader();
} catch (OleDbException se) {
// error handling
}
Not always safe from SQL injection, standard stored procedure programming constructs have the same effect as the use of parameterized queries when implemented safely, which is the norm for most stored procedure languages.
// After validating tainted input:
String custname = request.getParameter("customerName");
try {
CallableStatement cs = connection.prepareCall("{call sp_getAccountBalance(?)}");
cs.setString(1, custname);
ResultSet results = cs.executeQuery();
// result set handling
} catch (SQLException se) {
// error handling
}
Cross-Site Scripting (XSS)
Problem: XSS is a type of code injection in which malicious scripts are inserted into otherwise trusted websites. In an XSS attack an attacker uses a web application to send malicious code, generally in the form of a browser-side script, to a different user. OWASP
Note that there are three types: reflected just appears in the browser, stored is written to a database, and DOM-based modifies the DOM environment in the victim's browser. What matters is that all are bad and can be used in conjunction with other attacks.
Solutions: Use modern web frameworks, sanitize tainted input, encode output. OWASP XSS Cheat Sheet
Modern frameworks encourage good security practices and help mitigate XSS by using defenses such as templating and auto-escaping. Developers still need to be aware of problems that can occur when using frameworks insecurely, and where gaps in their frameworks exist.
Use output encoding to safely display user input as entered. Do not interpret variables as code. Use the framework's default output encoding protection. Note that output must be encoded for the context in which it appears, e.g.:
- HTML body, e.g.
<div>TAINT</div>
(validate and encode where needed) - HTML entities, e.g.
<span>TAINT</span>
(encode: convert & to&
, < to<
, > to>
, " to"
, ' to'
, and / to/
) - HTML attributes, e.g.
<input type="text" name="fname" value="TAINT">
(replace all characters except alphanumeric with the HTML Entity&#xHEX;
format, including spaces) - URLs and URLs in attributes, e.g.
<a href="URL TAINT ">Click here!</a> <iframe src="URL TAINT " />
(canonicalize input, validate the URL, use standard percent encoding to encode only parameter values) - JavaScript (replace all characters except alphanumeric characters with the \uXXXX Unicode encoding format)
- DOM, e.g.
<script>document.write("TAINTED INPUT: " + document.location.hash );<script/>
(see the DOM based XSS Prevention Cheat Sheet) - CSS (use the
\XX
or\XXXXXX
formats to encode where needed)
If a user absolutely needs to write HTML within the application (as for a WYSIWYG editor), use an HTML sanitization utility. Remember to sanitize after making any changes to the input (or sending to a library that modifies it); this may invalidate the security effort.
Cross-Site Request Forgery (CSRF)
Problem: A CSRF attack forces a user to execute unwanted actions on a web application in which they're currently authenticated. With some social engineering (e.g. sending a link via email or chat), an attacker may trick the user into doing the attacker's bidding. If the victim is a normal user, this can mean transferring funds, changing the user's email address, etc. If the victim is an administrative user, CSRF can compromise the application. OWASP
Solutions: See the following recommendations. OWASP CSRF Cheat Sheet
- Use the framework's CSRF protections if it has any (many modern frameworks do).
- If it doesn't, add CSRF tokens to all state changing requests.
- Reauthenticate for all sensitive actions on the backend.
- For stateful software, use the synchronizer token pattern.
- For stateless software, use double submit cookies.
- Avoid using GET requests for state-changing operations.
- Do at least one of:
- Use a SameSite Cookie Attribute for session cookies (but watch its use with an untrusted domain).
- Implement user interaction based protection for highly sensitive operations.
- Use custom request headers.
- Verify the origin with standard headers.
XML issues
XML External Entity (XXE) attacks can specify system references in applications that process XML, giving system access to an attacker.
- Do not accept external references in XML.
- Use minimal privileges in XML parsers.
- Use a secure, properly configured XML parser.
XML Entity Expansion (XEE, a.k.a. "Billion LOLs" or "XML bomb") is a Denial Of Service (DoS) attack that uses valid and well-formed XML blocks that expand exponentially until it exhausts server resources.
- Configure the XML parser so that it does not allow document type definition (DTD) custom entities as part of an incoming XML document.
- Set the "secure-processing" property for an XML factory, parser or reader.
- If inline DOCTYPE declaration is not needed, disable it:
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
Buffer overflow
Many native languages do not inherently check bounds on variable size or memory manipulation functions. This can provide an avenue of attack to inject arbitrary code or corrupt data. OWASP In a classic buffer overflow exploit, an attacker sends data to a program, which it stores in an undersized memory buffer. The result is that information on the call stack is overwritten, including the function's return pointer. The data sets the value of the return pointer so that when the function returns, it transfers control to malicious code contained in the attacker’s data (also see the shellcode Wikipedia article).
Resources
- Secure Coding Guidelines for Java SE (Oracle)
- Java language specification (Oracle)
- Java CWEs
- Oracle Secure Coding Standard for Java(SEI CERT)
- J. Bloch, Effective java. Prentice-Hall, 2008.
- J. Bloch and N. Gafter, Java puzzlers: traps, pitfalls, and corner cases. Addison-Wesley, 2012.
- [SEI CERT C Coding Standard: https://wiki.sei.cmu.edu/confluence/display/c/SEI+CERT+C+Coding+Standard
- [SEI CERT C++ Coding Standard: https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=88046682