JS: Update query17 from intro tutorial

This commit is contained in:
Asger F
2024-11-29 09:47:34 +01:00
parent 2722c45737
commit 2db89c1b02
2 changed files with 28 additions and 42 deletions

View File

@@ -700,19 +700,16 @@ The data flow graph-based analyses described so far are all intraprocedural: the
We distinguish here between data flow proper, and *taint tracking*: the latter not only considers value-preserving flow (such as from variable definitions to uses), but also cases where one value influences ("taints") another without determining it entirely. For example, in the assignment ``s2 = s1.substring(i)``, the value of ``s1`` influences the value of ``s2``, because ``s2`` is assigned a substring of ``s1``. In general, ``s2`` will not be assigned ``s1`` itself, so there is no data flow from ``s1`` to ``s2``, but ``s1`` still taints ``s2``.
It is a common pattern that we wish to specify data flow or taint analysis in terms of its *sources* (where flow starts), *sinks* (where it should be tracked), and *barriers* or *sanitizers* (where flow is interrupted). Sanitizers they are very common in security analyses: for example, an analysis that tracks the flow of untrusted user input into, say, a SQL query has to keep track of code that validates the input, thereby making it safe to use. Such a validation step is an example of a sanitizer.
It is a common pattern that we wish to specify data flow or taint analysis in terms of its *sources* (where flow starts), *sinks* (where it should be tracked), and *barriers* (also called *sanitizers*) where flow is interrupted. Sanitizers they are very common in security analyses: for example, an analysis that tracks the flow of untrusted user input into, say, a SQL query has to keep track of code that validates the input, thereby making it safe to use. Such a validation step is an example of a sanitizer.
The classes ``DataFlow::Configuration`` and ``TaintTracking::Configuration`` allow specifying a data flow or taint analysis, respectively, by overriding the following predicates:
A module implementing the signature `DataFlow::ConfigSig` may specify a data flow or taint analysis by implementing the following predicates:
- ``isSource(DataFlow::Node nd)`` selects all nodes ``nd`` from where flow tracking starts.
- ``isSink(DataFlow::Node nd)`` selects all nodes ``nd`` to which the flow is tracked.
- ``isBarrier(DataFlow::Node nd)`` selects all nodes ``nd`` that act as a barrier for data flow; ``isSanitizer`` is the corresponding predicate for taint tracking configurations.
- ``isBarrierEdge(DataFlow::Node src, DataFlow::Node trg)`` is a variant of ``isBarrier(nd)`` that allows specifying barrier *edges* in addition to barrier nodes; again, ``isSanitizerEdge`` is the corresponding predicate for taint tracking;
- ``isBarrier(DataFlow::Node nd)`` selects all nodes ``nd`` that act as a barrier/sanitizer for data flow.
- ``isAdditionalFlowStep(DataFlow::Node src, DataFlow::Node trg)`` allows specifying custom additional flow steps for this analysis; ``isAdditionalTaintStep`` is the corresponding predicate for taint tracking configurations.
Since for technical reasons both ``Configuration`` classes are subtypes of ``string``, you have to choose a unique name for each flow configuration and equate ``this`` with it in the characteristic predicate (as in the example below).
The predicate ``Configuration.hasFlow`` performs the actual flow tracking, starting at a source and looking for flow to a sink that does not pass through a barrier node or edge.
Such a module can be passed to ``DataFlow::Global<...>``. This will produce a module with a ``flow`` predicate that performs the actual flow tracking, starting at a source and looking for flow to a sink that does not pass through a barrier node.
For example, suppose that we are developing an analysis to find hard-coded passwords. We might write a simple query that looks for string constants flowing into variables named ``"password"``.
@@ -720,35 +717,27 @@ For example, suppose that we are developing an analysis to find hard-coded passw
import javascript
class PasswordTracker extends DataFlow::Configuration {
PasswordTracker() {
// unique identifier for this configuration
this = "PasswordTracker"
}
module PasswordConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node nd) { nd.asExpr() instanceof StringLiteral }
override predicate isSource(DataFlow::Node nd) {
nd.asExpr() instanceof StringLiteral
}
override predicate isSink(DataFlow::Node nd) {
passwordVarAssign(_, nd)
}
predicate passwordVarAssign(Variable v, DataFlow::Node nd) {
v.getAnAssignedExpr() = nd.asExpr() and
v.getName().toLowerCase() = "password"
}
predicate isSink(DataFlow::Node nd) { passwordVarAssign(_, nd) }
}
Now we can rephrase our query to use ``Configuration.hasFlow``:
predicate passwordVarAssign(Variable v, DataFlow::Node nd) {
v.getAnAssignedExpr() = nd.asExpr() and
v.getName().toLowerCase() = "password"
}
module PasswordFlow = DataFlow::Global<PasswordConfig>;
Now we can rephrase our query to use ``PasswordFlow::flow``:
.. code-block:: ql
from PasswordTracker pt, DataFlow::Node source, DataFlow::Node sink, Variable v
where pt.hasFlow(source, sink) and pt.passwordVarAssign(v, sink)
from DataFlow::Node source, DataFlow::Node sink, Variable v
where PasswordFlow::flow(_, sink) and passwordVarAssign(v, sink)
select sink, "Password variable " + v + " is assigned a constant string."
Syntax errors
~~~~~~~~~~~~~

View File

@@ -1,23 +1,20 @@
import javascript
class PasswordTracker extends DataFlow::Configuration {
PasswordTracker() {
// unique identifier for this configuration
this = "PasswordTracker"
}
module PasswordConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node nd) { nd.asExpr() instanceof StringLiteral }
override predicate isSource(DataFlow::Node nd) { nd.asExpr() instanceof StringLiteral }
override predicate isSink(DataFlow::Node nd) { this.passwordVarAssign(_, nd) }
predicate passwordVarAssign(Variable v, DataFlow::Node nd) {
v.getAnAssignedExpr() = nd.asExpr() and
v.getName().toLowerCase() = "password"
}
predicate isSink(DataFlow::Node nd) { passwordVarAssign(_, nd) }
}
predicate passwordVarAssign(Variable v, DataFlow::Node nd) {
v.getAnAssignedExpr() = nd.asExpr() and
v.getName().toLowerCase() = "password"
}
module PasswordFlow = DataFlow::Global<PasswordConfig>;
query predicate test_query17(DataFlow::Node sink, string res) {
exists(PasswordTracker pt, Variable v | pt.hasFlow(_, sink) and pt.passwordVarAssign(v, sink) |
exists(Variable v | PasswordFlow::flow(_, sink) and passwordVarAssign(v, sink) |
res = "Password variable " + v.toString() + " is assigned a constant string."
)
}