Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 49feeb1

Browse files
ahmed-farid-devsmowton
authored andcommitted
Timing attacks while comparing the headers value
1 parent 8b926f6 commit 49feeb1

3 files changed

Lines changed: 101 additions & 0 deletions

File tree

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
2+
<qhelp>
3+
4+
<overview>
5+
<p>
6+
A constant-time algorithm should be used for checking the value of headers.
7+
In other words, the comparison time should not depend on the content of the input.
8+
An attacker may be able to forge the value of the header.
9+
</p>
10+
</overview>
11+
12+
13+
<recommendation>
14+
<p>
15+
Use <code>MessageDigest.isEqual()</code> method to check the value of headers.
16+
If this method is used, then the calculation time depends only on the length of input byte arrays,
17+
and does not depend on the contents of the arrays.
18+
</p>
19+
</recommendation>
20+
<example>
21+
<p>
22+
The following example uses <code>Arrays.equals()</code> method for validating a csrf token .
23+
This method implements a non-constant-time algorithm.
24+
Both the message and the signature come from an untrusted HTTP request:
25+
</p>
26+
<sample src="UnsafecsrfComparison.java" />
27+
</qhelp>
28+
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import java
2+
import semmle.code.java.dataflow.FlowSources
3+
import semmle.code.java.dataflow.TaintTracking
4+
import DataFlow::PathGraph
5+
6+
private class NonConstantTimeEqualsCall extends MethodAccess {
7+
NonConstantTimeEqualsCall() {
8+
this.getMethod().hasQualifiedName("java.lang", "String", ["equals", "contentEquals", "equalsIgnoreCase"]) or
9+
this.getMethod().hasQualifiedName("java.nio", "ByteBuffer", ["equals", "compareTo"])
10+
}
11+
}
12+
13+
private predicate isNonConstantTimeEqualsCall(Expr firstObject, Expr secondObject) {
14+
exists(NonConstantTimeEqualsCall call |
15+
firstObject = call.getQualifier() and
16+
secondObject = call.getAnArgument()
17+
or
18+
firstObject = call.getAnArgument() and
19+
secondObject = call.getQualifier()
20+
)
21+
}
22+
class NonConstantTimeComparisonSink extends DataFlow::Node {
23+
Expr anotherParameter;
24+
NonConstantTimeComparisonSink() {
25+
isNonConstantTimeEqualsCall(this.asExpr(), anotherParameter)
26+
}
27+
}
28+
class ClientSuppliedIpTokenCheck extends DataFlow::Node {
29+
ClientSuppliedIpTokenCheck() {
30+
exists(MethodAccess ma |
31+
ma.getMethod().hasName("getHeader") and
32+
ma.getArgument(0).(CompileTimeConstantExpr).getStringValue().toLowerCase() in [
33+
"x-auth-token", "x-csrf-token", "http_x_csrf_token", "x-csrf-param", "x-csrf-header",
34+
"http_x_csrf_token"
35+
] and
36+
ma = this.asExpr()
37+
)
38+
}
39+
}
40+
41+
class NonConstantTimeComparisonConfig extends TaintTracking::Configuration {
42+
NonConstantTimeComparisonConfig() { this = "NonConstantTimeCryptoComparisonConfig" }
43+
44+
override predicate isSource(DataFlow::Node source) { source instanceof ClientSuppliedIpTokenCheck }
45+
46+
override predicate isSink(DataFlow::Node sink) { sink instanceof NonConstantTimeComparisonSink }
47+
}
48+
49+
from DataFlow::PathNode source, DataFlow::PathNode sink, NonConstantTimeComparisonConfig conf
50+
where conf.hasFlowPath(source, sink)
51+
select sink.getNode(), source, sink, "Possible timing attack against $@ validation.", source,
52+
source.getNode()
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import javax.servlet.http.HttpServletRequest;
2+
import javax.servlet.http.Cookie;
3+
4+
public boolean validateCsrfTokenInRequest(HttpServletRequest request) {
5+
if (cookies != null) {
6+
for (Cookie cookie : cookies) {
7+
if (cookie.getName().equals(CSRF-TOKEN){
8+
csrfCookieValue = cookie.getValue();
9+
}
10+
}
11+
}
12+
if (compareCsrfTokens(csrfCookieValue)) {
13+
return true;
14+
}
15+
}
16+
17+
private boolean compareCsrfTokens(String csrfTokenInCookie) {
18+
if(csrfTokenInCookie == null || !csrfTokenInCookie.equals(request.getHeader("X-CSRF-TOKEN"))) {
19+
return false;
20+
}
21+
}

0 commit comments

Comments
 (0)