Introduction
Objectives
To protect against injection vulnerabilities, the software developer has several means at his disposal. In order to get accurate analysis results, the AIA needs to discover if any of these mechanisms have been used in the application, and how to configure AIP Core to take them into account, when required.
- Collect usage of protection mecanism(s) used by ACME organization, in an interview.
- usage of presentation layer validator, standard or custom
- the names of the sanitization vetted libraries, standard or custom
- for SQL injection prevention, usage of parameter binding, aka SQL Bind Variables/Parameters
- If the collection of information is not possible or incomplete upfront, the AIA must use his knowledge to detect the presence of the mechanism(s) in the source code itself and/or in the SecurityAnalyzer.log.
- Presence of JAR or assemblies could be a first sign
- Dependency inside Maven pom.xml is a better sign
- Presence of a protection mechanism is not a proof the application is 100% covered.
Methodology presentation
The default configuration will cover 90% of the cases for public sanitization library (with AIP Core >= 8.3.15). Then, once flaws are found and validation or any interview / observation reveals some specific configuration should be done, add a custom blackbox file to define the specific methods as sanitization (mode=clear). Then the invalid violations (protected by a sanitization method) will be removed from list of violations, and the remaining violations are deemed true positives.
Sanitization methods general information
This part should be configured at the end of the on-boarding process, in order to ensure no other road block will stop the engine during graph exploration. Therefore, it must be configured after a first pass with at least one violation (or at least a flaw reported in SecurityAnalyzer.log), then use the configuration to remove this violation.
However, some specific validation technics cannot be taken into account automatically. You will have to live with them, and just document the reason why the violation paths including them are harmless. "Sanitization" is sometime also referred to as "neutralization" or "cleansing". It removes the unwanted characters from a tainted input. Whereas the validator rejects user input.
Sanitization limitations in AIP Core
The User Input Security engine does not recognize logical test as a valid sanitization but it does not stop the flow (for our engine):
if(filePathName.contains("./")) // checking for ./covers both ./ and ../ { throw new HNRuntimeException("Directory Traversal Attempt :: " + filePathName); }
nor this one :
Private Sub navigateToPreviousPage() ValidateControls() If Page.IsValid Then updateAppoints() updateCampaign() Response.Redirect(PageNavigation.GetPreviousPage(PageName)) End If End Sub
Please note that only sanitization methods that modify the string (cleaners) are supported. Verification methods which test the string (checkers, i.e "if(verifyString(x))" ) are not supported and no sanitization method can be declared for these kind of methods
Check for sanitization strategy
As a rule of thumb - as a front-end developer, you should validate or sanitize user input at the earliest opportunity (in the presentation layer), except for SQL injection prevention, where sanitization with parameter binding is recommended, and it will take place just before the SQL execute API.
Custom validator
a.Custom taglib (JSTL)
b.Check each string entry for its target format (regexp), and move it from String to target data type ASAP (date, structure, …)
c.Custom filter sample : com.acme.view.common.MyController.cleanXSS(java.lang.String)
Use the presentation layer's validation framework
Samples:
- Struts Validator
- JSF Validator
- Apache Wicket Validator
- Spring MVC Form Validator or filter
Also, XSS can be prevented in JSP by using JSTL<c:out> tag or fn:escapeXml() EL function when (re)displaying user-controlled input. See XSS prevention in JSP/Servlet web application.
For SQL injection prevention, parameter binding
Prepared Statement CallableStatement, JDBC, JPA as well as ADO.NET allow usage of bind variables that prevent the attacker from modifying the intent of the query. See OWASP SQL Injection Prevention Cheat Sheet - Defense Option 1: Prepared Statements (with Parameterized Queries). Here the strategy for a user Input Security analysis configuration is as follows:
- Define the SQL method (execute Query) as Target-SQL : start a search from the bottom.
- Define the variable binding (setString, setXYZ, setParameter, ...) as sanitization for SQL injection : stops the flow.
- In addition, "The JDBC driver will escape this data appropriately before the query is executed; making sure that data is used just as data" (See How to How to Fix SQL Injection using the Java Persistence API (JPA))
Sample with JDBC
java.sql.PreparedStatement.setString(int parameterIndex, String x)
Sets the designated parameter to the given Java String value. Many other methods exist : setBoolean, setDouble, setDate, setInt, SetLong etc. and they are all considered as valid protection against injection.
java.sql.CallableStatement
has similar methods, with named parameters: setString(String parameterName, String x)
Sample with Springframework JdbcTemplate
JdbcTemplate provides a number of methods performing parameter binding:
- 15 signatures of query(...)
- 7 signatures of queryForList(...)
- 6 signatures of queryForMap(...)
- 6 signatures of queryForObject(...)
- 2 signatures of queryForRowSet(...)
public String findCustomerNameById(int custId){ String sql = "SELECT NAME FROM CUSTOMER WHERE CUST_ID = ?"; String name = (String)getJdbcTemplate().queryForObject( // Query given SQL to create a prepared statement from SQL and an argument to bind to the query, expecting a result object. sql, new Object[] { custId }, String.class); return name; }
Comparison of vulnerable code versus protected code with different mangling (sample from FindSecBugs):
JdbcTemplate jdbc = new JdbcTemplate(); // Vulnerable Code: queryForObject(String sql, Class<T> requiredType) : the concatenation makes the difference : VULNERABLE int count = jdbc.queryForObject("select count(*) from Users where name = '"+paramName+"'", Integer.class); // Protected Code: queryForObject(String sql, Class<T> requiredType, Object... args) : the extra parameter for binding makes the difference : PROTECTED int count = jdbc.queryForObject("select count(*) from Users where name = ?", Integer.class, paramName);
Sample with JPA
Named Parameters in Queries
Named parameters are query parameters that are prefixed with a colon (:). Named parameters in a query are bound to an argument by the following method:
javax.persistence.Query.setParameter(String name, Object value)
Positional Parameters in Queries
You can use positional parameters instead of named parameters in queries. Positional parameters are prefixed with a question mark (?) followed by the numeric position of the parameter in the query. The javax.persistence.Query.setParameter(integer position, Object value) method is used to set the parameter values.
Samples with Spring Data JPA
Spring Data JPA with Query Methods
See https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods:
Derived queries with the predicates IsStartingWith, StartingWith, StartsWith, IsEndingWith, EndingWith, EndsWith, IsNotContaining, NotContaining, NotContains, IsContaining, Containing, Contains the respective arguments for these queries will get sanitized. This means if the arguments actually contain characters recognized by LIKE as wildcards these will get escaped so they match only as literals. The escape character used can be configured by setting the escapeCharacter of the @EnableJpaRepositories annotation.
Spring Data JPA with Named Parameters
See https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.named-parameters.
Other patterns
JPA supports either position-based parameter binding or named parameter with @Param annotation. @Param works with both @Query and @NamedQuery (reference https://www.logicbig.com/tutorials/spring-framework/spring-data/query-named-parameters.html):
package com.logicbig.example; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.query.Param; import java.util.List; public interface EmployeeRepository extends CrudRepository<Employee, Long> { @Query("SELECT e FROM Employee e WHERE e.dept = :dept AND " + "(SELECT COUNT(DISTINCT e2.salary) FROM Employee e2 " + "WHERE e.salary < e2.salary AND e2.dept = :dept) < :topSalNum " + "ORDER BY e.salary DESC") List<Employee> findByDeptTopNSalaries(@Param("topSalNum") long topSalaryNum, @Param("dept") String dept); }
Sample with Hibernate
Similarly to JPA, Hibernate makes provision of parameter binding method for the Query class:
Named Parameters in Queries
org.hibernate.Query.setParameter(String name, Object value)
Positional Parameters in Queries
org.hibernate.Query.setParameter(integer position, Object value)
There are also several methods such as setParameterList() to bind multiple values to a named query parameter, and one setParameters() to bind values and types to positional parameters.
Sample with mySQL
Similarly to PreparedStatement, JPA, Hibernate and mySQL fluent API for Java makes provision of parameter binding methods for the Statement interface of X DevAPI (com.mysql.cj.xdevapi.Statement):
- Collection interface: Representation of a document collection. This interface allows access to and manipulation of the collection through add/find/modify/remove statements.
- Statement (all known sub-interfaces): AddStatement, DeleteStatement, FindStatement, InsertStatement, ModifyStatement, RemoveStatement, SelectStatement, SqlStatement, UpdateStatement - a statement is a query or state-affecting command against a database that returns a result.
See https://dev.mysql.com/doc/x-devapi-userguide/en/parameter-binding.html and MySQL Connector/J X DevAPI Reference.
// Using the .bind() function to bind parameters : DocResult myRes2 = myColl.find("name = :param1 AND age = :param2").bind("param1","jack").bind("param2",17).execute();
Sample with ADO.NET
Parametrized queries prevents from SQL injection.
// Build the query statement using parameterized query. string sql = "SELECT UserId FROM User WHERE " + "UserName = @UserName AND Password = @Password"; using (SqlCommand cmd = new SqlCommand(sql)) { // Create the parameter objects as specific as possible. cmd.Parameters.Add("@UserName", System.Data.SqlDbType.NVarChar, 50); cmd.Parameters.Add("@Password", System.Data.SqlDbType.NVarChar, 25); // Add the parameter values. Validation should have already happened. cmd.Parameters["@UserName"].Value = UserName; cmd.Parameters["@Password"].Value = Password; cmd.Connection = connnection; try { cmd.Connection.Open(); var userId = cmd.ExecuteScalar(); } catch (SqlException sx) { // Handle exceptions before moving on. } }
See complete article at How to Fix SQL Injection Using Microsoft .Net Parameterized Queries.
Using LINQ to SQL or LINQ to Dataset
Using these modern .NET Entity frameworks ensure the parameters are binded, and thus prevent from SQL injection...to a limited extented according to Fortify.
- LINQ Prevent SQL Injection
- Fortify : SQL Injection: LINQ
- Roslyn Security Guard - Potential SQL injection with LINQ API
- LINQ queries are not susceptible to SQL injection attacks in the traditional sense
- Or choose a common sanitization library, see below for a list of the librariess encountered at our customers (direct usage, or with a wrapper to fix any gap in the checks):
Common sanitization libraries encountered in JEE and .NET analyses
jar file name (sample) | Sanitization library / framework | Support in AIP Core | Comments - Sample - Known Limitations |
---|---|---|---|
owasp-esapi-java-1.1.1.jar | OWASP ESAPI | 20 apps using org.owasp.esapi method encodeForHTML also included in sanitization.blackbox.xml (for OWASP Benchmark analysis) | |
2 apps usig org.owasp.encoder (high-performance encoding for XSS prevention) | |||
See OWASP_Java_HTML_Sanitizer_Project If your application handles markup -- untrusted input that is supposed to contain HTML -- it can be very difficult to validate. Encoding is also difficult, since it would break all the tags that are supposed to be in the input. Therefore, you need a library that can parse and clean HTML formatted text. import org.owasp.html.Sanitizers; import org.owasp.html.PolicyFactory; PolicyFactory sanitizer = Sanitizers.FORMATTING.and(Sanitizers.BLOCKS); String cleanResults = sanitizer.sanitize("<p>Hello, <b>World!</b>"); | |||
commons-lang3-3.6.jar commons-text-1.1.jar commons-text-1.7.jar | Apache Commons Lang StringEscapeUtils Apache Commons Text StringEscapeUtils | org.apache.commons.lang3.StringEscapeUtils is Deprecated. Escapes and unescapes method [commons-lang-2.6]org.apache.commons.lang.StringEscapeUtils.escapeHtml(ref [rt]java.lang.String) also included in sanitization.blackbox.xml (for OWASP Benchmark analysis) | |
spring-web-3.2.16.RELEASE.jar spring-web-4.2.3.RELEASE.jar | Spring Web HtmlUtils org.springframework.web.util.HtmlUtils.htmlEscape() | Utility class for HTML escaping. Escapes and unescapes based on the W3C HTML 4.01 recommendation, handling character entity references. See also Stack Exchange - Preventing XSS attacks in a Spring MVC application controller method htmlEscape also included in sanitization.blackbox.xml (for OWASP Benchmark analysis) | |
now in System.Web.dll since .NET framework 4.5 | Microsoft Anti-XSS library | Preventing Cross-site scripting attacks using Microsoft Anti-Cross Site Scripting Library V3.0 (Anti-XSS V3.0)! Predefined in standard configuration file : 8.3.6\configuration\DataflowSecurity\DotNet\FlawSpec_DotNet.xml Sibling methods Microsoft.Security.Application.Encoder.HtmlEncode and Microsoft.Security.Application.Encoder.UrlEncode are defined starting with AIP Core 8.3.7. Missing namespace / class : [HtmlSanitizationLibrary]Microsoft.Security.Application.Sanitizer.GetSafeHtmlFragment([mscorlib]System.String) | |
Microsoft ASP .NET 4.5 dynamic encoding | | HTML encode binding shortcut (<%#:) . Note the ':' after the '<%'. see sample at Developer guide XSS | |
ASP.NET 4.5 ASP.NET Core | For ASP.NET 4.5, see https://docs.microsoft.com/en-us/aspnet/whitepapers/whats-new-in-aspnet-45-and-visual-studio-2012#_Toc318097382 For ASP.NET Core see https://docs.microsoft.com/en-us/aspnet/core/security/cross-site-scripting#accessing-encoders-in-code : use the default encoders contained in the For ASP.NET see https://docs.microsoft.com/en-us/aspnet/aspnet/overview/web-development-best-practices/what-not-to-do-in-aspnet-and-what-to-do-instead#security | ||
Microsoft ASP.NET Built-in Features to Fend Off Web Attacks Applies to | | ValidateRequest function that provides limited sanitization. ValidateRequest attribute on the @Page directive, is on by default. <%@ Page ValidateRequest="false" %> is a violation (turned off) | |
HtmlSanitizer.dll | HtmlSanitizer | HtmlSanitizer is a .NET library for cleaning HTML fragments and documents from constructs that can lead to XSS attacks. See https://github.com/mganss/HtmlSanitizer
| |
antisamy-1.5.7.jar | OWASP AntiSamy a library for HTML and CSS encoding. | For ensuring user-supplied HTML/CSS is in compliance within an application's rules.
| |
jsoup-1.13.1.jar | jsoup: Java HTML Parser jsoup is a Java library for working with real-world HTML. | <div >UNTRUSTED HTML</div > Defense:
| |
csrfguard-3.0.0.jar | OWASP CSRFGuard | N/A | import org.owasp.csrfguard.CsrfGuard; CSRF not managed by Dataflow analyzer, but worth to be mentionned in this paragraph. |
Other useful reading on sanitization and validation techniques
- Is OWASP ESAPI still the recommended way to secure JSP pages? (provides alternatives to ESAPI)
- Custom Annotation in Java for SQL Injection Safe Parameters
- Sanitizing user inputs with Spring MVC framework (Stackoverflow)
- Check List for Spring Security Implementation: Watch your foes
- Spring Validation Example – Spring MVC Form Validator
Validation methods configuration in AIP Core
Validation mecanism can hardly be configured in Dataflow configuration today (when the corresponding framework is not supported, the validators are neither).
This is not a big issue : you just have to perform the rest of the configuration, find flaws, and once they are found, filter out manually the ones that are protected by a trusted validator.
This filtering could be further automated as a custom, since QR detail procedures are accessible.
Sanitization methods configuration in AIP Core
Sanitisation methods can be configured in AIP Core since first generation of dataflow (6.4 / 7.0).
A defined sanitization method will stop the flow, so no flaw will be found with a defined sanitization in its flow path..
Please note, the DataflowRunner on-the-fly blackboxing does not generate any sanitization decision (to avoid any false negative by abusive decision).
The means to configure/define sanitization methods are multiple:
Standard sanitization through Flawspec XML files (up to AIP Core 8.3.14)
A standard configuration is delivered, thanks to 2 configuration files, located in AIP Core subfolders DotNet and J2EE of \configuration\DataflowSecurity.
The current configuration is not documented in DOC83, so it is worth reading to see what CAST considers as valid sanitization, and what is missing for your application.
Also, some methods of rt.jar and mscorlib.dll are declared as "clear" in the standard predefined methods : these are mostly .close() and .flush() for certain OutputStream classes.
Standard sanitization through Predefined Methods (from AIP Core 8.3.15)
A total redesign has been done in AIP Core 8.3.15:
- more precise definitions: a sanitization method stops the flow for only a set of flaw searches, not for all.
- more standard libraries supported; out-of-the-box accurate results
- high-level documentation (supported libraries) is available for all in User Input Security - predefined methods
Custom sanitization through custom blackbox files (generic sanitization)
Since 8.3.3, this configuration can be made specific to the search (XSS, HTTP Response Splitting, Log Forging, ...) to avoid for instance encodeForSQL() stopping a flaw for XSS injection. (since encodeForSQL does characters neutralization for...SQL, so not valid for XSS). Also, some flaws (OS Command injection and others) do not have vetted sanitization methods : it is not a matter of annoying characters: you don't want any user input flying to the command, so no dynamic content here.
See User Input Security - manually configuring blackbox methods.
Dataflow SME kit provides sample sanitization blackbox files in folder 6. Blackbox for JEE . Some have been promoted in standard configuration in 8.3.3+, 8.3.15, and above :
- OWASP.ESAPI.blackbox.xml
- OWASP.Java Encoder_V01.01.blackbox.xml ; still awaited in AIP Core.
Sample snippet from typical custom sanitization blackbox
<?xml version="1.0" encoding="utf-8"?> <BlackBox name="sample_sanitization" xmlns="http://tempuri.org/BlackBoxes.xsd"> <Class mangling="org.apache.commons.lang3.StringEscapeUtils"> <Methods> <Method signature="escapeHtml4(java.lang.String)"> <Flow source="1" sink="0" mode="clear" /> <Flow source="0" sink="-1" mode="assign" /> </Method> </Methods> </Class> </BlackBox>
Snippet comment
This snippet reads as follows:
- Define escapeHtml4(java.lang.String) method of class org.apache.commons.lang3.StringEscapeUtils as a vetted sanitization.
- Whenever a tainted input comes into object intance (self = sink="0" ),
- as first parameter : (java.lang.String) as source="1" ,
- then stop the flow : mode="clear"
- The flow being stopped, whenever the engine encounters this method in a graph exploration, it stops the current search, and goes to the next one.
How to define your own blackbox file
Take the above snippet as a sample, and just replace the class and method name by yours. The flow tags are unchanged, they are always the same for sanitization method taking one parameter.
Custom sanitization through custom blackbox files (specific sanitization per QR)
Same as above, but you copy the .blackbox.xml file in a folder structure that will tell which specific flaw search you want to stop. That way, a method like encodeForSQL will stop only the searches originating from SQL targets, and won't affect XSS, File Path manipulation or the other searches. Location of the specific blackbox file :
%PROGRAMDATA%/CAST/CAST/<version>/QR[QRId]/
where QRId can be any of the 8 following rules:
Folder | Rule name |
---|---|
QR7740 | CWE-79: Avoid cross-site scripting DOM vulnerabilities |
QR7742 | CWE-89: Avoid SQL injection vulnerabilities |
QR7746 | CWE-90: Avoid LDAP injection vulnerabilities |
QR7748 | CWE-78: Avoid OS command injection vulnerabilities |
QR7750 | CWE-91: Avoid XPath injection vulnerabilities |
QR7752 | CWE-73: Avoid file path manipulation vulnerabilities |
QR8044 | CWE-117: Avoid Log forging vulnerabilities |
QR8098 | CWE-134: Avoid uncontrolled format string |