Skip to content

Commit 24280f5

Browse files
committed
xss: csl module fix jooby-project#475
1 parent fcfa124 commit 24280f5

10 files changed

Lines changed: 336 additions & 15 deletions

File tree

coverage-report/pom.xml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
<source>${project.parent.basedir}/jooby-couchbase/src/main/java</source>
8383
<source>${project.parent.basedir}/jooby-cassandra/src/main/java</source>
8484
<source>${project.parent.basedir}/jooby-scanner/src/main/java</source>
85+
<source>${project.parent.basedir}/jooby-csl/src/main/java</source>
8586
</sources>
8687
</configuration>
8788
</execution>
@@ -139,6 +140,7 @@
139140
<source>${project.parent.basedir}/jooby-couchbase/src/test/java</source>
140141
<source>${project.parent.basedir}/jooby-cassandra/src/test/java</source>
141142
<source>${project.parent.basedir}/jooby-scanner/src/test/java</source>
143+
<source>${project.parent.basedir}/jooby-csl/src/test/java</source>
142144
</sources>
143145
</configuration>
144146
</execution>
@@ -216,7 +218,8 @@
216218
<include>**/*Feature.java</include>
217219
<include>**/*Issue*.java</include>
218220
</includes>
219-
<argLine>-Xmx1024m -XX:MaxPermSize=256m -Xbootclasspath/p:${settings.localRepository}/org/mortbay/jetty/alpn/alpn-boot/${alpn-boot.version}/alpn-boot-${alpn-boot.version}.jar</argLine>
221+
<argLine>-Xmx1024m -XX:MaxPermSize=256m
222+
-Xbootclasspath/p:${settings.localRepository}/org/mortbay/jetty/alpn/alpn-boot/${alpn-boot.version}/alpn-boot-${alpn-boot.version}.jar</argLine>
220223
<systemPropertyVariables>
221224
<!-- JaCoCo runtime must know where to dump coverage: -->
222225
<jacoco-agent.destfile>target${file.separator}jacoco.exec</jacoco-agent.destfile>
@@ -410,6 +413,12 @@
410413
<version>${project.version}</version>
411414
</dependency>
412415

416+
<dependency>
417+
<groupId>org.jooby</groupId>
418+
<artifactId>jooby-csl</artifactId>
419+
<version>${project.version}</version>
420+
</dependency>
421+
413422
<!-- H2 database -->
414423
<dependency>
415424
<groupId>com.h2database</groupId>
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package org.jooby.issues;
2+
3+
import org.jooby.test.ServerFeature;
4+
import org.jooby.xss.XSS;
5+
import org.junit.Test;
6+
7+
public class Issue475 extends ServerFeature {
8+
9+
{
10+
use(new XSS());
11+
12+
get("/475/text", req -> {
13+
return req.param("text", "html").value();
14+
});
15+
16+
get("/475/js", req -> {
17+
return req.param("text", "js").value();
18+
});
19+
}
20+
21+
@Test
22+
public void escapeHtml() throws Exception {
23+
request()
24+
.get("/475/text?text=%3Ch1%3EX%3C/h1%3E")
25+
.expect("&lt;h1&gt;X&lt;&#x2F;h1&gt;");
26+
}
27+
28+
@Test
29+
public void escapeJs() throws Exception {
30+
request()
31+
.get("/475/js?text=%3Cscript%3Ealert(%27xss%27)%3C/script%3E")
32+
.expect("\\u003Cscript\\u003Ealert(\\u0027xss\\u0027)\\u003C\\u002Fscript\\u003E");
33+
}
34+
35+
}

jooby-csl/pom.xml

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
4+
5+
<parent>
6+
<groupId>org.jooby</groupId>
7+
<artifactId>jooby-project</artifactId>
8+
<version>1.0.0.Final</version>
9+
</parent>
10+
11+
<modelVersion>4.0.0</modelVersion>
12+
<artifactId>jooby-csl</artifactId>
13+
14+
<name>xss-csl module</name>
15+
16+
<build>
17+
<plugins>
18+
<!-- sure-fire -->
19+
<plugin>
20+
<groupId>org.apache.maven.plugins</groupId>
21+
<artifactId>maven-surefire-plugin</artifactId>
22+
<configuration>
23+
<includes>
24+
<include>**/*Test.java</include>
25+
<include>**/*Feature.java</include>
26+
<include>**/Issue*.java</include>
27+
</includes>
28+
</configuration>
29+
</plugin>
30+
31+
</plugins>
32+
</build>
33+
34+
<dependencies>
35+
<!-- Jooby -->
36+
<dependency>
37+
<groupId>org.jooby</groupId>
38+
<artifactId>jooby</artifactId>
39+
</dependency>
40+
41+
<dependency>
42+
<groupId>com.coverity.security</groupId>
43+
<artifactId>coverity-escapers</artifactId>
44+
</dependency>
45+
46+
<!-- Test dependencies -->
47+
<dependency>
48+
<groupId>org.jooby</groupId>
49+
<artifactId>jooby</artifactId>
50+
<version>${project.version}</version>
51+
<scope>test</scope>
52+
<classifier>tests</classifier>
53+
</dependency>
54+
55+
<dependency>
56+
<groupId>org.jooby</groupId>
57+
<artifactId>jooby-netty</artifactId>
58+
<version>${project.version}</version>
59+
<scope>test</scope>
60+
</dependency>
61+
62+
<dependency>
63+
<groupId>org.jooby</groupId>
64+
<artifactId>jooby-jackson</artifactId>
65+
<version>${project.version}</version>
66+
<scope>test</scope>
67+
</dependency>
68+
69+
<dependency>
70+
<groupId>junit</groupId>
71+
<artifactId>junit</artifactId>
72+
<scope>test</scope>
73+
</dependency>
74+
75+
<dependency>
76+
<groupId>org.easymock</groupId>
77+
<artifactId>easymock</artifactId>
78+
<scope>test</scope>
79+
</dependency>
80+
81+
<dependency>
82+
<groupId>org.powermock</groupId>
83+
<artifactId>powermock-api-easymock</artifactId>
84+
<scope>test</scope>
85+
</dependency>
86+
87+
<dependency>
88+
<groupId>org.powermock</groupId>
89+
<artifactId>powermock-module-junit4</artifactId>
90+
<scope>test</scope>
91+
</dependency>
92+
93+
<dependency>
94+
<groupId>org.jacoco</groupId>
95+
<artifactId>org.jacoco.agent</artifactId>
96+
<classifier>runtime</classifier>
97+
<scope>test</scope>
98+
</dependency>
99+
100+
</dependencies>
101+
102+
</project>
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package org.jooby.xss;
2+
3+
import org.jooby.Env;
4+
import org.jooby.Jooby.Module;
5+
6+
import com.coverity.security.Escape;
7+
import com.google.inject.Binder;
8+
import com.typesafe.config.Config;
9+
10+
/**
11+
* <h1>xss</h1>
12+
* <p>
13+
* Lightweight set of escaping routines for fixing cross-site scripting (XSS) via
14+
* <a href="https://github.com/coverity/coverity-security-library">coverity-security-library</a>
15+
* </p>
16+
*
17+
* <h2>exports</h2>
18+
* <ul>
19+
* <li><strong>html</strong> escaper: HTML entity escaping for text content and attributes.</li>
20+
* <li><strong>htmlText</strong> escaper: Faster HTML entity escaping for tag content or quoted
21+
* attributes values only.</li>
22+
* <li><strong>js</strong> escaper: JavaScript String Unicode escaper.</li>
23+
* <li><strong>jsRegex</strong> escaper: JavaScript regex content escaper.</li>
24+
* <li><strong>css</strong> escaper: CSS String escaper.</li>
25+
* <li><strong>uri</strong> escaper: URI encoder.</li>
26+
* </ul>
27+
*
28+
* <h2>usage</h2>
29+
* <pre>{@code
30+
* {
31+
* use(new XSS());
32+
*
33+
* post("/", req -> {
34+
* String safeHtml = req.param("text", "html").value();
35+
* });
36+
* }
37+
* }</pre>
38+
*
39+
* <p>
40+
* Nested context are supported by providing multiple encoders:
41+
* </p>
42+
*
43+
* <pre>{@code
44+
* {
45+
* use(new XSS());
46+
*
47+
* post("/", req -> {
48+
* String safeHtml = req.param("text", "js", "html", "uri").value();
49+
* });
50+
* }
51+
* }</pre>
52+
*
53+
* <p>
54+
* Encoders run in the order they are provided.
55+
* </p>
56+
* <p>
57+
* If you want to learn more about nested context and why they are important have a look at this
58+
* <a href=
59+
* "http://security.coverity.com/document/2013/Mar/fixing-xss-a-practical-guide-for-developers.html">nice
60+
* guide</code> from
61+
* <a href="https://github.com/coverity/coverity-security-library">coverity-security-library</a>.
62+
* </p>
63+
*
64+
* @author edgar
65+
* @since 1.0.0
66+
*/
67+
public class XSS implements Module {
68+
69+
@Override
70+
public void configure(final Env env, final Config conf, final Binder binder) {
71+
// contribute CSL escape functions
72+
env.xss("html", Escape::html)
73+
.xss("htmlText", Escape::htmlText)
74+
.xss("js", Escape::jsString)
75+
.xss("jsRegex", Escape::jsRegex)
76+
.xss("css", Escape::cssString)
77+
.xss("uri", Escape::uri);
78+
}
79+
80+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package csl;
2+
3+
import org.jooby.Jooby;
4+
import org.jooby.xss.XSS;
5+
6+
public class XssApp extends Jooby {
7+
8+
{
9+
use(new XSS());
10+
11+
get("/param", req -> "<html><body><a href=>" + req.param("p", "html").value() + "</html></body>");
12+
13+
get("/h", req -> "<html><body>" + req.header("h", "html").value("<h1>X</h1>") + "</html></body>");
14+
15+
get("*", req -> req.path(true));
16+
17+
}
18+
19+
public static void main(final String[] args) {
20+
run(XssApp::new, args);
21+
}
22+
}

jooby-scanner/pom.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@
4141
<dependency>
4242
<groupId>io.github.lukehutch</groupId>
4343
<artifactId>fast-classpath-scanner</artifactId>
44-
<version>1.99.0</version>
4544
</dependency>
4645

4746
<!-- Test dependencies -->

md/cors.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@ Cross-origin resource sharing (CORS) is a mechanism that allows restricted resou
77

88
```java
99
{
10-
1110
use("*", new CorsHandler());
12-
1311
}
1412
```
1513

md/doc/csl/csl.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# xss
2+
3+
Lightweight set of escaping routines for fixing cross-site scripting (XSS) via <a href="https://github.com/coverity/coverity-security-library">coverity-security-library</a>
4+
5+
## dependency
6+
7+
```xml
8+
<dependency>
9+
<groupId>org.jooby</groupId>
10+
<artifactId>jooby-xss</artifactId>
11+
<version>{{version}}</version>
12+
</dependency>
13+
```
14+
15+
## exports
16+
17+
* **html** escaper: HTML entity escaping for text content and attributes.
18+
* **htmlText** escaper: Faster HTML entity escaping for tag content or quoted attributes values only.
19+
* **js** escaper: JavaScript String Unicode escaper.
20+
* **jsRegex** escaper: JavaScript regex content escaper.
21+
* **css** escaper: CSS String escaper.
22+
* **uri** escaper: URI encoder.
23+
24+
## usage
25+
26+
```java
27+
{
28+
use(new XSS());
29+
30+
post("/", req -> {
31+
32+
String safeHtml = req.param("text", "html").value();
33+
});
34+
35+
}
36+
```
37+
38+
Nested context are supported by providing multiple encoders:
39+
40+
```java
41+
{
42+
use(new XSS());
43+
44+
post("/", req -> {
45+
46+
String safeHtml = req.param("text", "js", "html", "uri").value();
47+
});
48+
49+
}
50+
```
51+
52+
Encoders run in the order they are provided.
53+
54+
If you want to learn more about nested context and why they are important have a look at this <a href="http://security.coverity.com/document/2013/Mar/fixing-xss-a-practical-guide-for-developers.html">nice guide from </a><a href="https://github.com/coverity/coverity-security-library">coverity-security-library</a>.

md/doc/index.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ documentation
4848

4949
{{cors.md}}
5050

51-
{{javascript.md}}
52-
5351
{{https.md}}
5452

53+
{{javascript.md}}
54+
5555
{{appendix}}

0 commit comments

Comments
 (0)