Skip to content

Commit c2e057d

Browse files
authored
Merge pull request #7094 from geoffw0/non-https-url
C++: New query 'Failure to use HTTPS URLs'
2 parents d323b3b + ea580cd commit c2e057d

File tree

7 files changed

+217
-0
lines changed

7 files changed

+217
-0
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
lgtm,codescanning
2+
* A new query `cpp/non-https-url` has been added for C/C++. The query flags uses of `http` URLs that might be better replaced with `https`.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
void openUrl(char *url)
3+
{
4+
// ...
5+
}
6+
7+
openUrl("http://example.com"); // BAD
8+
9+
openUrl("https://example.com"); // GOOD: Opening a connection to a URL using HTTPS enforces SSL.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
<overview>
6+
7+
<p>Constructing URLs with the HTTP protocol can lead to unsecured connections.</p>
8+
9+
</overview>
10+
<recommendation>
11+
12+
<p>When you construct a URL, ensure that you use an HTTPS URL rather than an HTTP URL. Then, any connections that are made using that URL are secure SSL connections.</p>
13+
14+
</recommendation>
15+
<example>
16+
17+
<p>The following example shows two ways of opening a connection using a URL. When the connection is
18+
opened using an HTTP URL rather than an HTTPS URL, the connection is unsecured. When the connection is opened using an HTTPS URL, the connection is a secure SSL connection.</p>
19+
20+
<sample src="UseOfHttp.cpp" />
21+
22+
</example>
23+
<references>
24+
25+
<li>
26+
OWASP:
27+
<a href="https://cheatsheetseries.owasp.org/cheatsheets/Transport_Layer_Protection_Cheat_Sheet.html">Transport Layer Protection Cheat Sheet</a>.
28+
</li>
29+
<li>
30+
OWASP Top 10:
31+
<a href="https://owasp.org/Top10/A08_2021-Software_and_Data_Integrity_Failures/">A08:2021 - Software and Data Integrity Failures</a>.
32+
</li>
33+
34+
</references>
35+
</qhelp>
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/**
2+
* @name Failure to use HTTPS URLs
3+
* @description Non-HTTPS connections can be intercepted by third parties.
4+
* @kind path-problem
5+
* @problem.severity warning
6+
* @precision medium
7+
* @id cpp/non-https-url
8+
* @tags security
9+
* external/cwe/cwe-319
10+
*/
11+
12+
import cpp
13+
import semmle.code.cpp.dataflow.TaintTracking
14+
import DataFlow::PathGraph
15+
16+
/**
17+
* A string matching private host names of IPv4 and IPv6, which only matches
18+
* the host portion therefore checking for port is not necessary.
19+
* Several examples are localhost, reserved IPv4 IP addresses including
20+
* 127.0.0.1, 10.x.x.x, 172.16.x,x, 192.168.x,x, and reserved IPv6 addresses
21+
* including [0:0:0:0:0:0:0:1] and [::1]
22+
*/
23+
class PrivateHostName extends string {
24+
bindingset[this]
25+
PrivateHostName() {
26+
this.regexpMatch("(?i)localhost(?:[:/?#].*)?|127\\.0\\.0\\.1(?:[:/?#].*)?|10(?:\\.[0-9]+){3}(?:[:/?#].*)?|172\\.16(?:\\.[0-9]+){2}(?:[:/?#].*)?|192.168(?:\\.[0-9]+){2}(?:[:/?#].*)?|\\[?0:0:0:0:0:0:0:1\\]?(?:[:/?#].*)?|\\[?::1\\]?(?:[:/?#].*)?")
27+
}
28+
}
29+
30+
/**
31+
* A string containing an HTTP URL not in a private domain.
32+
*/
33+
class HttpStringLiteral extends StringLiteral {
34+
HttpStringLiteral() {
35+
exists(string s | this.getValue() = s |
36+
s = "http"
37+
or
38+
exists(string tail |
39+
tail = s.regexpCapture("http://(.*)", 1) and not tail instanceof PrivateHostName
40+
) and
41+
not TaintTracking::localExprTaint(any(StringLiteral p |
42+
p.getValue() instanceof PrivateHostName
43+
), this.getParent*())
44+
)
45+
}
46+
}
47+
48+
/**
49+
* Taint tracking configuration for HTTP connections.
50+
*/
51+
class HttpStringToUrlOpenConfig extends TaintTracking::Configuration {
52+
HttpStringToUrlOpenConfig() { this = "HttpStringToUrlOpenConfig" }
53+
54+
override predicate isSource(DataFlow::Node src) {
55+
// Sources are strings containing an HTTP URL not in a private domain.
56+
src.asExpr() instanceof HttpStringLiteral
57+
}
58+
59+
override predicate isSink(DataFlow::Node sink) {
60+
// Sinks can be anything that demonstrates the string is likely to be
61+
// accessed as a URL, for example using it in a network access. Some
62+
// URLs are only ever displayed or used for data processing.
63+
exists(FunctionCall fc |
64+
fc.getTarget().hasGlobalOrStdName(["system", "gethostbyname", "getaddrinfo"]) and
65+
sink.asExpr() = fc.getArgument(0)
66+
or
67+
fc.getTarget().hasGlobalOrStdName(["send", "URLDownloadToFile", "URLDownloadToCacheFile"]) and
68+
sink.asExpr() = fc.getArgument(1)
69+
or
70+
fc.getTarget().hasGlobalOrStdName(["curl_easy_setopt", "getnameinfo"]) and
71+
sink.asExpr() = fc.getArgument(2)
72+
or
73+
fc.getTarget().hasGlobalOrStdName(["ShellExecute", "ShellExecuteA", "ShellExecuteW"]) and
74+
sink.asExpr() = fc.getArgument(3)
75+
)
76+
}
77+
}
78+
79+
from
80+
HttpStringToUrlOpenConfig config, DataFlow::PathNode source, DataFlow::PathNode sink,
81+
HttpStringLiteral str
82+
where
83+
config.hasFlowPath(source, sink) and
84+
str = source.getNode().asExpr()
85+
select str, source, sink, "A URL may be constructed with the HTTP protocol."
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
edges
2+
| test.cpp:11:26:11:28 | url | test.cpp:15:30:15:32 | url |
3+
| test.cpp:28:10:28:29 | http://example.com | test.cpp:11:26:11:28 | url |
4+
| test.cpp:35:23:35:42 | http://example.com | test.cpp:39:11:39:15 | url_l |
5+
| test.cpp:36:26:36:45 | http://example.com | test.cpp:40:11:40:17 | access to array |
6+
| test.cpp:39:11:39:15 | url_l | test.cpp:11:26:11:28 | url |
7+
| test.cpp:40:11:40:17 | access to array | test.cpp:11:26:11:28 | url |
8+
| test.cpp:46:18:46:26 | http:// | test.cpp:49:11:49:16 | buffer |
9+
| test.cpp:49:11:49:16 | buffer | test.cpp:11:26:11:28 | url |
10+
nodes
11+
| test.cpp:11:26:11:28 | url | semmle.label | url |
12+
| test.cpp:15:30:15:32 | url | semmle.label | url |
13+
| test.cpp:28:10:28:29 | http://example.com | semmle.label | http://example.com |
14+
| test.cpp:35:23:35:42 | http://example.com | semmle.label | http://example.com |
15+
| test.cpp:36:26:36:45 | http://example.com | semmle.label | http://example.com |
16+
| test.cpp:39:11:39:15 | url_l | semmle.label | url_l |
17+
| test.cpp:40:11:40:17 | access to array | semmle.label | access to array |
18+
| test.cpp:46:18:46:26 | http:// | semmle.label | http:// |
19+
| test.cpp:49:11:49:16 | buffer | semmle.label | buffer |
20+
subpaths
21+
#select
22+
| test.cpp:28:10:28:29 | http://example.com | test.cpp:28:10:28:29 | http://example.com | test.cpp:15:30:15:32 | url | A URL may be constructed with the HTTP protocol. |
23+
| test.cpp:35:23:35:42 | http://example.com | test.cpp:35:23:35:42 | http://example.com | test.cpp:15:30:15:32 | url | A URL may be constructed with the HTTP protocol. |
24+
| test.cpp:36:26:36:45 | http://example.com | test.cpp:36:26:36:45 | http://example.com | test.cpp:15:30:15:32 | url | A URL may be constructed with the HTTP protocol. |
25+
| test.cpp:46:18:46:26 | http:// | test.cpp:46:18:46:26 | http:// | test.cpp:15:30:15:32 | url | A URL may be constructed with the HTTP protocol. |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Security/CWE/CWE-319/UseOfHttp.ql
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
2+
struct host
3+
{
4+
// ...
5+
};
6+
7+
host gethostbyname(const char *str);
8+
char *strcpy(char *s1, const char *s2);
9+
char *strcat(char *s1, const char *s2);
10+
11+
void openUrl(const char *url)
12+
{
13+
// ...
14+
15+
host myHost = gethostbyname(url);
16+
17+
// ...
18+
}
19+
20+
void doNothing(char *url)
21+
{
22+
}
23+
24+
const char *url_g = "http://example.com"; // BAD [NOT DETECTED]
25+
26+
void test()
27+
{
28+
openUrl("http://example.com"); // BAD
29+
openUrl("https://example.com"); // GOOD (https)
30+
openUrl("http://localhost/example"); // GOOD (localhost)
31+
openUrl("https://localhost/example"); // GOOD (https, localhost)
32+
doNothing("http://example.com"); // GOOD (URL not used)
33+
34+
{
35+
const char *url_l = "http://example.com"; // BAD
36+
const char *urls[] = { "http://example.com" }; // BAD
37+
38+
openUrl(url_g);
39+
openUrl(url_l);
40+
openUrl(urls[0]);
41+
}
42+
43+
{
44+
char buffer[1024];
45+
46+
strcpy(buffer, "http://"); // BAD
47+
strcat(buffer, "example.com");
48+
49+
openUrl(buffer);
50+
}
51+
52+
{
53+
char buffer[1024];
54+
55+
strcpy(buffer, "https://"); // GOOD (https)
56+
strcat(buffer, "example.com");
57+
58+
openUrl(buffer);
59+
}
60+
}

0 commit comments

Comments
 (0)