Skip to content

Commit eef7709

Browse files
authored
Merge pull request #7057 from erik-krogh/cwe598
JS: add js/sensitive-get-query query
2 parents 5beb681 + 0ab510f commit eef7709

File tree

7 files changed

+135
-0
lines changed

7 files changed

+135
-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+
* The `js/sensitive-get-query` query has been added. It highlights GET requests that read sensitive information from the query string.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
2+
<qhelp>
3+
<overview>
4+
<p>
5+
Sensitive information such as user passwords should not be transmitted within the query string of the requested URL.
6+
Sensitive information within URLs may be logged in various locations, including the user's browser, the web server,
7+
and any forward or reverse proxy servers between the two endpoints. URLs may also be displayed on-screen, bookmarked
8+
or emailed around by users. They may be disclosed to third parties via the Referer header when any off-site links are
9+
followed. Placing sensitive information into the URL therefore increases the risk that it will be captured by an attacker.
10+
</p>
11+
</overview>
12+
13+
<recommendation>
14+
<p>
15+
Use HTTP POST to send sensitive information as part of the request body; for example, as form data.
16+
</p>
17+
</recommendation>
18+
19+
<example>
20+
<p>
21+
The following example shows two route handlers that both receive a username and a password.
22+
The first receives this sensitive information from the query parameters of a GET request, which is
23+
transmitted in the URL. The second receives this sensitive information from the request body of a POST request.
24+
</p>
25+
<sample src="examples/SensitiveGet.js" />
26+
</example>
27+
28+
<references>
29+
<li>
30+
CWE:
31+
<a href="https://cwe.mitre.org/data/definitions/598.html">CWE-598: Use of GET Request Method with Sensitive Query Strings</a>
32+
</li>
33+
<li>
34+
PortSwigger (Burp):
35+
<a href="https://portswigger.net/kb/issues/00400300_password-submitted-using-get-method">Password Submitted using GET Method</a>
36+
</li>
37+
<li>
38+
OWASP:
39+
<a href="https://owasp.org/www-community/vulnerabilities/Information_exposure_through_query_strings_in_url">Information Exposure through Query Strings in URL</a>
40+
</li>
41+
</references>
42+
</qhelp>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
* @name Sensitive data read from GET request
3+
* @description Placing sensitive data in a GET request increases the risk of
4+
* the data being exposed to an attacker.
5+
* @kind problem
6+
* @problem.severity warning
7+
* @security-severity 6.5
8+
* @precision high
9+
* @id js/sensitive-get-query
10+
* @tags security
11+
* external/cwe/cwe-598
12+
*/
13+
14+
import javascript
15+
16+
from
17+
Express::RouteSetup setup, Express::RouteHandler handler, Express::RequestInputAccess input,
18+
SensitiveExpr sensitive
19+
where
20+
setup.getRequestMethod() = "GET" and
21+
handler = setup.getARouteHandler() and
22+
input.getRouteHandler() = handler and
23+
input.getKind() = "parameter" and
24+
input.(DataFlow::SourceNode).flowsToExpr(sensitive) and
25+
not sensitive.getClassification() = SensitiveDataClassification::id()
26+
select input, "$@ for GET requests uses query parameter as sensitive data.", handler,
27+
"Route handler"
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
const express = require('express');
2+
const app = express();
3+
app.use(require('body-parser').urlencoded({ extended: false }))
4+
5+
// bad: sensitive information is read from query parameters
6+
app.get('/login1', (req, res) => {
7+
const user = req.query.user;
8+
const password = req.query.password;
9+
if (checkUser(user, password)) {
10+
res.send('Welcome');
11+
} else {
12+
res.send('Access denied');
13+
}
14+
});
15+
16+
// good: sensitive information is read from post body
17+
app.post('/login2', (req, res) => {
18+
const user = req.body.user;
19+
const password = req.body.password;
20+
if (checkUser(user, password)) {
21+
res.send('Welcome');
22+
} else {
23+
res.send('Access denied');
24+
}
25+
});
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
| tst.js:8:22:8:39 | req.query.password | $@ for GET requests uses query parameter as sensitive data. | tst.js:6:19:14:1 | (req, r ... serId\\n} | Route handler |
2+
| tst.js:26:22:26:42 | req.par ... sword') | $@ for GET requests uses query parameter as sensitive data. | tst.js:24:20:35:1 | (req, r ... });\\n} | Route handler |
3+
| tst.js:31:24:31:40 | req.param('word') | $@ for GET requests uses query parameter as sensitive data. | tst.js:24:20:35:1 | (req, r ... });\\n} | Route handler |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Security/CWE-598/SensitiveGetQuery.ql
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
const express = require('express');
2+
const app = express();
3+
const bodyParser = require('body-parser');
4+
app.use(bodyParser.urlencoded({extended: true}));
5+
6+
app.get("/login", (req, res) => {
7+
const username = req.query.username; // OK - usernames are fine
8+
const password = req.query.password; // NOT OK - password read
9+
checkUser(username, password, (result) => {
10+
res.send(result);
11+
});
12+
13+
doThing(req.query.userId); // OK - userId
14+
});
15+
16+
app.post("/login", (req, res) => {
17+
const username = req.body.username; // OK - usernames are fine
18+
const password = req.body.password; // OK - not a query parameter
19+
checkUser(username, password, (result) => {
20+
res.send(result);
21+
});
22+
});
23+
24+
app.get("/login2", (req, res) => {
25+
const username = req.param('username'); // NOT OK - usernames are fine
26+
const password = req.param('password'); // NOT OK - password read
27+
checkUser(username, password, (result) => {
28+
res.send(result);
29+
});
30+
31+
const myPassword = req.param('word'); // NOT OK - is used in a sensitive write below.
32+
checkUser(username, myPassword, (result) => {
33+
res.send(result);
34+
});
35+
});

0 commit comments

Comments
 (0)