mirror of
https://github.com/github/codeql.git
synced 2026-04-29 18:55:14 +02:00
Merge pull request #10943 from bananabr/main
Javascript/Python: Tokens built from predictable UUIDs
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
var uuid = require('uuid');
|
||||
|
||||
module.exports = function (app) {
|
||||
|
||||
app.use('/login', function (req, res) {
|
||||
|
||||
var username = req.body.username;
|
||||
var password = req.body.password;
|
||||
|
||||
if (!username) {
|
||||
res.status(400);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!password) {
|
||||
res.status(400);
|
||||
return;
|
||||
}
|
||||
|
||||
var newToken = {
|
||||
userId: user._id,
|
||||
token: uuid.v1(),
|
||||
created: new Date(),
|
||||
};
|
||||
|
||||
res.status(200).json({
|
||||
token: newToken.token
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>
|
||||
GUIDs (often called UUIDs) are widely used in modern web applications.
|
||||
One common use for UUIDs is the generation of one-time-use tokens.
|
||||
These can used for password reset, and e-mail confirmation routines, for example.
|
||||
</p>
|
||||
<p>
|
||||
There are five versions of UUIDs defined in RFC 4122.
|
||||
Out of the five, four are generated in a predictable manner.
|
||||
This means it is possible for someone to predict future UUIDs based on a sample
|
||||
generated by the target application.
|
||||
</p>
|
||||
<p>
|
||||
Version four is the only UUID version expected to be randomly generated.
|
||||
Therefore, for situations where predictable tokens are not desired (e.g. password reset tokens),
|
||||
all other versions should be avoided.
|
||||
</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>When using GUIDs/UUIDs for generating tokens that should not be predictable, use version four.</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>This example shows a UUID v1 being used for a password reset routine.
|
||||
</p>
|
||||
|
||||
<sample src="TokenBuiltFromUUID.js" />
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>UUID <a href="https://datatracker.ietf.org/doc/html/rfc4122">RFC</a>.</li>
|
||||
<li>Daniel Thatcher <i>In GUID We Trust</i> <a href="https://www.intruder.io/research/in-guid-we-trust">article</a>.</li>
|
||||
<li>UUID exploitation <a href="https://github.com/intruder-io/guidtool">tool</a>.</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* @name Predictable token
|
||||
* @description Tokens used for sensitive tasks, such as, password recovery,
|
||||
* and email confirmation, should not use predictable values.
|
||||
* @kind path-problem
|
||||
* @precision medium
|
||||
* @problem.severity error
|
||||
* @security-severity 5
|
||||
* @id py/predictable-token
|
||||
* @tags security
|
||||
* external/cwe/cwe-340
|
||||
*/
|
||||
|
||||
import javascript
|
||||
import DataFlow
|
||||
import DataFlow::PathGraph
|
||||
|
||||
class PredictableResultSource extends DataFlow::Node {
|
||||
PredictableResultSource() {
|
||||
exists(API::Node uuidCallRet |
|
||||
uuidCallRet = API::moduleImport("uuid").getMember(["v1", "v3", "v5"]).getReturn()
|
||||
|
|
||||
this = uuidCallRet.asSource()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TokenAssignmentValueSink extends DataFlow::Node {
|
||||
TokenAssignmentValueSink() {
|
||||
exists(string name | name.toLowerCase().matches(["%token", "%code"]) |
|
||||
exists(PropWrite pw | this = pw.getRhs() | pw.getPropertyName().toLowerCase() = name)
|
||||
or
|
||||
exists(AssignExpr ae | this = ae.getRhs().flow() |
|
||||
ae.getLhs().(VariableAccess).getVariable().getName().toLowerCase() = name
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TokenBuiltFromUuidConfig extends TaintTracking::Configuration {
|
||||
TokenBuiltFromUuidConfig() { this = "TokenBuiltFromUuidConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof PredictableResultSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof TokenAssignmentValueSink }
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, TokenBuiltFromUuidConfig config
|
||||
where config.hasFlowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "Token built from $@.", source.getNode(), "predictable value"
|
||||
Reference in New Issue
Block a user