Browse files

Merge branch 'release-1.0'

  • Loading branch information...
2 parents c67b5ea + 0441037 commit 314cb7f5a1be427904f0499b4c1ebb0c7cd66912 @jonpasski jonpasski committed Oct 22, 2012
Showing with 1,374 additions and 143 deletions.
  1. +5 −0 .gitignore
  2. +43 −17 README.md
  3. +144 −98 coverity-escapers/README.md
  4. +164 −0 coverity-escapers/samples/functional-testsuite/pom.xml
  5. +27 −0 ...ty-escapers/samples/functional-testsuite/src/main/java/com/coverity/testsuite/HomeController.java
  6. +41 −0 coverity-escapers/samples/functional-testsuite/src/main/resources/log4j.xml
  7. +28 −0 ...capers/samples/functional-testsuite/src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml
  8. +8 −0 coverity-escapers/samples/functional-testsuite/src/main/webapp/WEB-INF/spring/root-context.xml
  9. +7 −0 coverity-escapers/samples/functional-testsuite/src/main/webapp/WEB-INF/views/includes/footer.jsp
  10. +144 −0 coverity-escapers/samples/functional-testsuite/src/main/webapp/WEB-INF/views/includes/header.jsp
  11. +3 −0 coverity-escapers/samples/functional-testsuite/src/main/webapp/WEB-INF/views/includes/taglibs.jsp
  12. +271 −0 coverity-escapers/samples/functional-testsuite/src/main/webapp/WEB-INF/views/test-el.jsp
  13. +319 −0 coverity-escapers/samples/functional-testsuite/src/main/webapp/WEB-INF/views/test-jsp.jsp
  14. +33 −0 coverity-escapers/samples/functional-testsuite/src/main/webapp/WEB-INF/web.xml
  15. 0 coverity-escapers/samples/{ → mockup-examples}/java/ExampleJavaHtmlEscaper.java
  16. 0 coverity-escapers/samples/{ → mockup-examples}/java/ExampleSQLLikeEscaper.java
  17. +2 −0 coverity-escapers/samples/{ → mockup-examples}/jsp/example_el.jsp
  18. +110 −28 coverity-escapers/src/test/java/com/coverity/security/EscapeTest.java
  19. +7 −0 pom.xml
  20. +18 −0 test-advisor-policy.json
View
5 .gitignore
@@ -0,0 +1,5 @@
+target
+cov_build
+trunk
+run-analysis.sh
+README.html
View
60 README.md
@@ -1,34 +1,60 @@
# Coverity Security Library
-[Coverity](http://www.coverity.com) [Security Research Labs](https://communities.coverity.com/blogs/security) has developed open source (BSD style) Java libraries useful to remedy security defects.
+The Coverity Security Library (CSL) is a lightweight set of escaping routines for fixing cross-site scripting (XSS), SQL injection, and other security defects in Java web applications.
+
+Here's why it's worth checking out:
+
+* **It's secure:** We take the security of CSL seriously. Every change is carefully scrutinized through a process that includes manual code review, static analysis, fuzz testing, and unit testing.
+
+* **It's convenient:** CSL contains escapers for XSS and SQL injection that are missing from standard libraries like Apache Commons and Java EE. We use fast, easy to invoke static methods with short, intuitive names. We also provide hooks for Expression Language (EL) to make it easy to use within JSPs.
+
+* **It's small:** CSL has no external dependencies and is a minimalist library. This means it's fast and does not require any configuration besides dropping a JAR in the right location or modifying your build to do it.
+
+* **It's free:** CSL is distributed under a BSD-style license. We would appreciate patches be sent back to us but it's not required.
+
+Users of Coverity Security Advisor get remediation guidance based on escaping routines in CSL. However, CSL is a standalone project with no dependencies on Security Advisor.
-The libraries can be used in Java programs as well as JSPs. The escapers are also available as EL (Expression Language) functions for an easier use in JSPs.
## Escape
-The [Escape library](https://github.com/coverity/coverity-security-library/tree/master/coverity-escapers) contains several escapers for web content. These escaping functions help remedy common defects (mostly cross-site scripting) that occur when the data is inserted into HTML element, HTML attribute values, URI, JavaScript strings, SQL LIKE clauses, etc. More information are available in the [Escape directory](https://github.com/coverity/coverity-security-library/tree/master/coverity-escapers).
+The [Escape class](https://github.com/coverity/coverity-security-library/tree/develop/coverity-escapers) contains several escapers for web content. These escaping functions help remedy common defects (mostly cross-site scripting) that occur when the data is inserted into HTML element, HTML attribute values, URI, JavaScript strings, SQL LIKE clauses, etc. More information are available in the [Escape directory](https://github.com/coverity/coverity-security-library/tree/develop/coverity-escapers).
-Before using any of these methods, the user should understand the context (or nested contexts) in which the data is inserted. [Several examples](https://github.com/coverity/coverity-security-library/tree/master/coverity-escapers/samples) are available in the repository, and more will be available on [our blog](https://communities.coverity.com/blogs/security).
+Before using any of these methods, you should understand the context (or nested contexts) in which the data is inserted. [Several examples](https://github.com/coverity/coverity-security-library/tree/develop/coverity-escapers/samples) are available in the repository, and more will be available on [our blog](https://communities.coverity.com/blogs/security).
To include this library into your Maven project, add the following:
- <dependency>
- <groupId>com.coverity.security</groupId>
- <artifactId>coverity-escapers/artifactId>
- <version>1.0.0</version>
- </dependency>
+```xml
+<dependency>
+ <groupId>com.coverity</groupId>
+ <artifactId>coverity-escapers</artifactId>
+ <version>1.0</version>
+</dependency>
+```
+
+or drop the JAR file in the <code>WEB-INF/lib</code> directory.
Then you can use it directly in your JSPs:
- <%@ taglib uri="http://coverity.com/security" prefix="cov" %>
- <script>
- var x = '${cov:jsStringEscape(param.tainted)}';
- </script>
+```jsp
+<%@ taglib uri="http://coverity.com/security" prefix="cov" %>
+<script type="text/javascript">
+ var x = '${cov:jsStringEscape(param.tainted)}';
+</script>
+<div onclick="alert('${cov:htmlEscape(cov:jsStringEscape(param.tainted))}')">
+ ${cov:htmlEscape(param.tainted)}
+</div>
+```
or in your Java programs:
- import com.coverity.security.Escape;
- // ...
- return "<div>" + Escape.html(request.getParameter("tainted")) + </div>;
+```java
+import com.coverity.security.Escape;
+// ...
+return "<div onclick='alert(\""
+ + Escape.html(Escape.jsString(request.getParameter("tainted")))
+ + "\")'>"
+ + Escape.html(request.getParameter("tainted"))
+ + "</div>";
+```
To contact the SRL, please email us at <srl@coverity.com>. Fork away, we look forward to your pull requests!
@@ -56,4 +82,4 @@ To contact the SRL, please email us at <srl@coverity.com>. Fork away, we look fo
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- OF SUCH DAMAGE.
+ OF SUCH DAMAGE.
View
242 coverity-escapers/README.md
@@ -15,7 +15,7 @@ and understands their behavior; however, there is no dependency on
Coverity products. This library is completely standalone. Feel free to
use them! Just make sure you use them correctly :)
-### Table of Content
+### Table of Contents
1. [Installation](#main_install)
2. [Usage](#main_usage)
3. [HTML Contexts Examples](#main_contexts)
@@ -26,11 +26,13 @@ use them! Just make sure you use them correctly :)
## Using Maven
To include this library into your Maven project, add the following to your pom:
- <dependency>
- <groupId>com.coverity.security</groupId>
- <artifactId>coverity-escapers</artifactId>
- <version>1.0.0</version>
- </dependency>
+```xml
+<dependency>
+ <groupId>com.coverity</groupId>
+ <artifactId>coverity-escapers</artifactId>
+ <version>1.0.0</version>
+</dependency>
+```
## Manually Build and Deploy
We use maven to build the library, and you can simply do:
@@ -42,16 +44,57 @@ A JAR file will be created in the `coverity-escapers/target` directory. You can
this JAR file `coverity-escaper-1.0.0.jar` and place it in the `WEB-INF/lib` of your
application.
+To use the Escape library in a JSP scriptlet, you need to import the class:
+```jsp
+<%@ page import="com.coverity.security.Escape" %>
+```
+
## Build the Javadoc
The javadoc can be created directly from the Maven build:
$ cd coverity-security-library
$ mvn install
$ open ./coverity-escapers/target/apidocs/index.html
-# <a id="main_usage"></a> Remediation Examples and Usage
+# <a id="main_usage"></a> Usage
+
+## Example 1: XSS Defect in Java Servlet
+
+### Before Remediation
+
+The servlet below takes a request parameter called `index` and directly inserts
+it into the output within an HTML context, creating an XSS defect.
+
+```java
+public class IndexServlet extends HttpServlet {
+
+ protected void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String param = request.getParameter("index");
+ PrintWriter out = response.getWriter();
+ response.setContentType("text/html");
+ out.write("<html><body>Index requested: " + param);
+```
+
+### After Remediation
+
+To remedy, the Escape library needs to be imported into the project and then the
+`Escape.html` method should wrap the `param` at the injection point.
+
+```java
+import com.coverity.security.Escape;
+// ...
+public class IndexServlet extends HttpServlet {
-## JSP Expression Language XSS Defect
+ protected void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String param = request.getParameter("index");
+ PrintWriter out = response.getWriter();
+ response.setContentType("text/html");
+ out.write("<html><body>Index requested: " + Escape.html(param));
+```
+
+## Example 2: XSS Defect in JSP EL
### Before Remediation
@@ -62,18 +105,20 @@ Expression Language (EL) to insert the value. While this tainted data is wrapped
by the JSTL `fn:escapeXml` method, the defect still exists because the underlying
JavaScript string context is not addressed.
- <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" %>
- <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
-
- <!DOCTYPE html>
- <html>
- <head>
- <script src="/static/js/main.js"></script>
- </head>
- <body>
- <span onmouseover="lookupHelp('${fn:escapeXml(param.needHelp)}');">
- Hello Blogger!
- </span>
+```jsp
+<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" %>
+<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
+
+<!doctype html>
+<html>
+<head>
+ <script src="/static/js/main.js"></script>
+</head>
+<body>
+<span onmouseover="lookupHelp('${fn:escapeXml(param.needHelp)}');">
+ Hello Blogger!
+</span>
+```
### After Remediation
@@ -82,56 +127,25 @@ and then the `cov:jsStringEscape` EL method needs to wrap the `param.needHelp` a
the injection point. The outer `fn:escapeXml` method should still be used to
ensure values are properly escaped for the HTML attribute value context.
- <%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" %>
- <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
- <%@ taglib prefix="cov" uri="http://coverity.com/security" %>
-
- <!DOCTYPE html>
- <html>
- <head>
- <script src="/static/js/main.js"></script>
- </head>
- <body>
- <span onmouseover="lookupHelp('${fn:escapeXml(cov:jsStringEscape(param.needHelp))}');">
- Hello Blogger!
- </span>
+```jsp
+<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" %>
+<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
+<%@ taglib prefix="cov" uri="http://coverity.com/security" %>
+
+<!doctype html>
+<html>
+<head>
+ <script src="/static/js/main.js"></script>
+</head>
+<body>
+<span onmouseover="lookupHelp('${fn:escapeXml(cov:jsStringEscape(param.needHelp))}');">
+ Hello Blogger!
+</span>
+```
Note that if you want to limit the number of EL functions imported, you can use the
`cov:htmlEscape` function instead of `fn:escapeXml`.
-## Java Servlet XSS Defect
-
-### Before Remediation
-
-The servlet below takes a request parameter called `index` and directly inserts
-it into the output within an HTML context, creating an XSS defect.
-
- public class IndexServlet extends HttpServlet {
-
- protected void doGet(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- String param = request.getParameter("index");
- PrintWriter out = response.getWriter();
- response.setContentType("text/html");
- out.write("<html><body>Index requested: " + param);
-
-
-### After Remediation
-
-To remedy, the Escape library needs to be imported into the project and then the
-`Escape.html` method should wrap the `param` at the injection point.
-
- import com.coverity.security.Escape;
-
- public class IndexServlet extends HttpServlet {
-
- protected void doGet(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- String param = request.getParameter("index");
- PrintWriter out = response.getWriter();
- response.setContentType("text/html");
- out.write("<html><body>Index requested: " + Escape.html(param));
-
# <a id="main_contexts"></a> Background Information
## Contexts
@@ -142,7 +156,9 @@ obligations. A context defines a subset of a language and syntax rules. For
example, the following `TAINTED_DATA_HERE` text occurs in an HTML double-quoted
attribute context.
- <span id="TAINTED_DATA_HERE">Some text here</span>
+```html
+<span id="TAINTED_DATA_HERE">Some text here</span>
+```
When tainted data is able to circumvent a context, it can lead to a security
defect, such as a cross-site scripting (XSS), SQL injection (SQLi), etc.. For
@@ -165,7 +181,9 @@ but a set of names should also be disallowed since they might create an XSS defe
A nested context occurs when more than one context exists for a given piece of
data. An example is the common HTML `<a>` anchor element and its `onclick` attribute:
- <a onclick="pullAuthor('TAINTED_DATA_HERE');return false;" ...
+```html
+<a onclick="pullAuthor('TAINTED_DATA_HERE');return false;">...
+```
In the example, there are currently two contexts that have safety obligations
for `TAINTED_DATA_HERE`:
@@ -194,27 +212,36 @@ The Escape library groups the following HTML contexts as one:
HTML normal element injection example:
- <span>TAINTED_DATA_HERE</span>
+```html
+<span>TAINTED_DATA_HERE</span>
+```
HTML quoted attribute injection example:
- <div id="TAINTED_DATA_HERE">
- <span id='TAINTED_DATA_HERE_TOO'>Testing blog</span>
- </div>
+```html
+<div id="TAINTED_DATA_HERE">
+ <span id='TAINTED_DATA_HERE_TOO'>Testing blog</span>
+</div>
+```
The Escape library meets the security obligations of these contexts by encoding
sensitive characters as HTML character references.
+Escape functions to use:
+* Java/JSP scriptlet: <code>Escape.html()</code>
+* JSP EL: <code>${cov:htmlEscape()}</code>
+
### JavaScript Strings (Single and Double Quoted)
ECMA 262 defines the [ECMAScript language] [2], of which JavaScript is a dialect.
The standard defines a string literal syntax for both ' and " strings in section
7.8.4 (of the ECMA PDF file).
Injection example:
-
- var blogComment = 'TAINTED_DATA_HERE';
- logBlogComment(blogComment, "TAINTED_DATA_HERE_TOO");
+```js
+var blogComment = 'TAINTED_DATA_HERE';
+logBlogComment(blogComment, "TAINTED_DATA_HERE_TOO");
+```
The Escape library meets the security obligations of these contexts by escaping
these characters using JavaScript Unicode escaping. In addition, since JavaScript
@@ -224,43 +251,55 @@ summarized as the tag should not be closed, and the string literal `</script>`
should not appear in the JavaScript string. For this purpose, we also escape
the `/` character.
+Escape functions to use:
+* Java/JSP scriptlet: <code>Escape.jsString()</code>
+* JSP EL: <code>${cov:jsStringEscape()}</code>
+
### CSS Strings (Single and Double Quoted)
CSS Level 2, Revision 1 (CSS 2.1) defines single-quoted (', U+0027) and
double-quoted (", U+0022) [strings] [3]. These strings are also used within a URL
quoted context and have the same obligations within that context.
Injection example:
-
- span[id="TAINTED_DATA_HERE"] {
- background-color: #efefef;
- }
-
+```css
+span[id="TAINTED_DATA_HERE"] {
+ background-color: #efefef;
+}
+```
The Escape library meets the security obligations of these contexts by escaping
these characters using CSS Unicode escaping. Just as JavaScript string
contexts are often in a parent `<script>` tag, CSS contexts often have a parent
HTML context within the `<style>` tag. For the same reason as JavaScript, we also
escape the `/` character.
+Escape functions to use:
+* Java/JSP scriptlet: <code>Escape.cssString()</code>
+* JSP EL: <code>${cov:cssStringEscape()}</code>
+
### URIs
The URI context is comprised of numerous sub-contexts. [RFC 3986] [8] provides
details on each of them. When used in HTML, the URL context includes some parent context,
such as HTML, JavaScript, or CSS.
Injection examples:
-
- <style>
- span[id="clickmes"] {
- background-image: url('TAINTED_DATA_HERE');
- }
- </style>
- <a href="http://www.example.com/?test=TAINTED_DATA_HERE">Click me!</a>
-
+```html
+<style>
+ #clickme a {
+ background-image: url('TAINTED_DATA_HERE');
+ }
+</style>
+<a id="clickme" href="http://www.example.com/?test=TAINTED_DATA_HERE">Click me!</a>
+```
When the tainted data is inserted as a query parameter, the Escape library
meets the URI query parameter obligations by encoding sensitive characters using
URI percent encoding.
+Escape functions to use:
+* Java/JSP scriptlet: <code>Escape.uri()</code>
+* JSP EL: <code>${cov:uriEncode()}</code>
+
### SQL LIKE Context
SQL LIKE clauses use special characters to perform wildcard matching. When
@@ -273,27 +312,34 @@ returned, changing the intent of the query.
Injection example:
- entityManager.createQuery("FROM MyEntity e WHERE e.content LIKE :like_query")
- .setParameter("like_query", "%" + TAINTED_DATA_HERE)
- .getResultList();
+```java
+entityManager.createQuery("FROM MyEntity e WHERE e.content LIKE :like_query")
+ .setParameter("like_query", "%" + TAINTED_DATA_HERE)
+ .getResultList();
+```
The Escape library meets these obligations by escaping these wildcard characters
using an additional escape character, by default the at sign (@, U+0040):
- entityManager.createQuery("FROM MyEntity e WHERE e.content LIKE :like_query ESCAPE '@'")
- .setParameter("like_query", "%" + Escape.sqlLikeClause(TAINTED_DATA_HERE))
- .getResultList();
+```java
+entityManager.createQuery("FROM MyEntity e WHERE e.content LIKE :like_query ESCAPE '@'")
+ .setParameter("like_query", "%" + Escape.sqlLikeClause(TAINTED_DATA_HERE))
+ .getResultList();
+```
Note: the Escape library does not prevent SQL injection issues. It preserves
the meaning of the LIKE query by escaping only characters with special meaning
in a LIKE clause.
-### Unquoted
+Escape function to use:
+* Java/JSP scriptlet: <code>Escape.sqlLikeClause()</code>
+
+### Unquoted HTML attributes or CSS URI
-HTML allows attribute values and CSS allows URI values to be used in an unquoted contexts, along
+HTML allows attribute values and CSS allows URI values to be used in an unquoted values, along
with their single and double-quoted alternatives. We recommend not using the
-unquoted context in HTML or CSS. Rather, use the double-quoted context. The reasoning
-is that unquoted contexts make it even more difficult to mitigate and are sometimes
+unquoted values in HTML or CSS. Rather, use the double or single quoted values. The reasoning
+is that unquoted values make it even more difficult to mitigate and are sometimes
web browser specific.
# <a id="main_authors"></a> Authors
View
164 coverity-escapers/samples/functional-testsuite/pom.xml
@@ -0,0 +1,164 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>com.coverity</groupId>
+ <artifactId>csl-functional-test</artifactId>
+ <name>csl-functional-test</name>
+ <packaging>war</packaging>
+ <version>1.0.0-BUILD-SNAPSHOT</version>
+ <properties>
+ <java-version>1.6</java-version>
+ <org.springframework-version>3.1.0.RELEASE</org.springframework-version>
+ <org.aspectj-version>1.6.9</org.aspectj-version>
+ <org.slf4j-version>1.5.10</org.slf4j-version>
+ </properties>
+ <dependencies>
+ <!-- Spring -->
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-context</artifactId>
+ <version>${org.springframework-version}</version>
+ <exclusions>
+ <!-- Exclude Commons Logging in favor of SLF4j -->
+ <exclusion>
+ <groupId>commons-logging</groupId>
+ <artifactId>commons-logging</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-webmvc</artifactId>
+ <version>${org.springframework-version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.coverity.security</groupId>
+ <artifactId>coverity-escapers</artifactId>
+ <version>1.0</version>
+ </dependency>
+
+ <!-- AspectJ -->
+ <dependency>
+ <groupId>org.aspectj</groupId>
+ <artifactId>aspectjrt</artifactId>
+ <version>${org.aspectj-version}</version>
+ </dependency>
+
+ <!-- Logging -->
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <version>${org.slf4j-version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>jcl-over-slf4j</artifactId>
+ <version>${org.slf4j-version}</version>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ <version>${org.slf4j-version}</version>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <version>1.2.15</version>
+ <exclusions>
+ <exclusion>
+ <groupId>javax.mail</groupId>
+ <artifactId>mail</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>javax.jms</groupId>
+ <artifactId>jms</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>com.sun.jdmk</groupId>
+ <artifactId>jmxtools</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>com.sun.jmx</groupId>
+ <artifactId>jmxri</artifactId>
+ </exclusion>
+ </exclusions>
+ <scope>runtime</scope>
+ </dependency>
+
+ <!-- @Inject -->
+ <dependency>
+ <groupId>javax.inject</groupId>
+ <artifactId>javax.inject</artifactId>
+ <version>1</version>
+ </dependency>
+
+ <!-- Servlet -->
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ <version>2.5</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet.jsp</groupId>
+ <artifactId>jsp-api</artifactId>
+ <version>2.1</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>jstl</artifactId>
+ <version>1.2</version>
+ </dependency>
+
+ <!-- Test -->
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.7</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-eclipse-plugin</artifactId>
+ <version>2.9</version>
+ <configuration>
+ <additionalProjectnatures>
+ <projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
+ </additionalProjectnatures>
+ <additionalBuildcommands>
+ <buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
+ </additionalBuildcommands>
+ <downloadSources>true</downloadSources>
+ <downloadJavadocs>true</downloadJavadocs>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.3.2</version>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ <compilerArgument>-Xlint:all</compilerArgument>
+ <showWarnings>true</showWarnings>
+ <showDeprecation>true</showDeprecation>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>exec-maven-plugin</artifactId>
+ <version>1.2.1</version>
+ <configuration>
+ <mainClass>org.test.int1.Main</mainClass>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
View
27 ...ers/samples/functional-testsuite/src/main/java/com/coverity/testsuite/HomeController.java
@@ -0,0 +1,27 @@
+package com.coverity.testsuite;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+@Controller
+public class HomeController {
+
+ // By default we go to the EL tests.
+ @RequestMapping(value = "/", method = RequestMethod.GET)
+ public String index(Model model) {
+ return "test-el";
+ }
+
+ @RequestMapping(value = "/el", method = RequestMethod.GET)
+ public String testEL(Model model) {
+ return "test-el";
+ }
+
+ @RequestMapping(value = "/scriptlet", method = RequestMethod.GET)
+ public String testJSP(Model model) {
+ return "test-jsp";
+ }
+}
+
View
41 coverity-escapers/samples/functional-testsuite/src/main/resources/log4j.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE log4j:configuration PUBLIC "-//APACHE//DTD LOG4J 1.2//EN" "log4j.dtd">
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
+
+ <!-- Appenders -->
+ <appender name="console" class="org.apache.log4j.ConsoleAppender">
+ <param name="Target" value="System.out" />
+ <layout class="org.apache.log4j.PatternLayout">
+ <param name="ConversionPattern" value="%-5p: %c - %m%n" />
+ </layout>
+ </appender>
+
+ <!-- Application Loggers -->
+ <logger name="com.coverity.testsuite">
+ <level value="info" />
+ </logger>
+
+ <!-- 3rdparty Loggers -->
+ <logger name="org.springframework.core">
+ <level value="info" />
+ </logger>
+
+ <logger name="org.springframework.beans">
+ <level value="info" />
+ </logger>
+
+ <logger name="org.springframework.context">
+ <level value="info" />
+ </logger>
+
+ <logger name="org.springframework.web">
+ <level value="info" />
+ </logger>
+
+ <!-- Root Logger -->
+ <root>
+ <priority value="warn" />
+ <appender-ref ref="console" />
+ </root>
+
+</log4j:configuration>
View
28 ...amples/functional-testsuite/src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans:beans xmlns="http://www.springframework.org/schema/mvc"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:beans="http://www.springframework.org/schema/beans"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
+ http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
+
+ <!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
+
+ <!-- Enables the Spring MVC @Controller programming model -->
+ <annotation-driven />
+
+ <!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
+ <resources mapping="/resources/**" location="/resources/" />
+
+ <!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
+ <beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
+ <beans:property name="prefix" value="/WEB-INF/views/" />
+ <beans:property name="suffix" value=".jsp" />
+ </beans:bean>
+
+ <context:component-scan base-package="com.coverity.testsuite" />
+
+
+
+</beans:beans>
View
8 ...ity-escapers/samples/functional-testsuite/src/main/webapp/WEB-INF/spring/root-context.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
+
+ <!-- Root Context: defines shared resources visible to all other web components -->
+
+</beans>
View
7 ...y-escapers/samples/functional-testsuite/src/main/webapp/WEB-INF/views/includes/footer.jsp
@@ -0,0 +1,7 @@
+</div>
+</div>
+<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
+<script src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.1.1/js/bootstrap.min.js"></script>
+<script src='//cdnjs.cloudflare.com/ajax/libs/prettify/188.0.0/prettify.js'></script>
+</body>
+</html>
View
144 ...y-escapers/samples/functional-testsuite/src/main/webapp/WEB-INF/views/includes/header.jsp
@@ -0,0 +1,144 @@
+<%@ include file="/WEB-INF/views/includes/taglibs.jsp" %>
+<!doctype html>
+<html>
+<head>
+ <title>CSL test suite - JSP</title>
+ <link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.1.1/css/bootstrap-combined.min.css" rel="stylesheet">
+ <link href="//netdna.bootstrapcdn.com/font-awesome/2.0/css/font-awesome.css" rel="stylesheet">
+
+ <style>
+/* shamelessly copied from bootstrap website */
+body {
+ position: relative;
+ padding-top: 60px;
+}
+section {
+ padding-top: 30px;
+}
+section > .page-header,
+section > .lead {
+ color: #5a5a5a;
+}
+section > ul li {
+ margin-bottom: 5px;
+}
+.bs-docs-sidenav {
+ width: 228px;
+ margin: 30px 0 0;
+ padding: 0;
+ background-color: #fff;
+ -webkit-border-radius: 6px;
+ -moz-border-radius: 6px;
+ border-radius: 6px;
+ -webkit-box-shadow: 0 1px 4px rgba(0,0,0,.065);
+ -moz-box-shadow: 0 1px 4px rgba(0,0,0,.065);
+ box-shadow: 0 1px 4px rgba(0,0,0,.065);
+}
+.bs-docs-sidenav > li > a {
+ display: block;
+ *width: 190px;
+ margin: 0 0 -1px;
+ padding: 8px 14px;
+ border: 1px solid #e5e5e5;
+}
+.bs-docs-sidenav > li:first-child > a {
+ -webkit-border-radius: 6px 6px 0 0;
+ -moz-border-radius: 6px 6px 0 0;
+ border-radius: 6px 6px 0 0;
+}
+.bs-docs-sidenav > li:last-child > a {
+ -webkit-border-radius: 0 0 6px 6px;
+ -moz-border-radius: 0 0 6px 6px;
+ border-radius: 0 0 6px 6px;
+}
+.bs-docs-sidenav > .active > a {
+ position: relative;
+ z-index: 2;
+ padding: 9px 15px;
+ border: 0;
+ text-shadow: 0 1px 0 rgba(0,0,0,.15);
+ -webkit-box-shadow: inset 1px 0 0 rgba(0,0,0,.1), inset -1px 0 0 rgba(0,0,0,.1);
+ -moz-box-shadow: inset 1px 0 0 rgba(0,0,0,.1), inset -1px 0 0 rgba(0,0,0,.1);
+ box-shadow: inset 1px 0 0 rgba(0,0,0,.1), inset -1px 0 0 rgba(0,0,0,.1);
+}
+/* Chevrons */
+.bs-docs-sidenav .icon-chevron-right {
+ float: right;
+ margin-top: 2px;
+ margin-right: -6px;
+ opacity: .25;
+}
+.bs-docs-sidenav > li > a:hover {
+ background-color: #f5f5f5;
+}
+.bs-docs-sidenav a:hover .icon-chevron-right {
+ opacity: .5;
+}
+.bs-docs-sidenav .active .icon-chevron-right,
+.bs-docs-sidenav .active a:hover .icon-chevron-right {
+ opacity: 1;
+}
+.bs-docs-sidenav.affix {
+ top: 40px;
+}
+.bs-docs-sidenav.affix-bottom {
+ position: absolute;
+ top: auto;
+ bottom: 270px;
+}
+
+.com { color: #93a1a1; }
+.lit { color: #195f91; }
+.pun, .opn, .clo { color: #93a1a1; }
+.fun { color: #dc322f; }
+.str, .atv { color: #D14; }
+.kwd, .prettyprint .tag { color: #1e347b; }
+.typ, .atn, .dec, .var { color: teal; }
+.pln { color: #48484c; }
+
+.prettyprint {
+ padding: 8px;
+ background-color: #f7f7f9;
+ border: 1px solid #e1e1e8;
+}
+.prettyprint.linenums {
+ -webkit-box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0;
+ -moz-box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0;
+ box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0;
+}
+
+/* Specify class=linenums on a pre to get line numbering */
+ol.linenums {
+ margin: 0 0 0 33px; /* IE indents via margin-left */
+}
+ol.linenums li {
+ padding-left: 12px;
+ color: #bebec5;
+ line-height: 20px;
+ text-shadow: 0 1px 0 #fff;
+}
+ </style>
+</head>
+
+<body data-spy="scroll" data-target=".bs-docs-sidebar" onload="prettyPrint()">
+
+<div class="navbar navbar-inverse navbar-fixed-top">
+ <div class="navbar-inner">
+ <div class="container">
+ <a class="brand" href="https://github.com/coverity/coverity-security-library">CSL on Github</a>
+ <div class="nav-collapse collapse">
+ <ul class="nav">
+ <li>
+ <a href="/testsuite/scriptlet">Java/JSP test suite</a>
+ </li>
+ <li>
+ <a href="/testsuite/el">EL test suite</a>
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+</div>
+
+<div class='container-fluid'>
+<div class="row-fluid">
View
3 ...-escapers/samples/functional-testsuite/src/main/webapp/WEB-INF/views/includes/taglibs.jsp
@@ -0,0 +1,3 @@
+<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
+<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
+<%@ taglib uri="http://coverity.com/security" prefix="cov" %>
View
271 coverity-escapers/samples/functional-testsuite/src/main/webapp/WEB-INF/views/test-el.jsp
@@ -0,0 +1,271 @@
+<%@ include file="/WEB-INF/views/includes/header.jsp" %>
+
+ <div class="span3 bs-docs-sidebar">
+ <ul class="nav nav-list bs-docs-sidenav affix">
+ <li><a href="#htmlEscape"><i class="icon-chevron-right"></i> htmlEscape</a></li>
+ <li><a href="#jsStringEscape"><i class="icon-chevron-right"></i> jsStringEscape</a></li>
+ <li><a href="#cssStringEscape"><i class="icon-chevron-right"></i> cssStringEscape</a></li>
+ <li><a href="#jsRegexEscape"><i class="icon-chevron-right"></i> jsRegexEscape</a></li>
+ <li><a href="#uriEncode"><i class="icon-chevron-right"></i> uriEncode</a></li>
+ <li><a href="#nested"><i class="icon-chevron-right"></i> Nested contexts</a></li>
+ </ul>
+ </div>
+
+ <div class="span9">
+
+<section id="htmlEscape">
+ <div class="page-header">
+ <h1>htmlEscape <small>com.coverity.security.EscapeEL.htmlEscape</small></h1>
+ </div>
+ <ul>
+ <li>Performs HTML escaping as EL function</li>
+ <li>Testcases: GET parameter 'web'</li>
+ </ul>
+ <h3>Code</h3>
+<pre class="prettyprint linenums">
+&lt;div>
+ Content: \${cov:htmlEscape(param.web)}
+&lt;/div>
+</pre>
+ <h3>Result</h3>
+ <div>
+ Content: ${cov:htmlEscape(param.web)}
+ </div>
+</section>
+
+<section id="htmlEscape">
+ <div class="page-header">
+ <h1>htmlEscape <small>com.coverity.security.EscapeEL.htmlEscape</small></h1>
+ </div>
+ <ul>
+ <li>Performs HTML escaping as EL function</li>
+ <li>Testcases: GET parameter 'web'</li>
+ </ul>
+ <h3>Code</h3>
+<pre class="prettyprint linenums">
+&lt;div id="\${cov:htmlEscape(param.web)}">
+ Content
+&lt;/div>
+</pre>
+ <h3>Result</h3>
+ <div id="${cov:htmlEscape(param.web)}">
+ Content
+ </div>
+</section>
+
+
+<section id="jsStringEscape">
+ <div class="page-header">
+ <h1>jsStringEscape <small>com.coverity.security.EscapeEL.jsStringEscape</small></h1>
+ </div>
+ <ul>
+ <li>Performs JavaScript String Unicode escaping as EL function</li>
+ <li>Testcases: GET parameter 'web'</li>
+ </ul>
+ <h3>Code</h3>
+<pre class="prettyprint linenums">
+&lt;script type="text/javascript">
+ var x = '\${cov:jsStringEscape(param.web)}';
+ console.log(x);
+&lt;/script>
+</pre>
+ <h3>Result</h3>
+ <script type="text/javascript">
+ var x = '${cov:jsStringEscape(param.web)}';
+ console.log(x);
+ </script>
+</section>
+
+<section id="jsStringEscape">
+ <div class="page-header">
+ <h1>jsStringEscape <small>com.coverity.security.EscapeEL.jsStringEscape</small></h1>
+ </div>
+ <ul>
+ <li>Performs JavaScript String Unicode escaping as EL function</li>
+ <li>Testcases: GET parameter 'web'</li>
+ </ul>
+ <h3>Code</h3>
+<pre class="prettyprint linenums">
+&lt;script type="text/javascript">
+ var x = "\${cov:jsStringEscape(param.web)}";
+ console.log(x);
+&lt;/script>
+</pre>
+ <h3>Result</h3>
+ <script type="text/javascript">
+ var x = "${cov:jsStringEscape(param.web)}";
+ console.log(x);
+ </script>
+</section>
+
+<section id="cssStringEscape">
+ <div class="page-header">
+ <h1>cssStringEscape <small>com.coverity.security.EscapeEL.cssStringEscape</small></h1>
+ </div>
+ <ul>
+ <li>Performs CSS String escaping as EL function</li>
+ <li>Testcases: GET parameter 'web'</li>
+ </ul>
+ <h3>Code</h3>
+<pre class="prettyprint linenums">
+&lt;style>
+ div[id *= '\${cov:cssStringEscape(param.web)}'] {
+ background-color: pink;
+ }
+&lt;/style>
+</pre>
+ <h3>Result</h3>
+ <style>
+ div[id *= '${cov:cssStringEscape(param.web)}'] {
+ background-color: pink;
+ }
+ </style>
+ <div id="test-result">test-content</div>
+</section>
+
+<section id="cssStringEscape">
+ <div class="page-header">
+ <h1>cssStringEscape <small>com.coverity.security.EscapeEL.cssStringEscape</small></h1>
+ </div>
+ <ul>
+ <li>Performs CSS String escaping as EL function</li>
+ <li>Testcases: GET parameter 'web'</li>
+ </ul>
+ <h3>Code</h3>
+<pre class="prettyprint linenums">
+&lt;style>
+ div[id *= "\${cov:cssStringEscape(param.web)}"] {
+ background-color: pink;
+ }
+&lt;/style>
+</pre>
+ <h3>Result</h3>
+ <style>
+ div[id *= "${cov:cssStringEscape(param.web)}"] {
+ background-color: pink;
+ }
+ </style>
+ <div id="test-result">test-content</div>
+</section>
+
+<section id="jsRegexEscape">
+ <div class="page-header">
+ <h1>jsRegexEscape <small>com.coverity.security.EscapeEL.jsRegexEscape</small></h1>
+ </div>
+ <ul>
+ <li>Performs JavaScript regex escaping as EL function</li>
+ <li>Testcases: GET parameter 'web'</li>
+ </ul>
+ <h3>Code</h3>
+<pre class="prettyprint linenums">
+&lt;script type="text/javascript">
+ var control = 'content';
+ var reg = /^\${cov:jsRegexEscape(param.web)}/;
+ console.log(reg.test(control));
+&lt;/script>
+</pre>
+ <h3>Result</h3>
+ <script type="text/javascript">
+ var control = 'content';
+ var reg = /^${cov:jsRegexEscape(param.web)}/;
+ console.log(reg.test(control));
+ </script>
+</section>
+
+<section id="uriEncode">
+ <div class="page-header">
+ <h1>uriEncode <small>com.coverity.security.EscapeEL.uriEncode</small></h1>
+ </div>
+ <ul>
+ <li>Performs URI encoding as EL function</li>
+ <li>Testcases: GET parameter 'web'</li>
+ </ul>
+ <h3>Code</h3>
+<pre class="prettyprint linenums">
+&lt;a href="/testsuite/el?web=\${cov:uriEncode(param.web)}">web link&lt;/a>
+</pre>
+ <h3>Result</h3>
+ <a href="/testsuite/el?web=${cov:uriEncode(param.web)}">web link</a>
+</section>
+
+
+<!-- Then, we can add some nested context variations -->
+<section id="nested">
+ <div class="page-header">
+ <h1>Nested contexts <small>HTML double quoted attribute, JavaScript single-quoted string</small></h1>
+ </div>
+ <ul>
+ <li>Uses jsStringEscape and htmlEscape</li>
+ <li>Testcases: GET parameter 'web'</li>
+ </ul>
+ <h3>Code</h3>
+<pre class="prettyprint linenums">
+&lt;img src=. onerror="console.log('\${cov:htmlEscape(cov:jsStringEscape(param.web))}')" />
+</pre>
+ <h3>Result</h3>
+
+ <img src=. onerror="console.log('${cov:htmlEscape(cov:jsStringEscape(param.web))}')" />
+
+ <div class='well well-small'>
+ Note, here's what the JavaScript engine receives:
+ <code style="background-color:#fff">console.log('${cov:htmlEscape(cov:jsStringEscape(param.web))}')</code>
+ </div>
+
+</section>
+
+
+<section id="nested">
+ <div class="page-header">
+ <h1>Nested contexts <small>HTML double quoted attribute, CSS single-quoted string (in url())</small></h1>
+ </div>
+ <ul>
+ <li>Uses cssStringEscape and htmlEscape</li>
+ <li>Testcases: GET parameter 'web'</li>
+ </ul>
+ <h3>Code</h3>
+<pre class="prettyprint linenums">
+&lt;div style="background-image: url('/404/\${cov:htmlEscape(cov:cssStringEscape(param.web))}')">
+ Content
+&lt;/div>
+</pre>
+ <h3>Result</h3>
+ <div style="background-image: url('/404/${cov:htmlEscape(cov:cssStringEscape(param.web))}')">
+ Content
+ </div>
+
+ <div class='well well-small'>
+ Note, here's what the CSS engine receives:
+ <code style="background-color:#fff">background-image: url('/404/${cov:htmlEscape(cov:cssStringEscape(param.web))}')</code>
+ </div>
+</section>
+
+<section id="nested">
+ <div class="page-header">
+ <h1>Nested contexts <small>JavaScript String, JavaScript regex</small></h1>
+ </div>
+ <ul>
+ <li>Uses jsRegexEscape and jsStringEscape</li>
+ <li>Testcases: GET parameter 'web'</li>
+ </ul>
+ <h3>Code</h3>
+<pre class="prettyprint linenums">
+&lt;script type="text/javascript">
+ var control = 'content';
+ var reg = new RegExp('^(\${cov:jsStringEscape(cov:jsRegexEscape(param.web))})?content');
+ console.log(reg.test(control));
+&lt;/script>
+</pre>
+ <h3>Result</h3>
+ <script type="text/javascript">
+ var control = 'content';
+ var reg = new RegExp('^(${cov:jsStringEscape(cov:jsRegexEscape(param.web))})?content');
+ console.log(reg.test(control));
+ </script>
+ <div class='well well-small'>
+ Note, here's what the JS engine receives:
+ <code style="background-color:#fff">var reg = new RegExp('^(${cov:htmlEscape(cov:jsStringEscape(cov:jsRegexEscape(param.web)))})?content');</code>
+ </div>
+</section>
+
+ </div>
+<%@ include file="/WEB-INF/views/includes/footer.jsp" %>
View
319 coverity-escapers/samples/functional-testsuite/src/main/webapp/WEB-INF/views/test-jsp.jsp
@@ -0,0 +1,319 @@
+<%@ page import="com.coverity.security.Escape" %>
+
+<%@ include file="/WEB-INF/views/includes/header.jsp" %>
+
+ <div class="span3 bs-docs-sidebar">
+ <ul class="nav nav-list bs-docs-sidenav affix">
+ <li><a href="#html"><i class="icon-chevron-right"></i> Escape.html</a></li>
+ <li><a href="#jsString"><i class="icon-chevron-right"></i> Escape.jsString</a></li>
+ <li><a href="#cssString"><i class="icon-chevron-right"></i> Escape.cssString</a></li>
+ <li><a href="#jsRegex"><i class="icon-chevron-right"></i> Escape.jsRegex</a></li>
+ <li><a href="#uri"><i class="icon-chevron-right"></i> Escape.uri</a></li>
+ <li><a href="#nested"><i class="icon-chevron-right"></i> Nested contexts</a></li>
+ </ul>
+ </div>
+
+ <div class="span9">
+
+<section id="html">
+ <div class="page-header">
+ <h1>html <small>com.coverity.security.Escape.html</small></h1>
+ </div>
+ <ul>
+ <li>Performs HTML escaping from Java or JSP scriptlet</li>
+ <li>Testcases: GET parameter 'web'</li>
+ </ul>
+ <h3>Code</h3>
+<pre class="prettyprint linenums">
+&lt;%
+ String input = request.getParameter("web");
+ String result = Escape.html(input);
+
+ out.write("&lt;div>");
+ out.write("Content:" + result);
+ out.write("&lt;/div>");
+%&gt;
+</pre>
+ <h3>Result</h3>
+<%
+String input = request.getParameter("web");
+String result = Escape.html(input);
+
+out.write("<div>");
+out.write("Content:" + result);
+out.write("</div>");
+%>
+</section>
+
+<section id="html">
+ <div class="page-header">
+ <h1>html <small>com.coverity.security.Escape.html</small></h1>
+ </div>
+ <ul>
+ <li>Performs HTML escaping from Java or JSP scriptlet</li>
+ <li>Testcases: GET parameter 'web'</li>
+ </ul>
+ <h3>Code</h3>
+<pre class="prettyprint linenums">
+&lt;%
+ String input2 = request.getParameter("web");
+
+ out.write("&lt;div id=\"");
+ out.write(Escape.html(input2));
+ out.write("\">\n");
+ out.write("Content");
+ out.write("&lt;/div>");
+%&gt;
+</pre>
+ <h3>Result</h3>
+<%
+ String input2 = request.getParameter("web");
+
+ out.write("<div id=\"");
+ out.write(Escape.html(input2));
+ out.write("\">\n");
+ out.write("Content");
+ out.write("</div>");
+%>
+</section>
+
+
+<section id="jsString">
+ <div class="page-header">
+ <h1>jsString <small>com.coverity.security.Escape.jsString</small></h1>
+ </div>
+ <ul>
+ <li>Performs JavaScript String Unicode escaping from Java or JSP scriptlet</li>
+ <li>Testcases: GET parameter 'web'</li>
+ </ul>
+ <h3>Code</h3>
+<pre class="prettyprint linenums">
+&lt;script type="text/javascript">
+ var x = '&lt;%= Escape.jsString(request.getParameter("web")) %&gt;';
+ console.log(x);
+&lt;/script>
+</pre>
+ <h3>Result</h3>
+ <script type="text/javascript">
+ var x = '<%= Escape.jsString(request.getParameter("web")) %>';
+ console.log(x);
+ </script>
+</section>
+
+<section id="jsString">
+ <div class="page-header">
+ <h1>jsString <small>com.coverity.security.Escape.jsString</small></h1>
+ </div>
+ <ul>
+ <li>Performs JavaScript String Unicode escaping from Java or JSP scriptlet</li>
+ <li>Testcases: GET parameter 'web'</li>
+ </ul>
+ <h3>Code</h3>
+<pre class="prettyprint linenums">
+&lt;script type="text/javascript">
+ var x = "&lt;%= Escape.jsString(request.getParameter("web")) %&gt;";
+ console.log(x);
+&lt;/script>
+</pre>
+ <h3>Result</h3>
+ <script type="text/javascript">
+ var x = "<%= Escape.jsString(request.getParameter("web")) %>";
+ console.log(x);
+ </script>
+</section>
+
+<section id="cssString">
+ <div class="page-header">
+ <h1>cssString <small>com.coverity.security.Escape.cssString</small></h1>
+ </div>
+ <ul>
+ <li>Performs CSS String escaping from Java or JSP scriptlet</li>
+ <li>Testcases: GET parameter 'web'</li>
+ </ul>
+ <h3>Code</h3>
+<pre class="prettyprint linenums">
+&lt;style>
+ div[id *= '&lt;%= Escape.cssString(request.getParameter("web")) %&gt;'] {
+ background-color: pink;
+ }
+&lt;/style>
+</pre>
+ <h3>Result</h3>
+ <style>
+ div[id *= '<%= Escape.cssString(request.getParameter("web")) %>'] {
+ background-color: pink;
+ }
+ </style>
+ <div id="test-result">test-content</div>
+</section>
+
+<section id="cssString">
+ <div class="page-header">
+ <h1>cssString <small>com.coverity.security.Escape.cssString</small></h1>
+ </div>
+ <ul>
+ <li>Performs CSS String escaping from Java or JSP scriptlet</li>
+ <li>Testcases: GET parameter 'web'</li>
+ </ul>
+ <h3>Code</h3>
+<pre class="prettyprint linenums">
+&lt;style>
+ div[id *= "&lt;%= Escape.cssString(request.getParameter("web")) %&gt;"] {
+ background-color: pink;
+ }
+&lt;/style>
+</pre>
+ <h3>Result</h3>
+ <style>
+ div[id *= "<%= Escape.cssString(request.getParameter("web")) %>"] {
+ background-color: pink;
+ }
+ </style>
+ <div id="test-result">test-content</div>
+</section>
+
+<section id="jsRegex">
+ <div class="page-header">
+ <h1>jsRegex <small>com.coverity.security.Escape.jsRegex</small></h1>
+ </div>
+ <ul>
+ <li>Performs JavaScript regex escaping from Java or JSP scriptlet</li>
+ <li>Testcases: GET parameter 'web'</li>
+ </ul>
+ <h3>Code</h3>
+<pre class="prettyprint linenums">
+&lt;script type="text/javascript">
+ var control = 'content';
+ var reg = /^&lt;%= Escape.jsRegex(request.getParameter("web")) %&gt;/;
+ console.log(reg.test(control));
+&lt;/script>
+</pre>
+ <h3>Result</h3>
+ <script type="text/javascript">
+ var control = 'content';
+ var reg = /^<%= Escape.jsRegex(request.getParameter("web")) %>/;
+ console.log(reg.test(control));
+ </script>
+</section>
+
+<section id="uri">
+ <div class="page-header">
+ <h1>uri <small>com.coverity.security.Escape.uri</small></h1>
+ </div>
+ <ul>
+ <li>Performs URI encoding from Java or JSP scriptlet</li>
+ <li>Testcases: GET parameter 'web'</li>
+ </ul>
+ <h3>Code</h3>
+<pre class="prettyprint linenums">
+&lt;a href="/testsuite/el?web=&lt;%= Escape.uri(request.getParameter("web")) %&gt;">web link&lt;/a>
+</pre>
+ <h3>Result</h3>
+ <a href="/testsuite/el?web=<%= Escape.uri(request.getParameter("web")) %>">web link</a>
+</section>
+
+
+<!-- Then, we can add some nested context variations -->
+<section id="nested">
+ <div class="page-header">
+ <h1>Nested contexts <small>HTML double quoted attribute, JavaScript single-quoted string</small></h1>
+ </div>
+ <ul>
+ <li>Uses Escape.jsString and Escape.html</li>
+ <li>Testcases: GET parameter 'web'</li>
+ </ul>
+ <h3>Code</h3>
+<pre class="prettyprint linenums">
+&lt;%
+ String inputNested1 = request.getParameter("web");
+ String hjString1 = Escape.html(Escape.jsString(inputNested1));
+%&gt;
+&lt;img src=. onerror="console.log('&lt;%= hjString1 %&gt;')" /&gt;
+</pre>
+ <h3>Result</h3>
+<%
+String inputNested1 = request.getParameter("web");
+String hjString1 = Escape.html(Escape.jsString(inputNested1));
+%>
+<img src=. onerror="console.log('<%= hjString1 %>')" />
+
+ <div class='well well-small'>
+ Note, here's what the JavaScript engine receives:
+ <code style="background-color:#fff">console.log('<%= hjString1 %>')</code>
+ </div>
+
+</section>
+
+
+<section id="nested">
+ <div class="page-header">
+ <h1>Nested contexts <small>HTML double quoted attribute, CSS single-quoted string (in url())</small></h1>
+ </div>
+ <ul>
+ <li>Uses Escape.cssString and Escape.html</li>
+ <li>Testcases: GET parameter 'web'</li>
+ </ul>
+ <h3>Code</h3>
+<pre class="prettyprint linenums">
+&lt;%
+ String inputNested2 = request.getParameter("web");
+ String chString1 = Escape.html(Escape.cssString(inputNested2));
+%&gt;
+&lt;div style="background-image: url('/404/&lt;%= chString1 %&gt;')">
+ Content
+&lt;/div>
+</pre>
+ <h3>Result</h3>
+<%
+String inputNested2 = request.getParameter("web");
+String chString1 = Escape.html(Escape.cssString(inputNested2));
+%>
+ <div style="background-image: url('/404/<%= chString1 %>')">
+ Content
+ </div>
+
+ <div class='well well-small'>
+ Note, here's what the CSS engine receives:
+ <code style="background-color:#fff">background-image: url('/404/<%= chString1 %>')</code>
+ </div>
+</section>
+
+<section id="nested">
+ <div class="page-header">
+ <h1>Nested contexts <small>JavaScript String, JavaScript regex</small></h1>
+ </div>
+ <ul>
+ <li>Uses Escape.jsRegex and Escape.jsString</li>
+ <li>Testcases: GET parameter 'web'</li>
+ </ul>
+ <h3>Code</h3>
+<pre class="prettyprint linenums">
+&lt;%
+ String inputNested3 = request.getParameter("web");
+ String jjString1 = Escape.jsString(Escape.jsRegex(inputNested3));
+%&gt;
+&lt;script type="text/javascript">
+ var control = 'content';
+ var reg = new RegExp('^(&lt;%= jjString1 %&gt;)?content');
+ console.log(reg.test(control));
+&lt;/script>
+</pre>
+ <h3>Result</h3>
+<%
+String inputNested3 = request.getParameter("web");
+String jjString1 = Escape.jsString(Escape.jsRegex(inputNested3));
+%>
+ <script type="text/javascript">
+ var control = 'content';
+ var reg = new RegExp('^(<%= jjString1 %>)?content');
+ console.log(reg.test(control));
+ </script>
+ <div class='well well-small'>
+ Note, here's what the JS engine receives:
+ <code style="background-color:#fff">var reg = new RegExp('^(<%= Escape.html(jjString1) %>)?content');</code>
+ </div>
+</section>
+
+ </div>
+
+<%@ include file="/WEB-INF/views/includes/footer.jsp" %>
View
33 coverity-escapers/samples/functional-testsuite/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
+
+ <!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
+ <context-param>
+ <param-name>contextConfigLocation</param-name>
+ <param-value>/WEB-INF/spring/root-context.xml</param-value>
+ </context-param>
+
+ <!-- Creates the Spring Container shared by all Servlets and Filters -->
+ <listener>
+ <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
+ </listener>
+
+ <!-- Processes application requests -->
+ <servlet>
+ <servlet-name>appServlet</servlet-name>
+ <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
+ <init-param>
+ <param-name>contextConfigLocation</param-name>
+ <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
+ </init-param>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>appServlet</servlet-name>
+ <url-pattern>/</url-pattern>
+ </servlet-mapping>
+
+</web-app>
View
0 .../samples/java/ExampleJavaHtmlEscaper.java → ...examples/java/ExampleJavaHtmlEscaper.java
File renamed without changes.
View
0 ...s/samples/java/ExampleSQLLikeEscaper.java → ...-examples/java/ExampleSQLLikeEscaper.java
File renamed without changes.
View
2 coverity-escapers/samples/jsp/example_el.jsp → ...amples/mockup-examples/jsp/example_el.jsp
@@ -27,6 +27,8 @@
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<%@ taglib uri="http://coverity.com/security" prefix="cov" %>
+
+<%@ page import="com.coverity.security.Escape" %>
<!--
Sample JSP page that contains some mocked-up CSS, JavaScript,
and HTML. Using EL for most of the data manipulation, and the
View
138 coverity-escapers/src/test/java/com/coverity/security/EscapeTest.java
@@ -24,7 +24,10 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
-package com.coverity.security;
+package com.coverity.testsuite;
+
+import com.coverity.security.Escape;
+import com.coverity.security.EscapeEL;
import junit.framework.Test;
import junit.framework.TestCase;
@@ -33,33 +36,33 @@
// Unit tests for imporant characters
public class EscapeTest extends TestCase {
- public static String[] WEB_NEW_LINES = {
+ public final static String[] WEB_NEW_LINES = {
"\n", "\r", "\f",
"\u2028", "\u2029"
};
- public static String[] WEB_WHITESPACES = {
+ public final static String[] WEB_WHITESPACES = {
" ", "\t"
};
- public static String[] HTML_SENSITIVE_CHARS = {
+ public final static String[] HTML_SENSITIVE_CHARS = {
"<", ">", // HTML tags
"'", "\"", // HTML attributes
" ", "/" // HTML tag/attribute name
};
- public static String[] JS_STRING_SENSITIVE_CHARS = {
+ public final static String[] JS_STRING_SENSITIVE_CHARS = {
"'", "\"", // JavaScript string transition
"<", "/" // Potential HTML </script> transition
};
- public static String[] CSS_STRING_SENSITIVE_CHARS = {
+ public final static String[] CSS_STRING_SENSITIVE_CHARS = {
"'", "\"", // CSS string transition
"<", ">", "&" // Potential HTML </style> transition
};
public EscapeTest(String testName) {
- super( testName );
+ super(testName);
}
public static Test suite() {
@@ -107,25 +110,65 @@ public void testHTMLEscaper_Whitespace() {
public void testHTMLEscaper_String() {
// Assume the string is within any HTML tag, like <div>:
// <div>TAINTED_DATA_HERE</div>
- String beforeEscape = "</div><script src=\"http://example.com/?evil=true&param=xss\">";
- String afterEscape = Escape.html(beforeEscape);
- for (int i=0; i < HTML_SENSITIVE_CHARS.length; i++) {
- String chr = HTML_SENSITIVE_CHARS[i];
- assertTrue(!afterEscape.contains(chr));
+ // or the content of an HTML attibute (not DOM event or CSS style)
+ // <div data-param="TAINTED_DATA_HERE">...
+ String beforeEscape = "</div><script src=\"http://example.com/?evil=true&param=xss\">"
+ + "\\ Foobar & '\"><img src=. onerorr=alert(1) > ";
+ String afterEscape = Escape.html(beforeEscape)
+ + EscapeEL.htmlEscape(beforeEscape);
+
+ String[] badSequences = {
+ "<", ">", "<script", "</div",
+ "\\", "'", " ", "& "
+ };
+
+ for (int i=0; i < badSequences.length; i++) {
+ String badSequence = badSequences[i];
+ assertTrue(!afterEscape.contains(badSequence));
+ }
+ }
+
+ public void testHTMLTextEscaper_String() {
+ // This escaper Escape.htmlText is a relaxed version of the Escape.html
+ // it only escapes ' " < > & and is sufficient when ALWAYS using quoted
+ // attributes.
+ //
+ // Assume the string is within any HTML tag, like <div>:
+ // <div>TAINTED_DATA_HERE</div>
+ // or the content of an HTML attibute (not DOM event or CSS style)
+ // <div data-param="TAINTED_DATA_HERE">...
+ String beforeEscape = "</div><script src=\"http://example.com/?evil=true&param=xss\">"
+ + "Foobar & '\"><img src=. onerorr=alert(1) > ";
+ String afterEscape = Escape.htmlText(beforeEscape)
+ + EscapeEL.htmlText(beforeEscape);
+
+ String[] badSequences = {
+ "<", ">", "<script", "</div",
+ "'", "\"", "& "
+ };
+
+ for (int i=0; i < badSequences.length; i++) {
+ String badSequence = badSequences[i];
+ assertTrue(!afterEscape.contains(badSequence));
}
}
public void testURIEncoder() {
// Assume the string is within an HTML <script> tag, like so:
// <a href="foobar?value=TAINTED_DATA_HERE">
String beforeEscape = "close context'\" break context "
- + "& + : % </script>";
- String afterEscape = Escape.uri(beforeEscape);
+ + "& + : % </script>"
+ + "\t \n \f \r (!#foobar$) *.*=?[@]";
+ String afterEscape = Escape.uri(beforeEscape)
+ + EscapeEL.uriEncode(beforeEscape)
+ + EscapeEL.uriParamEncode(beforeEscape);
+
String[] badSequences = {
"% ",
- "'",
- "\"",
- "+"
+ "'", "\"",
+ "+", "\t", "\n", "\f", "\r",
+ "(", "!", "#", "$", ")", "*", ".", "=", "?",
+ "[", "@", "]"
};
for (int i=0; i < badSequences.length; i++) {
@@ -137,14 +180,19 @@ public void testURIEncoder() {
public void testJSStringEscaper_String() {
// Assume the string is within an HTML <script> tag, like so:
// <script> var = 'TAINTED_DATA_HERE'; </script>
- String beforeEscape = "close context' continue context \\ break context "
- + "\u2029 \u2028 escape HTML context </script>";
- String afterEscape = Escape.jsString(beforeEscape);
+ String beforeEscape = "close context'\" continue context \\ break context "
+ + "\u2029 \u2028 escape HTML context & </script>"
+ + " control chars: \b \t \n \u000b \f";
+ String afterEscape = Escape.jsString(beforeEscape)
+ + EscapeEL.jsStringEscape(beforeEscape);
+
String[] badSequences = {
- "' ",
+ "'",
+ "\"",
" \\ ",
"\u2028",
"\u2029",
+ "&", "\b", "\t", "\n", "\u000b", "\f",
"</script>",
};
@@ -154,16 +202,44 @@ public void testJSStringEscaper_String() {
}
}
+
+ public void testJSRegexEscaper_String() {
+ // Assume the string is within a JavaScript regex:
+ // <script> var b = /^TAINTED_DATA_HERE/.test("foo"); </script>
+ String beforeEscape = "close context / continue context \\ break context "
+ + "\u2029 \u2028 escape HTML context & </script>"
+ + " ( ) [ ] { } * + - . ? ! ^ $ | "
+ + " control chars: \t \n \u000b \f \r ";
+ String afterEscape = Escape.jsRegex(beforeEscape)
+ + EscapeEL.jsRegexEscape(beforeEscape);
+
+ String[] badSequences = {
+ "\t", "\n", "\u000b", "\f", "\r",
+ "</script>", " \\ ", " / ",
+ " ( ", " ) ", " [ ", " ] ", " { ", " } ", " * ",
+ " . ", " + ", " - ", " ? ", " ! ", " ^ ", " $ ",
+ " | "
+ };
+
+ for (int i=0; i < badSequences.length; i++) {
+ String badSequence = badSequences[i];
+ assertTrue(!afterEscape.contains(badSequence));
+ }
+ }
+
public void testCSSStringEscaper_String() {
// Assume the string is within an HTML <style> tag, like so:
// <style> li [id *= 'TAINTED_DATA_HERE'] { ... } </style>
String beforeEscape = "close context' \" continue context \\ break context \n"
- + " escape HTML context </style>";
- String afterEscape = Escape.cssString(beforeEscape);
+ + " escape HTML context </style>"
+ + " control chars: \b \t \n \f \r";
+ String afterEscape = Escape.cssString(beforeEscape)
+ + EscapeEL.cssStringEscape(beforeEscape);
+
String[] badSequences = {
- "' ",
- " \\ ",
- " \n ",
+ "'",
+ "\\ ",
+ "\n", "\r", "\t", "\f", "\r",
"\"",
"</style>",
};
@@ -221,19 +297,25 @@ public void testNestedURLInCSSInHTMLEscaper_String() {
}
public void testForNullInput() {
+ // The test for null inputs is useful to make sure that we do not throw an
+ // exception when receiving an null EL variable (quite common scenario)
try {
Escape.html(null);
+ Escape.htmlText(null);
Escape.jsString(null);
+ Escape.jsRegex(null);
Escape.cssString(null);
Escape.uri(null);
+ Escape.uriParam(null);
+ Escape.sqlLikeClause(null, '\\');
Escape.sqlLikeClause(null);
}
- catch(NullPointerException ex) {
+ catch(Exception ex) {
+ // Test must fail if any exception is thrown
assertTrue(false);
}
}
-
public void testSQLLikeEscaper_String() {
assertTrue(Escape.sqlLikeClause("%_@'+=").equals("@%@_@@'+="));
assertTrue(Escape.sqlLikeClause("%_@'+=\\", '\\').equals("\\%\\_@'+=\\\\"));
View
7 pom.xml
@@ -17,6 +17,13 @@
</license>
</licenses>
+ <!-- https://docs.sonatype.org/display/Repository/Sonatype+OSS+Maven+Repository+Usage+Guide -->
+ <parent>
+ <groupId>org.sonatype.oss</groupId>
+ <artifactId>oss-parent</artifactId>
+ <version>7</version>
+ </parent>
+
<scm>
<connection>scm:git:git@github.com:coverity/coverity-security-library.git</connection>
<developerConnection>scm:git:git@github.com:coverity/coverity-security-library.git</developerConnection>
View
18 test-advisor-policy.json
@@ -0,0 +1,18 @@
+{
+ "type": "Coverity test policy definition for Coverity Security Library",
+ "format_version": 1,
+ "rules" : [{
+ "violation_name" : "security-sanitizer-policy",
+ "minimum_line_coverage_pct" : 100,
+ "aggregation_granularity" : "function",
+ "use_filters" : [
+ "detected-security-sanitizers"
+ ]
+ }],
+ "define_filters" : [{
+ "filter_name" : "detected-security-sanitizers",
+ "function_filters" : [{
+ "func_name_regex" : "com\\.coverity\\.security\\.(.*)"
+ }]
+ }]
+}

0 comments on commit 314cb7f

Please sign in to comment.