Files
codeql/csharp/ql/src/Security Features/InsecureRandomness.ql
2018-08-02 17:53:23 +01:00

109 lines
3.6 KiB
Plaintext

/**
* @name Insecure randomness
* @description Using a cryptographically weak pseudo-random number generator to generate a
* security sensitive value may allow an attacker to predict what sensitive value will
* be generated.
* @kind problem
* @problem.severity warning
* @precision high
* @id cs/insecure-randomness
* @tags security
* external/cwe/cwe-338
*/
import csharp
import semmle.code.csharp.frameworks.Test
module Random {
import semmle.code.csharp.dataflow.flowsources.Remote
import semmle.code.csharp.security.SensitiveActions
/**
* A data flow sink for insecure randomness in security sensitive context.
*/
abstract class Sink extends DataFlow::ExprNode { }
/**
* A data flow source for insecure randomness in security sensitive context.
*/
abstract class Source extends DataFlow::ExprNode { }
/**
* A sanitizer for insecure randomness in security sensitive context.
*/
abstract class Sanitizer extends DataFlow::ExprNode { }
/**
* A taint-tracking configuration for insecure randomness in security sensitive context.
*/
class TaintTrackingConfiguration extends TaintTracking::Configuration {
TaintTrackingConfiguration() {
this = "RandomDataFlowConfiguration"
}
override predicate isSource(DataFlow::Node source) {
source instanceof Source
}
override predicate isSink(DataFlow::Node sink) {
sink instanceof Sink
}
override predicate isSanitizer(DataFlow::Node node) {
node instanceof Sanitizer
}
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
// succ = array_or_indexer[pred] - use of random numbers in an index
succ.asExpr().(ElementAccess).getAnIndex() = pred.asExpr()
}
}
/** A source of cryptographically insecure random numbers. */
class RandomSource extends Source {
RandomSource() {
this.getExpr() = any(MethodCall mc | mc.getQualifier().getType().(RefType).hasQualifiedName("System", "Random"))
}
}
/** A value assigned to a property, variable or parameter which holds security sensitive data. */
class SensitiveSink extends Sink {
SensitiveSink() {
exists(Expr e |
// Simple assignment
e = this.getExpr() |
e = any(SensitiveVariable v).getAnAssignedValue() or
e = any(SensitiveProperty v).getAnAssignedValue() or
e = any(SensitiveLibraryParameter v).getAnAssignedArgument() or
// Assignment operation, e.g. += or similar
exists(AssignOperation ao |
ao.getRValue() = e and
// "expanded" assignments will be covered by simple assignment
not ao.hasExpandedAssignment() |
ao.getLValue() = any(SensitiveVariable v).getAnAccess() or
ao.getLValue() = any(SensitiveProperty v).getAnAccess() or
ao.getLValue() = any(SensitiveLibraryParameter v).getAnAccess()
)
)
}
}
/**
* Stop tracking beyond first assignment to sensitive element, so as to remove duplication in the
* reported results.
*/
class AlreadyTrackedSanitizer extends Sanitizer {
AlreadyTrackedSanitizer() {
exists(Expr e |
e = this.getExpr() |
e = any(SensitiveVariable v).getAnAccess() or
e = any(SensitiveProperty v).getAnAccess() or
e = any(SensitiveLibraryParameter v).getAnAccess()
)
}
}
}
from Random::TaintTrackingConfiguration randomTracking, Random::Source source, Random::Sink sink
where randomTracking.hasFlow(source, sink)
select sink, "Cryptographically insecure random number is generated at $@ and used here in a security context.", source, source.toString()