Skip to content

Commit 3a23451

Browse files
committed
Enhance the query
1 parent 01fb518 commit 3a23451

File tree

8 files changed

+210
-41
lines changed

8 files changed

+210
-41
lines changed

java/ql/src/experimental/Security/CWE/CWE-522/UnsecureBasicAuth.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
public class UnsecureBasicAuth {
22
/**
3-
*Test basic authentication with Apache HTTP request.
3+
* Test basic authentication with Apache HTTP request.
44
*/
55
public void testApacheHttpRequest(String username, String password) {
66
{
7-
// BAD: Use HTTP with basic authentication
7+
// BAD: basic authentication over HTTP
88
String url = "http://www.example.com/rest/getuser.do?uid=abcdx";
99
}
1010

1111
{
12-
// GOOD: Use HTTPS with basic authentication
12+
// GOOD: basic authentication over HTTPS
1313
String url = "https://www.example.com/rest/getuser.do?uid=abcdx";
1414
}
1515

@@ -29,12 +29,12 @@ public void testApacheHttpRequest(String username, String password) {
2929
*/
3030
public void testHttpUrlConnection(String username, String password) {
3131
{
32-
// BAD: Use HTTP with basic authentication
32+
// BAD: basic authentication over HTTP
3333
String urlStr = "http://www.example.com/rest/getuser.do?uid=abcdx";
3434
}
3535

3636
{
37-
// GOOD: Use HTTPS with basic authentication
37+
// GOOD: basic authentication over HTTPS
3838
String urlStr = "https://www.example.com/rest/getuser.do?uid=abcdx";
3939
}
4040

java/ql/src/experimental/Security/CWE/CWE-522/UnsecureBasicAuth.qhelp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,20 @@
1010
</recommendation>
1111

1212
<example>
13-
<p>The following example shows two ways of using basic authentication. In the 'BAD' case,
14-
the credentials are transmitted over HTTP. In the 'GOOD' case, the credentials are transmitted over HTTPS.</p>
13+
<p>The following example shows two ways of using basic authentication. In the 'BAD' case, the credentials are transmitted over HTTP. In the 'GOOD' case, the credentials are transmitted over HTTPS.</p>
1514
<sample src="UnsecureBasicAuth.java" />
1615
</example>
1716

1817
<references>
1918
<li>
2019
<a href="https://cwe.mitre.org/data/definitions/522">CWE-522</a>
20+
</li>
21+
<li>
22+
SonarSource rule:
2123
<a href="https://rules.sonarsource.com/java/tag/owasp/RSPEC-2647">Basic authentication should not be used</a>
24+
</li>
25+
<li>
26+
Acunetix:
2227
<a href="https://www.acunetix.com/vulnerabilities/web/basic-authentication-over-http/">WEB VULNERABILITIES INDEX - Basic authentication over HTTP</a>
2328
</li>
2429
</references>

java/ql/src/experimental/Security/CWE/CWE-522/UnsecureBasicAuth.ql

Lines changed: 43 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
22
* @name Unsecure basic authentication
3-
* @description Basic authentication only obfuscates username/password in Base64 encoding, which can be easily recognized and reversed. Transmission of sensitive information not in HTTPS is vulnerable to packet sniffing.
3+
* @description Basic authentication only obfuscates username/password in Base64 encoding, which can be easily recognized and reversed. Transmission of sensitive information not over HTTPS is vulnerable to packet sniffing.
44
* @kind problem
55
* @id java/unsecure-basic-auth
66
* @tags security
@@ -14,23 +14,27 @@ import semmle.code.java.dataflow.TaintTracking
1414
import DataFlow::PathGraph
1515

1616
/**
17-
* The Java class `org.apache.http.message.AbstractHttpMessage`. Popular subclasses include `HttpGet`, `HttpPost`, and `HttpPut`.
17+
* The Java class `org.apache.http.client.methods.HttpRequestBase`. Popular subclasses include `HttpGet`, `HttpPost`, and `HttpPut`.
18+
* And the Java class `org.apache.http.message.BasicHttpRequest`.
1819
*/
1920
class ApacheHttpRequest extends RefType {
20-
ApacheHttpRequest() { hasQualifiedName("org.apache.http.message", "AbstractHttpMessage") }
21+
ApacheHttpRequest() {
22+
hasQualifiedName("org.apache.http.client.methods", "HttpRequestBase") or
23+
hasQualifiedName("org.apache.http.message", "BasicHttpRequest")
24+
}
2125
}
2226

2327
/**
24-
* Class of Java URL constructor
28+
* Class of Java URL constructor.
2529
*/
2630
class URLConstructor extends ClassInstanceExpr {
2731
URLConstructor() { this.getConstructor().getDeclaringType() instanceof TypeUrl }
2832

2933
Expr stringArg() {
30-
// Query only in URL's that were constructed by calling the single parameter string constructor.
31-
this.getConstructor().getNumberOfParameters() = 1 and
34+
// URLs constructed with any of the four string constructors below:
35+
// URL(String spec), URL(String protocol, String host, int port, String file), URL(String protocol, String host, int port, String file, URLStreamHandler handler), URL(String protocol, String host, String file)
3236
this.getConstructor().getParameter(0).getType() instanceof TypeString and
33-
result = this.getArgument(0)
37+
result = this.getArgument(0) // First argument contains the protocol part.
3438
}
3539
}
3640

@@ -42,12 +46,14 @@ class TypeHttpUrlConnection extends RefType {
4246
}
4347

4448
/**
45-
* String of HTTP URLs not in private domains
49+
* String of HTTP URLs not in private domains.
4650
*/
4751
class HttpString extends StringLiteral {
4852
HttpString() {
4953
// Match URLs with the HTTP protocol and without private IP addresses to reduce false positives.
5054
exists(string s | this.getRepresentedString() = s |
55+
s = "http"
56+
or
5157
s.matches("http://%") and
5258
not s.matches("%/localhost%") and
5359
not s.matches("%/127.0.0.1%") and
@@ -59,21 +65,36 @@ class HttpString extends StringLiteral {
5965
}
6066

6167
/**
62-
* String concatenated with `HttpString`
68+
* String concatenated with `HttpString`.
6369
*/
6470
predicate builtFromHttpStringConcat(Expr expr) {
6571
expr instanceof HttpString
6672
or
67-
exists(AddExpr concatExpr | concatExpr = expr |
68-
builtFromHttpStringConcat(concatExpr.getLeftOperand())
69-
)
73+
builtFromHttpStringConcat(expr.(AddExpr).getLeftOperand())
7074
or
71-
exists(AddExpr concatExpr | concatExpr = expr |
72-
exists(Expr arg | arg = concatExpr.getLeftOperand() | arg instanceof HttpString)
75+
exists(Expr other | builtFromHttpStringConcat(other) |
76+
exists(Variable var | var.getAnAssignedValue() = other and var.getAnAccess() = expr)
7377
)
7478
or
7579
exists(Expr other | builtFromHttpStringConcat(other) |
76-
exists(Variable var | var.getAnAssignedValue() = other and var.getAnAccess() = expr)
80+
exists(ConstructorCall cc |
81+
(
82+
cc.getConstructedType().hasQualifiedName("org.apache.http.message", "BasicRequestLine") and
83+
cc.getArgument(1) = other // BasicRequestLine(String method, String uri, ProtocolVersion version)
84+
or
85+
cc.getConstructedType().hasQualifiedName("java.net", "URI") and
86+
cc.getArgument(0) = other // URI(String str) or URI(String scheme, ...)
87+
) and
88+
(
89+
cc = expr
90+
or
91+
exists(Variable var, VariableAssign va |
92+
var.getAnAccess() = expr and
93+
va.getDestVar() = var and
94+
va.getSource() = cc
95+
)
96+
)
97+
)
7798
)
7899
}
79100

@@ -100,11 +121,11 @@ class AddBasicAuthHeaderMethodAccess extends MethodAccess {
100121
)
101122
) and
102123
exists(VarAccess request, VariableAssign va, ConstructorCall cc, Expr arg0 |
103-
this.getQualifier() = request and //Check the method invocation with the pattern post.addHeader("Authorization", "Basic " + authStringEnc)
124+
this.getQualifier() = request and // Constructor call like HttpPost post = new HttpPost("http://www.example.com/rest/endpoint.do"); and BasicHttpRequest post = new BasicHttpRequest("POST", uriStr);
104125
va.getDestVar() = request.getVariable() and
105126
va.getSource() = cc and
106-
cc.getArgument(0) = arg0 and
107-
builtFromHttpStringConcat(arg0) // Check url string
127+
cc.getAnArgument() = arg0 and
128+
builtFromHttpStringConcat(arg0)
108129
)
109130
}
110131
}
@@ -118,7 +139,7 @@ class HttpURLOpenMethod extends Method {
118139
}
119140

120141
/**
121-
* Tracks the flow of data from parameter of URL constructor to the url instance
142+
* Tracks the flow of data from parameter of URL constructor to the url instance.
122143
*/
123144
class URLConstructorTaintStep extends TaintTracking::AdditionalTaintStep {
124145
override predicate step(DataFlow::Node node1, DataFlow::Node node2) {
@@ -130,7 +151,7 @@ class URLConstructorTaintStep extends TaintTracking::AdditionalTaintStep {
130151
}
131152

132153
/**
133-
* Tracks the flow of data from `openConnection` method to the connection object
154+
* Tracks the flow of data from `openConnection` method to the connection object.
134155
*/
135156
class OpenHttpURLTaintStep extends TaintTracking::AdditionalTaintStep {
136157
override predicate step(DataFlow::Node node1, DataFlow::Node node2) {
@@ -160,7 +181,7 @@ class HttpStringToHttpURLOpenMethodFlowConfig extends TaintTracking::Configurati
160181

161182
override predicate isSink(DataFlow::Node sink) {
162183
sink.asExpr().(VarAccess).getVariable().getType() instanceof TypeUrlConnection or
163-
sink.asExpr().(VarAccess).getVariable().getType() instanceof TypeHttpUrlConnection // Somehow TypeHttpUrlConnection isn't instance of TypeUrlConnection
184+
sink.asExpr().(VarAccess).getVariable().getType() instanceof TypeHttpUrlConnection // TypeHttpUrlConnection isn't instance of TypeUrlConnection
164185
}
165186

166187
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
@@ -210,4 +231,4 @@ from MethodAccess ma
210231
where
211232
ma instanceof AddBasicAuthHeaderMethodAccess or
212233
ma instanceof SetBasicAuthPropertyMethodAccess
213-
select ma, "Unsafe basic authentication"
234+
select ma, "Insecure basic authentication"
Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
edges
2-
| UnsecureBasicAuth.java:41:19:41:68 | "http://www.example.com/rest/getuser.do?uid=abcdx" : String | UnsecureBasicAuth.java:46:3:46:6 | conn |
3-
| UnsecureBasicAuth.java:41:19:41:68 | "http://www.example.com/rest/getuser.do?uid=abcdx" : String | UnsecureBasicAuth.java:47:3:47:6 | conn |
4-
| UnsecureBasicAuth.java:41:19:41:68 | "http://www.example.com/rest/getuser.do?uid=abcdx" : String | UnsecureBasicAuth.java:48:3:48:6 | conn |
2+
| UnsecureBasicAuth.java:94:19:94:68 | "http://www.example.com/rest/getuser.do?uid=abcdx" : String | UnsecureBasicAuth.java:99:3:99:6 | conn |
3+
| UnsecureBasicAuth.java:94:19:94:68 | "http://www.example.com/rest/getuser.do?uid=abcdx" : String | UnsecureBasicAuth.java:100:3:100:6 | conn |
4+
| UnsecureBasicAuth.java:94:19:94:68 | "http://www.example.com/rest/getuser.do?uid=abcdx" : String | UnsecureBasicAuth.java:101:3:101:6 | conn |
55
nodes
6-
| UnsecureBasicAuth.java:41:19:41:68 | "http://www.example.com/rest/getuser.do?uid=abcdx" : String | semmle.label | "http://www.example.com/rest/getuser.do?uid=abcdx" : String |
7-
| UnsecureBasicAuth.java:46:3:46:6 | conn | semmle.label | conn |
8-
| UnsecureBasicAuth.java:47:3:47:6 | conn | semmle.label | conn |
9-
| UnsecureBasicAuth.java:48:3:48:6 | conn | semmle.label | conn |
6+
| UnsecureBasicAuth.java:94:19:94:68 | "http://www.example.com/rest/getuser.do?uid=abcdx" : String | semmle.label | "http://www.example.com/rest/getuser.do?uid=abcdx" : String |
7+
| UnsecureBasicAuth.java:99:3:99:6 | conn | semmle.label | conn |
8+
| UnsecureBasicAuth.java:100:3:100:6 | conn | semmle.label | conn |
9+
| UnsecureBasicAuth.java:101:3:101:6 | conn | semmle.label | conn |
1010
#select
11-
| UnsecureBasicAuth.java:24:3:24:59 | addHeader(...) | Unsafe basic authentication |
12-
| UnsecureBasicAuth.java:34:3:34:108 | setHeader(...) | Unsafe basic authentication |
13-
| UnsecureBasicAuth.java:48:3:48:63 | setRequestProperty(...) | Unsafe basic authentication |
11+
| UnsecureBasicAuth.java:28:3:28:59 | addHeader(...) | Insecure basic authentication |
12+
| UnsecureBasicAuth.java:38:3:38:108 | setHeader(...) | Insecure basic authentication |
13+
| UnsecureBasicAuth.java:54:3:54:59 | addHeader(...) | Insecure basic authentication |
14+
| UnsecureBasicAuth.java:70:3:70:59 | addHeader(...) | Insecure basic authentication |
15+
| UnsecureBasicAuth.java:87:3:87:59 | addHeader(...) | Insecure basic authentication |
16+
| UnsecureBasicAuth.java:101:3:101:63 | setRequestProperty(...) | Insecure basic authentication |

java/ql/test/experimental/query-tests/security/CWE-522/UnsecureBasicAuth.java

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
1+
import org.apache.http.RequestLine;
12
import org.apache.http.client.methods.HttpRequestBase;
23
import org.apache.http.client.methods.HttpGet;
34
import org.apache.http.client.methods.HttpPost;
5+
import org.apache.http.message.BasicHttpRequest;
6+
import org.apache.http.message.BasicRequestLine;
47

8+
import java.net.URI;
59
import java.net.URL;
610
import java.net.HttpURLConnection;
711
import java.net.URLConnection;
812
import java.util.Base64;
913

1014
public class UnsecureBasicAuth {
1115
/**
12-
* Test basic authentication with Apache HTTP POST request.
16+
* Test basic authentication with Apache HTTP POST request using string constructor.
1317
*/
1418
public void testApacheHttpRequest(String username, String password) {
1519
String host = "www.example.com";
@@ -34,6 +38,55 @@ public void testApacheHttpRequest2(String url) throws java.io.IOException {
3438
get.setHeader("Authorization", "Basic " + new String(Base64.getEncoder().encode("admin:test".getBytes())));
3539
}
3640

41+
/**
42+
* Test basic authentication with Apache HTTP POST request using URI constructor.
43+
*/
44+
public void testApacheHttpRequest3(String username, String password) {
45+
String uriStr = "http://www.example.com/rest/getuser.do?uid=abcdx";
46+
HttpRequestBase post = new HttpPost(new URI(uriStr));
47+
post.setHeader("Accept", "application/json");
48+
post.setHeader("Content-type", "application/json");
49+
50+
String authString = username + ":" + password;
51+
byte[] authEncBytes = Base64.getEncoder().encode(authString.getBytes());
52+
String authStringEnc = new String(authEncBytes);
53+
54+
post.addHeader("Authorization", "Basic " + authStringEnc);
55+
}
56+
57+
/**
58+
* Test basic authentication with Apache HTTP `BasicHttpRequest` using string constructor.
59+
*/
60+
public void testApacheHttpRequest4(String username, String password) {
61+
String uriStr = "http://www.example.com/rest/getuser.do?uid=abcdx";
62+
BasicHttpRequest post = new BasicHttpRequest("POST", uriStr);
63+
post.setHeader("Accept", "application/json");
64+
post.setHeader("Content-type", "application/json");
65+
66+
String authString = username + ":" + password;
67+
byte[] authEncBytes = Base64.getEncoder().encode(authString.getBytes());
68+
String authStringEnc = new String(authEncBytes);
69+
70+
post.addHeader("Authorization", "Basic " + authStringEnc);
71+
}
72+
73+
/**
74+
* Test basic authentication with Apache HTTP `BasicHttpRequest` using `RequestLine`.
75+
*/
76+
public void testApacheHttpRequest5(String username, String password) {
77+
String uriStr = "http://www.example.com/rest/getuser.do?uid=abcdx";
78+
RequestLine requestLine = new BasicRequestLine("POST", uriStr, null);
79+
BasicHttpRequest post = new BasicHttpRequest(requestLine);
80+
post.setHeader("Accept", "application/json");
81+
post.setHeader("Content-type", "application/json");
82+
83+
String authString = username + ":" + password;
84+
byte[] authEncBytes = Base64.getEncoder().encode(authString.getBytes());
85+
String authStringEnc = new String(authEncBytes);
86+
87+
post.addHeader("Authorization", "Basic " + authStringEnc);
88+
}
89+
3790
/**
3891
* Test basic authentication with Java HTTP URL connection.
3992
*/

java/ql/test/stubs/apache-http-4.4.13/org/apache/http/client/methods/HttpRequestBase.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,12 @@ public void abort() {
7979
public boolean isAborted() {
8080
return false;
8181
}
82+
83+
// Add method from `org.apache.http.HttpMessage`
84+
public void addHeader(String name, String value) {
85+
}
86+
87+
// Add method from `org.apache.http.HttpMessage`
88+
public void setHeader(String name, String value) {
89+
}
8290
}

java/ql/test/stubs/apache-http-4.4.13/org/apache/http/message/BasicHttpRequest.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,18 @@ public BasicHttpRequest(final RequestLine requestline) {
6161
}
6262

6363
public ProtocolVersion getProtocolVersion() {
64-
return null;
64+
return null;
6565
}
6666

6767
public RequestLine getRequestLine() {
6868
return null;
6969
}
7070

71+
// Add method from `org.apache.http.HttpMessage`
72+
public void addHeader(String name, String value) {
73+
}
74+
75+
// Add method from `org.apache.http.HttpMessage`
76+
public void setHeader(String name, String value) {
77+
}
7178
}

0 commit comments

Comments
 (0)