Skip to content

Modify rule S5131: Add support for NanoHTTPD (APPSEC-2480) #5145

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/header_names/allowed_framework_names.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
* Jdom2
* JSP
* Legacy Mongo Java API
* NanoHTTPD
* OkHttp
* OpenAI
* Realm
Expand Down
106 changes: 106 additions & 0 deletions rules/S5131/java/how-to-fix-it/nanohttpd.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
== How to fix it in a NanoHTTPD

=== Code examples

The following code is vulnerable to cross-site scripting because it returns an HTML response that contains user input.

Third-party data, such as user input, is not to be trusted. If embedded in HTML code, it should be HTML-encoded to prevent the injection of additional code.
This can be done with the https://owasp.org/www-project-java-encoder/[OWASP Java Encoder] or similar libraries.

==== Noncompliant code example

[source,java,diff-id=41,diff-type=noncompliant]
----
import fi.iki.elonen.NanoHTTPD;

public class App extends NanoHTTPD {

@Override
public Response serve(IHTTPSession session) {
String name = session.getParms().get("input");
return newFixedLengthResponse( // Noncompliant
"<html><body><h1> Hello, " + name + "!</h1></body></html>"
);
}
}
----

==== Compliant solution

[source,java,diff-id=41,diff-type=compliant]
----
import fi.iki.elonen.NanoHTTPD;
import org.owasp.encoder.Encode;

public class App extends NanoHTTPD {

@Override
public Response serve(IHTTPSession session) {
String name = session.getParms().get("input");
return newFixedLengthResponse(
"<html><body><h1> Hello, " + Encode.forHtml(name) + "!</h1></body></html>"
);
}
}
----

If you do not intend to send HTML code to clients, the vulnerability can be fixed by specifying the type of data returned in the response with the Content-Type header.

For example, setting the Content-Type to `text/plain` allows to safely reflect user input.
In this case, browsers will not try to parse and execute the response.

==== Noncompliant code example

[source,java,diff-id=42,diff-type=noncompliant]
----
import fi.iki.elonen.NanoHTTPD;

public class App extends NanoHTTPD {

@Override
public Response serve(IHTTPSession session) {
String name = session.getParms().get("input");
return newFixedLengthResponse( // Noncompliant - text/html by default
"Hello, " + name + "!"
);
}
}
----

==== Compliant solution

[source,java,diff-id=42,diff-type=compliant]
----
import fi.iki.elonen.NanoHTTPD;
import fi.iki.elonen.NanoHTTPD.Response.Status;

public class App extends NanoHTTPD {

@Override
public Response serve(IHTTPSession session) {
String name = session.getParms().get("input");
return newFixedLengthResponse(
Status.OK,
"text/plain",
"Hello, " + name + "!"
);
}
}
----

=== How does this work?

include::../../common/fix/data_encoding.adoc[]

`org.owasp.encoder.Encode.forHtml` is the recommended method to encode HTML entities.

=== Pitfalls

include::../../common/pitfalls/content-types.adoc[]

include::../../common/pitfalls/validation.adoc[]

=== Going the extra mile

include::../../common/extra-mile/csp.adoc[]

2 changes: 2 additions & 0 deletions rules/S5131/java/rule.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ include::how-to-fix-it/spring.adoc[]

include::how-to-fix-it/thymeleaf.adoc[]

include::how-to-fix-it/nanohttpd.adoc[]

== Resources

include::../common/resources/docs.adoc[]
Expand Down
106 changes: 106 additions & 0 deletions rules/S5131/kotlin/how-to-fix-it/nanohttpd.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
== How to fix it in a NanoHTTPD

=== Code examples

The following code is vulnerable to cross-site scripting because it returns an HTML response that contains user input.

Third-party data, such as user input, is not to be trusted. If embedded in HTML code, it should be HTML-encoded to prevent the injection of additional code.
This can be done with the https://owasp.org/www-project-java-encoder/[OWASP Java Encoder] or similar libraries.

==== Noncompliant code example

[source,kotlin,diff-id=41,diff-type=noncompliant]
----
import fi.iki.elonen.NanoHTTPD

class App : NanoHTTPD() {

@Override
fun serve(session: IHTTPSession): Response {
val name = session.getParms().get("input");
return newFixedLengthResponse( // Noncompliant
"<html><body><h1> Hello, $name!</h1></body></html>"
);
}
}
----

==== Compliant solution

[source,kotlin,diff-id=41,diff-type=compliant]
----
import fi.iki.elonen.NanoHTTPD
import org.owasp.encoder.Encode

class App : NanoHTTPD() {

@Override
fun serve(session: IHTTPSession): Response {
val name = session.getParms().get("input");
return newFixedLengthResponse(
"<html><body><h1> Hello, ${Encode.forHtml(name)}!</h1></body></html>"
);
}
}
----

If you do not intend to send HTML code to clients, the vulnerability can be fixed by specifying the type of data returned in the response with the Content-Type header.

For example, setting the Content-Type to `text/plain` allows to safely reflect user input.
In this case, browsers will not try to parse and execute the response.

==== Noncompliant code example

[source,kotlin,diff-id=42,diff-type=noncompliant]
----
import fi.iki.elonen.NanoHTTPD

class App : NanoHTTPD() {

@Override
fun serve(session: IHTTPSession): Response {
val name = session.getParms().get("input");
return newFixedLengthResponse( // Noncompliant - text/html by default
"Hello, $name!"
);
}
}
----

==== Compliant solution

[source,kotlin,diff-id=42,diff-type=compliant]
----
import fi.iki.elonen.NanoHTTPD
import fi.iki.elonen.NanoHTTPD.Response.Status

class App : NanoHTTPD() {

@Override
fun serve(session: IHTTPSession): Response {
val name = session.getParms().get("input");
return newFixedLengthResponse(
Status.OK,
"text/plain",
"Hello, $name!"
);
}
}
----

=== How does this work?

include::../../common/fix/data_encoding.adoc[]

`org.owasp.encoder.Encode.forHtml` is the recommended method to encode HTML entities.

=== Pitfalls

include::../../common/pitfalls/content-types.adoc[]

include::../../common/pitfalls/validation.adoc[]

=== Going the extra mile

include::../../common/extra-mile/csp.adoc[]

2 changes: 2 additions & 0 deletions rules/S5131/kotlin/rule.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ include::how-to-fix-it/servlet.adoc[]

include::how-to-fix-it/spring.adoc[]

include::how-to-fix-it/nanohttpd.adoc[]

== Resources

include::../common/resources/docs.adoc[]
Expand Down