promote the js/jwt-missing-verification query out of exeprimental

This commit is contained in:
Erik Krogh Kristensen
2022-01-25 14:49:40 +01:00
parent cc527bdecd
commit de633940fe
9 changed files with 75 additions and 42 deletions

View File

@@ -0,0 +1,42 @@
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd"> <qhelp>
<overview>
<p>
Applications decoding JSON Web Token (JWT) may be misconfigured due to the <code>None</code> algorithm.
</p>
<p>
The <code>None</code> algorithm is selected by calling the <code>verify()</code> function with a falsy value
instead of a cryptographic secret or key. The <code>None</code> algorithm disables the integrity enforcement of
a JWT payload and may allow a malicious actor to make any desired changes to a JWT payload leading
to critical security issues like privilege escalation.
</p>
</overview>
<recommendation>
<p>
Calls to <code>verify()</code> functions should use a cryptographic secret or key to decode JWT payloads.
</p>
</recommendation>
<example>
<p>
In the example below <code>false</code> is used to disable the integrity enforcement of a JWT payload.
This may allow a malicious actor to make any desired changes to a JWT payload.
</p>
<sample src="examples/missing-key-verification-bad.js" />
<p>
The following code fixes the problem by using a cryptographic secret or key to decode JWT payloads.
</p>
<sample src="examples/missing-key-verification-good.js" />
</example>
<references>
<li>Auth0 Blog: <a href="https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/#Meet-the--None--Algorithm">Meet the "None" Algorithm</a>.</li>
</references>
</qhelp>

View File

@@ -10,12 +10,11 @@
*/
import javascript
import DataFlow
import semmle.javascript.RestrictedLocations
from CallNode call
from DataFlow::CallNode call
where
call = moduleMember("jsonwebtoken", "verify").getACall() and
call = DataFlow::moduleMember("jsonwebtoken", "verify").getACall() and
unique(boolean b | b = call.getArgument(1).analyze().getABooleanValue()) = false
select call.asExpr().(FirstLineOf),
"does not verify the JWT payload with a cryptographic secret or public key."

View File

@@ -0,0 +1,6 @@
const jwt = require("jsonwebtoken");
const secret = "my-secret-key";
var token = jwt.sign({ foo: 'bar' }, secret, { algorithm: "none" })
jwt.verify(token, false, { algorithms: ["HS256", "none"] })

View File

@@ -0,0 +1,7 @@
const jwt = require("jsonwebtoken");
const secret = "my-secret-key";
var token = jwt.sign({ foo: 'bar' }, secret, { algorithm: "HS256" })
jwt.verify(token, secret, { algorithms: ["HS256", "none"] })

View File

@@ -0,0 +1,4 @@
---
category: newQuery
---
* A new query `js/jwt-missing-verification` has been added. The query detects applications that does not verify JWT tokens.

View File

@@ -1,30 +0,0 @@
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd"> <qhelp>
<overview>
<p>Applications decoding JSON Web Token (JWT) may be misconfigured due to the none algorithm.</p>
<p>The none algorithm is selected by calling the <code>verify()</code> function with a falsy value
instead of a cryptographic secret or key. The none algorithm disables the integrity enforcement of
a JWT payload and may allow a malicious actor to make any desired changes to a JWT payload leading
to critical security issues like privilege escalation.</p>
</overview>
<recommendation>
<p>Call to <code>verify()</code> functions should use a cryptographic secret or key to decode JWT payloads.</p>
</recommendation>
<example>
<p>In the example, the first case is signing an object with a secret and a HS256 algorithm. In the
second case, an empty string is provided, then an undefined value, and finally a false value. These
three misconfigured calls to <code>jwt.verify()</code> can cause vulnerabilities.</p>
<sample src="examples/JWTMissingSecretOrPublicKeyVerification.js" />
</example>
<references>
<li>Auth0 Blog: <a href="https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/#Meet-the--None--Algorithm">Meet the "None" Algorithm</a>.</li>
</references>
</qhelp>

View File

@@ -1,11 +0,0 @@
const jwt = require("jsonwebtoken");
const secret = "buybtc";
// #1
var token = jwt.sign({ foo: 'bar' }, secret, { algorithm: "HS256" }) // alg:HS256
jwt.verify(token, secret, { algorithms: ["HS256", "none"] }) // pass
// #2
var token = jwt.sign({ foo: 'bar' }, secret, { algorithm: "none" }) // alg:none (unsafe)
jwt.verify(token, "", { algorithms: ["HS256", "none"] }) // detected
jwt.verify(token, undefined, { algorithms: ["HS256", "none"] }) // detected
jwt.verify(token, false, { algorithms: ["HS256", "none"] }) // detected