mirror of
https://github.com/github/codeql.git
synced 2026-04-29 18:55:14 +02:00
add insecureRandomness
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Provides a taint tracking configuration for reasoning about random
|
||||
* values that are not cryptographically secure.
|
||||
*
|
||||
* Note, for performance reasons: only import this file if
|
||||
* `InsecureRandomness::Configuration` is needed, otherwise
|
||||
* `InsecureRandomnessCustomizations` should be imported instead.
|
||||
*/
|
||||
|
||||
private import python
|
||||
import semmle.python.dataflow.new.DataFlow
|
||||
import semmle.python.dataflow.new.TaintTracking
|
||||
|
||||
/**
|
||||
* A taint tracking configuration for random values that are not cryptographically secure.
|
||||
*/
|
||||
module InsecureRandomness {
|
||||
import InsecureRandomnessCustomizations::InsecureRandomness
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for reasoning about random values that are
|
||||
* not cryptographically secure.
|
||||
*/
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "InsecureRandomness" }
|
||||
|
||||
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 isSanitizerGuard(DataFlow::BarrierGuard guard) {
|
||||
guard instanceof SanitizerGuard
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* Provides default sources, sinks and sanitizers for reasoning about random values that are
|
||||
* not cryptographically secure, as well as extension points for adding your own.
|
||||
*/
|
||||
|
||||
private import python
|
||||
private import semmle.python.ApiGraphs
|
||||
private import semmle.python.Concepts
|
||||
private import semmle.python.dataflow.new.BarrierGuards
|
||||
private import semmle.python.dataflow.new.internal.DataFlowPrivate
|
||||
|
||||
/**
|
||||
* Provides default sources, sinks and sanitizers for reasoning about random values that are
|
||||
* not cryptographically secure, as well as extension points for adding your own.
|
||||
*/
|
||||
module InsecureRandomness {
|
||||
/**
|
||||
* A data flow source for random values that are not cryptographically secure.
|
||||
*/
|
||||
abstract class Source extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A data flow sink for random values that are not cryptographically secure.
|
||||
*/
|
||||
abstract class Sink extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A sanitizer for random values that are not cryptographically secure.
|
||||
*/
|
||||
abstract class Sanitizer extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A sanitizer guard for random values that are not cryptographically secure.
|
||||
*/
|
||||
abstract class SanitizerGuard extends DataFlow::BarrierGuard { }
|
||||
|
||||
/**
|
||||
* A random source that is not sufficient for security use. So far this is only made up
|
||||
* of the math package's rand function, more insufficient random sources can be added here.
|
||||
*/
|
||||
class InsecureRandomSource extends Source {
|
||||
InsecureRandomSource() {
|
||||
this =
|
||||
API::moduleImport("random")
|
||||
.getMember([
|
||||
"betavariate", "choice", "choices", "expovariate",
|
||||
"gammavariate", "gauss", "getrandbits", "getstate",
|
||||
"lognormvariate", "normalvariate", "paretovariate",
|
||||
"randbytes", "randint", "random", "randrange",
|
||||
"sample", "seed", "setstate", "shuffle",
|
||||
"triangular", "uniform", "vonmisesvariate", "weibullvariate"
|
||||
])
|
||||
.getACall()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A use in a function that heuristically deals with passwords.
|
||||
*/
|
||||
class PasswordFnSink extends Sink {
|
||||
PasswordFnSink() {
|
||||
exists(DataFlowCallable passwordFn |
|
||||
passwordFn.getName().regexpMatch("(?i).*(gen(erate)?|salt|make|mk)Password.*")
|
||||
|
|
||||
this.getEnclosingCallable() = passwordFn
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A cryptographic key, considered as a sink for random values that are not cryptographically
|
||||
* secure.
|
||||
*/
|
||||
class CryptoKeySink extends Sink {
|
||||
CryptoKeySink() {
|
||||
exists(Cryptography::CryptographicOperation operation |
|
||||
this = operation.getAnInput()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>
|
||||
Using a cryptographically weak pseudo-random number generator to generate a security-sensitive value,
|
||||
such as a password, makes it easier for an attacker to predict the value.
|
||||
</p>
|
||||
<p>
|
||||
Pseudo-random number generators generate a sequence of numbers that only approximates the properties
|
||||
of random numbers. The sequence is not truly random because it is completely determined by a
|
||||
relatively small set of initial values, the seed. If the random number generator is
|
||||
cryptographically weak, then this sequence may be easily predictable through outside observations.
|
||||
</p>
|
||||
</overview>
|
||||
<recommendation>
|
||||
<p>
|
||||
Use a cryptographically secure pseudo-random number generator if the output is to be used in a
|
||||
security sensitive context. As a rule of thumb, a value should be considered "security sensitive"
|
||||
if predicting it would allow the attacker to perform an action that they would otherwise be unable
|
||||
to perform. For example, if an attacker could predict the random password generated for a new user,
|
||||
they would be able to log in as that new user.
|
||||
</p>
|
||||
<p>
|
||||
For Python, <code>secrets</code> provides a cryptographically secure pseudo-random
|
||||
number generator. <code>random</code> is not cryptographically secure, and should be avoided in
|
||||
security contexts.
|
||||
</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>
|
||||
The example below uses the <code>random</code> package instead of <code>secrets</code> to generate a password:
|
||||
</p>
|
||||
<sample src="examples/InsecureRandomness.py" />
|
||||
<p>
|
||||
Instead, use <code>secrets</code>:
|
||||
</p>
|
||||
<sample src="examples/InsecureRandomnessGood.py" />
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>Wikipedia. <a href="http://en.wikipedia.org/wiki/Pseudorandom_number_generator">Pseudo-random number generator</a>.</li>
|
||||
<li>OWASP: <a href="https://owasp.org/www-community/vulnerabilities/Insecure_Randomness">Insecure Randomness</a>.</li>
|
||||
<li>OWASP: <a href="https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html#secure-random-number-generation">Secure Random Number Generation</a>.</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* @name Insecure randomness
|
||||
* @description Using insufficient randomness as the key of a cryptographic algorithm can allow an attacker to compromise security.
|
||||
* @kind path-problem
|
||||
* @problem.severity warning
|
||||
* @security-severity 7.8
|
||||
* @precision high
|
||||
* @id python/insecure-randomness
|
||||
* @tags security
|
||||
* external/cwe/cwe-338
|
||||
*/
|
||||
|
||||
import python
|
||||
import semmle.python.security.dataflow.InsecureRandomness::InsecureRandomness
|
||||
import semmle.python.dataflow.new.DataFlow
|
||||
import DataFlow::PathGraph
|
||||
|
||||
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where cfg.hasFlowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "Cryptographically insecure $@ in a security context.",
|
||||
source.getNode(), "random value"
|
||||
@@ -0,0 +1,5 @@
|
||||
import random
|
||||
|
||||
def generatePassword():
|
||||
# BAD: the random is not cryptographically secure
|
||||
return random.random()
|
||||
@@ -0,0 +1,6 @@
|
||||
import secrets
|
||||
|
||||
def generatePassword():
|
||||
# GOOD: the random is cryptographically secure
|
||||
secret_generator = secrets.SystemRandom()
|
||||
return secret_generator.random()
|
||||
Reference in New Issue
Block a user