Skip to content

Commit 6bc9624

Browse files
authored
Merge pull request github#3236 from luchua-bc/java-improper-url-validation
Java: Improper url validation
2 parents 5fb76df + 2a654af commit 6bc9624

File tree

3 files changed

+142
-0
lines changed

3 files changed

+142
-0
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
public boolean shouldOverrideUrlLoading(WebView view, String url) {
2+
{
3+
Uri uri = Uri.parse(url);
4+
// BAD: partial domain match, which allows an attacker to register a domain like myexample.com to circumvent the verification
5+
if (uri.getHost() != null && uri.getHost().endsWith("example.com")) {
6+
return false;
7+
}
8+
}
9+
10+
{
11+
Uri uri = Uri.parse(url);
12+
// GOOD: full domain match
13+
if (uri.getHost() != null && uri.getHost().endsWith(".example.com")) {
14+
return false;
15+
}
16+
}
17+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
6+
<overview>
7+
<p>Apps that rely on URL Parsing to verify that a given URL is pointing to a trust server may be susceptible to many different ways to get URL parsing and verification wrong, which allows an attacker to register a fake site to break the access control.</p>
8+
</overview>
9+
10+
<recommendation>
11+
<p>Verify the whole host and domain (FQDN) or check endsWith dot+domain.</p>
12+
</recommendation>
13+
14+
<example>
15+
<p>The following example shows two ways of verifying host domain. In the 'BAD' case,
16+
verification is implemented as partial domain match. In the 'GOOD' case, full domain is verified.</p>
17+
<sample src="IncorrectURLVerification.java" />
18+
</example>
19+
20+
<references>
21+
<li>
22+
<a href="https://drive.google.com/file/d/0BwMN49Gzo3x6T1N5WGQ4TTNlMHBOb1ZRQTVEWnVBZjFUaE5N/view">Common Android app vulnerabilities from Sebastian Porst of Google</a>
23+
</li>
24+
<li>
25+
<a href="https://www.bugcrowd.com/resources/webinars/overview-of-common-android-app-vulnerabilities/">Common Android app vulnerabilities from bugcrowd</a>
26+
</li>
27+
</references>
28+
</qhelp>
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/**
2+
* @id java/incorrect-url-verification
3+
* @name Incorrect URL verification
4+
* @description Apps that rely on URL parsing to verify that a given URL is pointing to a trusted server are susceptible to wrong ways of URL parsing and verification.
5+
* @kind problem
6+
* @tags security
7+
* external/cwe-939
8+
*/
9+
10+
import java
11+
12+
/**
13+
* The Java class `android.R.string` specific to Android applications, which contains references to application specific resources defined in /res/values/strings.xml.
14+
* For example, <resources>...<string name="host">example.com</string>...</resources> in the application com.example.android.web can be referred as R.string.host with the type com.example.android.web.R$string
15+
*/
16+
class AndroidRString extends RefType {
17+
AndroidRString() { this.hasQualifiedName(_, "R$string") }
18+
}
19+
20+
/**
21+
* The Java class `android.net.Uri` and `java.net.URL`.
22+
*/
23+
class Uri extends RefType {
24+
Uri() {
25+
hasQualifiedName("android.net", "Uri") or
26+
hasQualifiedName("java.net", "URL")
27+
}
28+
}
29+
30+
/**
31+
* The method `getHost()` declared in `android.net.Uri` and `java.net.URL`.
32+
*/
33+
class UriGetHostMethod extends Method {
34+
UriGetHostMethod() {
35+
getDeclaringType() instanceof Uri and
36+
hasName("getHost") and
37+
getNumberOfParameters() = 0
38+
}
39+
}
40+
41+
/**
42+
* The method access with incorrect string comparision
43+
*/
44+
class HostVerificationMethodAccess extends MethodAccess {
45+
HostVerificationMethodAccess() {
46+
(
47+
this.getMethod().hasName("endsWith") or
48+
this.getMethod().hasName("contains") or
49+
this.getMethod().hasName("indexOf")
50+
) and
51+
this.getMethod().getNumberOfParameters() = 1 and
52+
(
53+
this.getArgument(0).(StringLiteral).getRepresentedString().charAt(0) != "." //string constant comparison e.g. uri.getHost().endsWith("example.com")
54+
or
55+
this
56+
.getArgument(0)
57+
.(AddExpr)
58+
.getLeftOperand()
59+
.(VarAccess)
60+
.getVariable()
61+
.getAnAssignedValue()
62+
.(StringLiteral)
63+
.getRepresentedString()
64+
.charAt(0) != "." //var1+var2, check var1 starts with "." e.g. String domainName = "example"; Uri.parse(url).getHost().endsWith(domainName+".com")
65+
or
66+
this
67+
.getArgument(0)
68+
.(AddExpr)
69+
.getLeftOperand()
70+
.(StringLiteral)
71+
.getRepresentedString()
72+
.charAt(0) != "." //"."+var2, check string constant "." e.g. String domainName = "example.com"; Uri.parse(url).getHost().endsWith("www."+domainName)
73+
or
74+
exists(MethodAccess ma, Method m, Field f |
75+
this.getArgument(0) = ma and
76+
ma.getMethod() = m and
77+
m.hasName("getString") and
78+
m.getDeclaringType().getQualifiedName() = "android.content.res.Resources" and
79+
ma.getArgument(0).(FieldRead).getField() = f and
80+
f.getDeclaringType() instanceof AndroidRString
81+
) //Check resource properties in /res/values/strings.xml in Android mobile applications using res.getString(R.string.key)
82+
or
83+
this
84+
.getArgument(0)
85+
.(VarAccess)
86+
.getVariable()
87+
.getAnAssignedValue()
88+
.(StringLiteral)
89+
.getRepresentedString()
90+
.charAt(0) != "." //check variable starts with "." e.g. String domainName = "example.com"; Uri.parse(url).getHost().endsWith(domainName)
91+
)
92+
}
93+
}
94+
95+
from UriGetHostMethod um, MethodAccess uma, HostVerificationMethodAccess hma
96+
where hma.getQualifier() = uma and uma.getMethod() = um
97+
select hma, "Method has potentially $@ ", hma.getArgument(0), "improper URL verification"

0 commit comments

Comments
 (0)