| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,30 @@ | |||
| 1 | + var uuid = require('uuid'); | ||
| 2 | + | ||
| 3 | + module.exports = function (app) { | ||
| 4 | + | ||
| 5 | + app.use('/login', function (req, res) { | ||
| 6 | + | ||
| 7 | + var username = req.body.username; | ||
| 8 | + var password = req.body.password; | ||
| 9 | + | ||
| 10 | + if (!username) { | ||
| 11 | + res.status(400); | ||
| 12 | + return; | ||
| 13 | + } | ||
| 14 | + | ||
| 15 | + if (!password) { | ||
| 16 | + res.status(400); | ||
| 17 | + return; | ||
| 18 | + } | ||
| 19 | + | ||
| 20 | + var newToken = { | ||
| 21 | + userId: user._id, | ||
| 22 | + token: uuid.v1(), | ||
| 23 | + created: new Date(), | ||
| 24 | + }; | ||
| 25 | + | ||
| 26 | + res.status(200).json({ | ||
| 27 | + token: newToken.token | ||
| 28 | + }); | ||
| 29 | + }); | ||
| 30 | + }; | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,40 @@ | |||
| 1 | + <!DOCTYPE qhelp PUBLIC | ||
| 2 | + "-//Semmle//qhelp//EN" | ||
| 3 | + "qhelp.dtd"> | ||
| 4 | + <qhelp> | ||
| 5 | + <overview> | ||
| 6 | + <p> | ||
| 7 | + GUIDs (often called UUIDs) are widely used in modern web applications. | ||
| 8 | + One common use for UUIDs is the generation of one-time-use tokens. | ||
| 9 | + These can used for password reset, and e-mail confirmation routines, for example. | ||
| 10 | + </p> | ||
| 11 | + <p> | ||
| 12 | + There are five versions of UUIDs defined in RFC 4122. | ||
| 13 | + Out of the five, four are generated in a predictable manner. | ||
| 14 | + This means it is possible for someone to predict future UUIDs based on a sample | ||
| 15 | + generated by the target application. | ||
| 16 | + </p> | ||
| 17 | + <p> | ||
| 18 | + Version four is the only UUID version expected to be randomly generated. | ||
| 19 | + Therefore, for situations where predictable tokens are not desired (e.g. password reset tokens), | ||
| 20 | + all other versions should be avoided. | ||
| 21 | + </p> | ||
| 22 | + </overview> | ||
| 23 | + | ||
| 24 | + <recommendation> | ||
| 25 | + <p>When using GUIDs/UUIDs for generating tokens that should not be predictable, use version four.</p> | ||
| 26 | + </recommendation> | ||
| 27 | + | ||
| 28 | + <example> | ||
| 29 | + <p>This example shows a UUID v1 being used for a password reset routine. | ||
| 30 | + </p> | ||
| 31 | + | ||
| 32 | + <sample src="TokenBuiltFromUUID.js" /> | ||
| 33 | + </example> | ||
| 34 | + | ||
| 35 | + <references> | ||
| 36 | + <li>UUID <a href="https://datatracker.ietf.org/doc/html/rfc4122">RFC</a>.</li> | ||
| 37 | + <li>Daniel Thatcher <i>In GUID We Trust</i> <a href="https://www.intruder.io/research/in-guid-we-trust">article</a>.</li> | ||
| 38 | + <li>UUID exploitation <a href="https://github.com/intruder-io/guidtool">tool</a>.</li> | ||
| 39 | + </references> | ||
| 40 | + </qhelp> | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,50 @@ | |||
| 1 | + /** | ||
| 2 | + * @name Predictable token | ||
| 3 | + * @description Tokens used for sensitive tasks, such as, password recovery, | ||
| 4 | + * and email confirmation, should not use predictable values. | ||
| 5 | + * @kind path-problem | ||
| 6 | + * @precision medium | ||
| 7 | + * @problem.severity error | ||
| 8 | + * @security-severity 5 | ||
| 9 | + * @id py/predictable-token | ||
| 10 | + * @tags security | ||
| 11 | + * external/cwe/cwe-340 | ||
| 12 | + */ | ||
| 13 | + | ||
| 14 | + import javascript | ||
| 15 | + import DataFlow | ||
| 16 | + import DataFlow::PathGraph | ||
| 17 | + | ||
| 18 | + class PredictableResultSource extends DataFlow::Node { | ||
| 19 | + PredictableResultSource() { | ||
| 20 | + exists(API::Node uuidCallRet | | ||
| 21 | + uuidCallRet = API::moduleImport("uuid").getMember(["v1", "v3", "v5"]).getReturn() | ||
| 22 | + | | ||
| 23 | + this = uuidCallRet.asSource() | ||
| 24 | + ) | ||
| 25 | + } | ||
| 26 | + } | ||
| 27 | + | ||
| 28 | + class TokenAssignmentValueSink extends DataFlow::Node { | ||
| 29 | + TokenAssignmentValueSink() { | ||
| 30 | + exists(string name | name.toLowerCase().matches(["%token", "%code"]) | | ||
| 31 | + exists(PropWrite pw | this = pw.getRhs() | pw.getPropertyName().toLowerCase() = name) | ||
| 32 | + or | ||
| 33 | + exists(AssignExpr ae | this = ae.getRhs().flow() | | ||
| 34 | + ae.getLhs().(VariableAccess).getVariable().getName().toLowerCase() = name | ||
| 35 | + ) | ||
| 36 | + ) | ||
| 37 | + } | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + class TokenBuiltFromUuidConfig extends TaintTracking::Configuration { | ||
| 41 | + TokenBuiltFromUuidConfig() { this = "TokenBuiltFromUuidConfig" } | ||
| 42 | + | ||
| 43 | + override predicate isSource(DataFlow::Node source) { source instanceof PredictableResultSource } | ||
| 44 | + | ||
| 45 | + override predicate isSink(DataFlow::Node sink) { sink instanceof TokenAssignmentValueSink } | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + from DataFlow::PathNode source, DataFlow::PathNode sink, TokenBuiltFromUuidConfig config | ||
| 49 | + where config.hasFlowPath(source, sink) | ||
| 50 | + select sink.getNode(), source, sink, "Token built from $@.", source.getNode(), "predictable value" | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,13 @@ | |||
| 1 | + import uuid | ||
| 2 | + | ||
| 3 | + | ||
| 4 | + class User: | ||
| 5 | + def __init__(self): | ||
| 6 | + self.token = None | ||
| 7 | + | ||
| 8 | + def resetPassword(self): | ||
| 9 | + self.token = uuid.uuid1().hex | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + user = User() | ||
| 13 | + user.resetPassword() | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,40 @@ | |||
| 1 | + <!DOCTYPE qhelp PUBLIC | ||
| 2 | + "-//Semmle//qhelp//EN" | ||
| 3 | + "qhelp.dtd"> | ||
| 4 | + <qhelp> | ||
| 5 | + <overview> | ||
| 6 | + <p> | ||
| 7 | + GUIDs (often called UUIDs) are widely used in modern web applications. | ||
| 8 | + One common use for UUIDs is the generation of one-time-use tokens. | ||
| 9 | + These can used for password reset, and e-mail confirmation routines, for example. | ||
| 10 | + </p> | ||
| 11 | + <p> | ||
| 12 | + There are five versions of UUIDs defined in RFC 4122. | ||
| 13 | + Out of the five, four are generated in a predictable manner. | ||
| 14 | + This means it is possible for someone to predict future UUIDs based on a sample | ||
| 15 | + generated by the target application. | ||
| 16 | + </p> | ||
| 17 | + <p> | ||
| 18 | + Version four is the only UUID version expected to be randomly generated. | ||
| 19 | + Therefore, for situations where predictable tokens are not desired (e.g. password reset tokens), | ||
| 20 | + all other versions should be avoided. | ||
| 21 | + </p> | ||
| 22 | + </overview> | ||
| 23 | + | ||
| 24 | + <recommendation> | ||
| 25 | + <p>When using GUIDs/UUIDs for generating tokens that should not be predictable, use version four.</p> | ||
| 26 | + </recommendation> | ||
| 27 | + | ||
| 28 | + <example> | ||
| 29 | + <p>This example shows a UUID v1 being used for a password reset routine. | ||
| 30 | + </p> | ||
| 31 | + | ||
| 32 | + <sample src="TokenBuiltFromUUID.py" /> | ||
| 33 | + </example> | ||
| 34 | + | ||
| 35 | + <references> | ||
| 36 | + <li>UUID <a href="https://datatracker.ietf.org/doc/html/rfc4122">RFC</a>.</li> | ||
| 37 | + <li>Daniel Thatcher <i>In GUID We Trust</i> <a href="https://www.intruder.io/research/in-guid-we-trust">article</a>.</li> | ||
| 38 | + <li>UUID exploitation <a href="https://github.com/intruder-io/guidtool">tool</a>.</li> | ||
| 39 | + </references> | ||
| 40 | + </qhelp> | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,60 @@ | |||
| 1 | + /** | ||
| 2 | + * @name Predictable token | ||
| 3 | + * @description Tokens used for sensitive tasks, such as, password recovery, | ||
| 4 | + * and email confirmation, should not use predictable values. | ||
| 5 | + * @kind path-problem | ||
| 6 | + * @precision medium | ||
| 7 | + * @problem.severity error | ||
| 8 | + * @security-severity 5 | ||
| 9 | + * @id py/predictable-token | ||
| 10 | + * @tags security | ||
| 11 | + * external/cwe/cwe-340 | ||
| 12 | + */ | ||
| 13 | + | ||
| 14 | + import python | ||
| 15 | + import semmle.python.dataflow.new.DataFlow | ||
| 16 | + import semmle.python.ApiGraphs | ||
| 17 | + import semmle.python.dataflow.new.TaintTracking | ||
| 18 | + import DataFlow::PathGraph | ||
| 19 | + | ||
| 20 | + class PredictableResultSource extends DataFlow::Node { | ||
| 21 | + PredictableResultSource() { | ||
| 22 | + exists(API::Node uuidCallRet | | ||
| 23 | + uuidCallRet = API::moduleImport("uuid").getMember(["uuid1", "uuid3", "uuid5"]).getReturn() | ||
| 24 | + | | ||
| 25 | + this = uuidCallRet.asSource() | ||
| 26 | + or | ||
| 27 | + this = uuidCallRet.getMember(["hex", "bytes", "bytes_le"]).asSource() | ||
| 28 | + ) | ||
| 29 | + } | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | + class TokenAssignmentValueSink extends DataFlow::Node { | ||
| 33 | + TokenAssignmentValueSink() { | ||
| 34 | + exists(string name | name.toLowerCase().matches(["%token", "%code"]) | | ||
| 35 | + exists(DefinitionNode n | n.getValue() = this.asCfgNode() | name = n.(NameNode).getId()) | ||
| 36 | + or | ||
| 37 | + exists(DataFlow::AttrWrite aw | aw.getValue() = this | name = aw.getAttributeName()) | ||
| 38 | + ) | ||
| 39 | + } | ||
| 40 | + } | ||
| 41 | + | ||
| 42 | + class TokenBuiltFromUuidConfig extends TaintTracking::Configuration { | ||
| 43 | + TokenBuiltFromUuidConfig() { this = "TokenBuiltFromUuidConfig" } | ||
| 44 | + | ||
| 45 | + override predicate isSource(DataFlow::Node source) { source instanceof PredictableResultSource } | ||
| 46 | + | ||
| 47 | + override predicate isSink(DataFlow::Node sink) { sink instanceof TokenAssignmentValueSink } | ||
| 48 | + | ||
| 49 | + override predicate isAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { | ||
| 50 | + exists(DataFlow::CallCfgNode call | | ||
| 51 | + call = API::builtin("str").getACall() and | ||
| 52 | + nodeFrom = call.getArg(0) and | ||
| 53 | + nodeTo = call | ||
| 54 | + ) | ||
| 55 | + } | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | + from DataFlow::PathNode source, DataFlow::PathNode sink, TokenBuiltFromUuidConfig config | ||
| 59 | + where config.hasFlowPath(source, sink) | ||
| 60 | + select sink.getNode(), source, sink, "Token built from $@.", source.getNode(), "predictable value" | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments