mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
Copy the structure of the Javascript query
This commit is contained in:
committed by
Owen Mansel-Chan
parent
5c403d374e
commit
34b2e3e2bf
@@ -33,6 +33,7 @@ import semmle.go.frameworks.AwsLambda
|
||||
import semmle.go.frameworks.Beego
|
||||
import semmle.go.frameworks.BeegoOrm
|
||||
import semmle.go.frameworks.Bun
|
||||
import semmle.go.frameworks.CryptoLibraries
|
||||
import semmle.go.frameworks.RsCors
|
||||
import semmle.go.frameworks.Couchbase
|
||||
import semmle.go.frameworks.Echo
|
||||
|
||||
@@ -6,6 +6,7 @@ extractor: go
|
||||
library: true
|
||||
upgrades: upgrades
|
||||
dependencies:
|
||||
codeql/concepts: ${workspace}
|
||||
codeql/dataflow: ${workspace}
|
||||
codeql/mad: ${workspace}
|
||||
codeql/threat-models: ${workspace}
|
||||
|
||||
@@ -8,6 +8,10 @@ import go
|
||||
import semmle.go.dataflow.FunctionInputsAndOutputs
|
||||
import semmle.go.concepts.HTTP
|
||||
import semmle.go.concepts.GeneratedFile
|
||||
private import codeql.concepts.ConceptsShared
|
||||
private import semmle.go.dataflow.internal.DataFlowImplSpecific
|
||||
|
||||
private module ConceptsShared = ConceptsMake<Location, GoDataFlow>;
|
||||
|
||||
/**
|
||||
* A data-flow node that executes an operating system command,
|
||||
@@ -505,3 +509,31 @@ module UnmarshalingFunction {
|
||||
abstract string getFormat();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides models for cryptographic things.
|
||||
*/
|
||||
module Cryptography {
|
||||
private import ConceptsShared::Cryptography as SC
|
||||
|
||||
/**
|
||||
* A data-flow node that is an application of a cryptographic algorithm. For example,
|
||||
* encryption, decryption, signature-validation.
|
||||
*
|
||||
* Extend this class to refine existing API models. If you want to model new APIs,
|
||||
* extend `CryptographicOperation::Range` instead.
|
||||
*/
|
||||
class CryptographicOperation extends SC::CryptographicOperation { }
|
||||
|
||||
class EncryptionAlgorithm = SC::EncryptionAlgorithm;
|
||||
|
||||
class HashingAlgorithm = SC::HashingAlgorithm;
|
||||
|
||||
class PasswordHashingAlgorithm = SC::PasswordHashingAlgorithm;
|
||||
|
||||
module CryptographicOperation = SC::CryptographicOperation;
|
||||
|
||||
class BlockMode = SC::BlockMode;
|
||||
|
||||
class CryptographicAlgorithm = SC::CryptographicAlgorithm;
|
||||
}
|
||||
|
||||
@@ -3,180 +3,31 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
|
||||
/**
|
||||
* Names of cryptographic algorithms, separated into strong and weak variants.
|
||||
*
|
||||
* The names are normalized: upper-case, no spaces, dashes or underscores.
|
||||
*
|
||||
* The names are inspired by the names used in real world crypto libraries.
|
||||
*
|
||||
* The classification into strong and weak are based on OWASP and Wikipedia (2020).
|
||||
*
|
||||
* Sources (more links in qhelp file):
|
||||
* https://en.wikipedia.org/wiki/Strong_cryptography#Cryptographically_strong_algorithms
|
||||
* https://en.wikipedia.org/wiki/Strong_cryptography#Examples
|
||||
* https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html
|
||||
*/
|
||||
private module AlgorithmNames {
|
||||
predicate isStrongHashingAlgorithm(string name) {
|
||||
name =
|
||||
[
|
||||
"DSA", "ED25519", "SHA256", "SHA384", "SHA512", "SHA3", "ES256", "ECDSA256", "ES384",
|
||||
"ECDSA384", "ES512", "ECDSA512", "SHA2", "SHA224"
|
||||
]
|
||||
}
|
||||
|
||||
predicate isWeakHashingAlgorithm(string name) {
|
||||
name =
|
||||
[
|
||||
"HAVEL128", "MD2", "SHA1", "MD4", "MD5", "PANAMA", "RIPEMD", "RIPEMD128", "RIPEMD256",
|
||||
"RIPEMD320", "SHA0"
|
||||
]
|
||||
}
|
||||
|
||||
predicate isStrongEncryptionAlgorithm(string name) {
|
||||
name = ["AES", "AES128", "AES192", "AES256", "AES512", "RSA", "RABBIT", "BLOWFISH"]
|
||||
}
|
||||
|
||||
predicate isWeakEncryptionAlgorithm(string name) {
|
||||
name =
|
||||
[
|
||||
"DES", "3DES", "ARC5", "RC5", "TRIPLEDES", "TDEA", "TRIPLEDEA", "ARC2", "RC2", "ARC4",
|
||||
"RC4", "ARCFOUR"
|
||||
]
|
||||
}
|
||||
|
||||
predicate isStrongPasswordHashingAlgorithm(string name) {
|
||||
name = ["ARGON2", "PBKDF2", "BCRYPT", "SCRYPT"]
|
||||
}
|
||||
|
||||
predicate isWeakPasswordHashingAlgorithm(string name) { none() }
|
||||
}
|
||||
|
||||
private import AlgorithmNames
|
||||
|
||||
/**
|
||||
* A cryptographic algorithm.
|
||||
*/
|
||||
private newtype TCryptographicAlgorithm =
|
||||
MkHashingAlgorithm(string name, boolean isWeak) {
|
||||
isStrongHashingAlgorithm(name) and isWeak = false
|
||||
or
|
||||
isWeakHashingAlgorithm(name) and isWeak = true
|
||||
} or
|
||||
MkEncryptionAlgorithm(string name, boolean isWeak) {
|
||||
isStrongEncryptionAlgorithm(name) and isWeak = false
|
||||
or
|
||||
isWeakEncryptionAlgorithm(name) and isWeak = true
|
||||
} or
|
||||
MkPasswordHashingAlgorithm(string name, boolean isWeak) {
|
||||
isStrongPasswordHashingAlgorithm(name) and isWeak = false
|
||||
or
|
||||
isWeakPasswordHashingAlgorithm(name) and isWeak = true
|
||||
}
|
||||
|
||||
/**
|
||||
* A cryptographic algorithm.
|
||||
*/
|
||||
abstract class CryptographicAlgorithm extends TCryptographicAlgorithm {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = this.getName() }
|
||||
|
||||
/**
|
||||
* Gets the name of this algorithm.
|
||||
*/
|
||||
abstract string getName();
|
||||
|
||||
/**
|
||||
* Holds if the name of this algorithm matches `name` modulo case,
|
||||
* white space, dashes and underscores.
|
||||
*/
|
||||
bindingset[name]
|
||||
predicate matchesName(string name) {
|
||||
exists(name.regexpReplaceAll("[-_]", "").regexpFind("(?i)\\Q" + this.getName() + "\\E", _, _))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this algorithm is weak.
|
||||
*/
|
||||
abstract predicate isWeak();
|
||||
}
|
||||
|
||||
/**
|
||||
* A hashing algorithm such as `MD5` or `SHA512`.
|
||||
*/
|
||||
class HashingAlgorithm extends MkHashingAlgorithm, CryptographicAlgorithm {
|
||||
string name;
|
||||
boolean isWeak;
|
||||
|
||||
HashingAlgorithm() { this = MkHashingAlgorithm(name, isWeak) }
|
||||
|
||||
override string getName() { result = name }
|
||||
|
||||
override predicate isWeak() { isWeak = true }
|
||||
}
|
||||
|
||||
/**
|
||||
* An encryption algorithm such as `DES` or `AES512`.
|
||||
*/
|
||||
class EncryptionAlgorithm extends MkEncryptionAlgorithm, CryptographicAlgorithm {
|
||||
string name;
|
||||
boolean isWeak;
|
||||
|
||||
EncryptionAlgorithm() { this = MkEncryptionAlgorithm(name, isWeak) }
|
||||
|
||||
override string getName() { result = name }
|
||||
|
||||
override predicate isWeak() { isWeak = true }
|
||||
}
|
||||
|
||||
/**
|
||||
* A password hashing algorithm such as `PBKDF2` or `SCRYPT`.
|
||||
*/
|
||||
class PasswordHashingAlgorithm extends MkPasswordHashingAlgorithm, CryptographicAlgorithm {
|
||||
string name;
|
||||
boolean isWeak;
|
||||
|
||||
PasswordHashingAlgorithm() { this = MkPasswordHashingAlgorithm(name, isWeak) }
|
||||
|
||||
override string getName() { result = name }
|
||||
|
||||
override predicate isWeak() { isWeak = true }
|
||||
}
|
||||
|
||||
/**
|
||||
* An application of a cryptographic algorithm.
|
||||
*/
|
||||
abstract class CryptographicOperation extends DataFlow::Node {
|
||||
/**
|
||||
* Gets the input the algorithm is used on, e.g. the plain text input to be encrypted.
|
||||
*/
|
||||
abstract Expr getInput();
|
||||
|
||||
/**
|
||||
* Gets the applied algorithm.
|
||||
*/
|
||||
abstract CryptographicAlgorithm getAlgorithm();
|
||||
}
|
||||
import semmle.go.Concepts::Cryptography
|
||||
private import codeql.concepts.internal.CryptoAlgorithmNames
|
||||
|
||||
/**
|
||||
* A cryptographic operation from the `crypto/md5` package.
|
||||
*/
|
||||
class Md5 extends CryptographicOperation, DataFlow::CallNode {
|
||||
Md5() { this.getTarget().hasQualifiedName("crypto/md5", ["New", "Sum"]) }
|
||||
private module CryptoMd5 {
|
||||
private class Md5 extends CryptographicOperation::Range instanceof DataFlow::CallNode {
|
||||
Md5() { this.getTarget().hasQualifiedName("crypto/md5", ["New", "Sum"]) }
|
||||
|
||||
override Expr getInput() { result = this.getArgument(0).asExpr() }
|
||||
override DataFlow::Node getInitialization() { result = this }
|
||||
|
||||
override CryptographicAlgorithm getAlgorithm() {
|
||||
result.matchesName(this.getTarget().getPackage().getName())
|
||||
override CryptographicAlgorithm getAlgorithm() { result.matchesName("MD5") }
|
||||
|
||||
override DataFlow::Node getAnInput() { result = super.getArgument(0) }
|
||||
|
||||
// not relevant for md5
|
||||
override BlockMode getBlockMode() { none() }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A cryptographic operation from the `crypto/sha1` package.
|
||||
*/
|
||||
class Sha1 extends CryptographicOperation, DataFlow::CallNode {
|
||||
class Sha1 extends CryptographicOperation::Range instanceof DataFlow::CallNode {
|
||||
Sha1() { this.getTarget().hasQualifiedName("crypto/sha1", ["New", "Sum"]) }
|
||||
|
||||
override Expr getInput() { result = this.getArgument(0).asExpr() }
|
||||
@@ -189,7 +40,7 @@ class Sha1 extends CryptographicOperation, DataFlow::CallNode {
|
||||
/**
|
||||
* A cryptographic operation from the `crypto/des` package.
|
||||
*/
|
||||
class Des extends CryptographicOperation, DataFlow::CallNode {
|
||||
class Des extends CryptographicOperation::Range instanceof DataFlow::CallNode {
|
||||
Des() { this.getTarget().hasQualifiedName("crypto/des", ["NewCipher", "NewTripleDESCipher"]) }
|
||||
|
||||
override Expr getInput() { result = this.getArgument(0).asExpr() }
|
||||
@@ -202,7 +53,7 @@ class Des extends CryptographicOperation, DataFlow::CallNode {
|
||||
/**
|
||||
* A cryptographic operation from the `crypto/rc4` package.
|
||||
*/
|
||||
class Rc4 extends CryptographicOperation, DataFlow::CallNode {
|
||||
class Rc4 extends CryptographicOperation::Range instanceof DataFlow::CallNode {
|
||||
Rc4() { this.getTarget().hasQualifiedName("crypto/rc4", "NewCipher") }
|
||||
|
||||
override Expr getInput() { result = this.getArgument(0).asExpr() }
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Provides default sources, sinks and sanitizers for reasoning about
|
||||
* sensitive information in weak cryptographic algorithms,
|
||||
* as well as extension points for adding your own.
|
||||
*/
|
||||
|
||||
import go
|
||||
private import semmle.go.security.SensitiveActions
|
||||
|
||||
/**
|
||||
* Provides default sources, sinks and sanitizers for reasoning about
|
||||
* sensitive information in weak cryptographic algorithms,
|
||||
* as well as extension points for adding your own.
|
||||
*/
|
||||
module BrokenCryptoAlgorithm {
|
||||
/**
|
||||
* A data flow source for sensitive information in broken or weak cryptographic algorithms.
|
||||
*/
|
||||
abstract class Source extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A data flow sink for sensitive information in broken or weak cryptographic algorithms.
|
||||
*/
|
||||
abstract class Sink extends DataFlow::Node {
|
||||
/** Gets the data-flow node where the cryptographic algorithm used in this operation is configured. */
|
||||
abstract DataFlow::Node getInitialization();
|
||||
}
|
||||
|
||||
/**
|
||||
* A sanitizer for sensitive information in broken or weak cryptographic algorithms.
|
||||
*/
|
||||
abstract class Sanitizer extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A sensitive source.
|
||||
*/
|
||||
class SensitiveSource extends Source {
|
||||
SensitiveSource() { this.asExpr() instanceof SensitiveExpr }
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression used by a broken or weak cryptographic algorithm.
|
||||
*/
|
||||
class WeakCryptographicOperationSink extends Sink {
|
||||
CryptographicOperation application;
|
||||
|
||||
WeakCryptographicOperationSink() {
|
||||
(
|
||||
application.getAlgorithm().isWeak()
|
||||
or
|
||||
application.getBlockMode().isWeak()
|
||||
) and
|
||||
this = application.getAnInput()
|
||||
}
|
||||
|
||||
override DataFlow::Node getInitialization() { result = application.getInitialization() }
|
||||
}
|
||||
}
|
||||
41
go/ql/lib/semmle/go/security/BrokenCryptoAlgorithmQuery.qll
Normal file
41
go/ql/lib/semmle/go/security/BrokenCryptoAlgorithmQuery.qll
Normal file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Provides a taint tracking configuration for reasoning about
|
||||
* sensitive information in broken or weak cryptographic algorithms.
|
||||
*
|
||||
* Note, for performance reasons: only import this file if
|
||||
* `BrokenCryptoAlgorithm::Configuration` is needed, otherwise
|
||||
* `BrokenCryptoAlgorithmCustomizations` should be imported instead.
|
||||
*/
|
||||
|
||||
import go
|
||||
import BrokenCryptoAlgorithmCustomizations::BrokenCryptoAlgorithm
|
||||
|
||||
/**
|
||||
* A taint tracking configuration for sensitive information in broken or weak cryptographic algorithms.
|
||||
*
|
||||
* This configuration identifies flows from `Source`s, which are sources of
|
||||
* sensitive data, to `Sink`s, which is an abstract class representing all
|
||||
* the places sensitive data may used in broken or weak cryptographic algorithms. Additional sources or sinks can be
|
||||
* added either by extending the relevant class, or by subclassing this configuration itself,
|
||||
* and amending the sources and sinks.
|
||||
*/
|
||||
private module BrokenCryptoAlgorithmConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
|
||||
Location getASelectedSinkLocation(DataFlow::Node sink) {
|
||||
result = sink.(Sink).getLocation()
|
||||
or
|
||||
result = sink.(Sink).getInitialization().getLocation()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Taint tracking flow for sensitive information in broken or weak cryptographic algorithms.
|
||||
*/
|
||||
module BrokenCryptoAlgorithmFlow = TaintTracking::Global<BrokenCryptoAlgorithmConfig>;
|
||||
@@ -1,66 +0,0 @@
|
||||
/**
|
||||
* Provides default sources, sinks and sanitizers for reasoning about
|
||||
* sensitive information in weak cryptographic algorithms,
|
||||
* as well as extension points for adding your own.
|
||||
*/
|
||||
|
||||
import go
|
||||
private import semmle.go.frameworks.CryptoLibraries
|
||||
private import semmle.go.security.SensitiveActions
|
||||
|
||||
/**
|
||||
* Provides default sources, sinks and sanitizers for reasoning about
|
||||
* sensitive information in weak cryptographic algorithms,
|
||||
* as well as extension points for adding your own.
|
||||
*/
|
||||
module WeakCryptoAlgorithm {
|
||||
/**
|
||||
* A data flow source for sensitive information in weak cryptographic algorithms.
|
||||
*/
|
||||
abstract class Source extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A data flow sink for sensitive information in weak cryptographic algorithms.
|
||||
*/
|
||||
abstract class Sink extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A sanitizer for sensitive information in weak cryptographic algorithms.
|
||||
*/
|
||||
abstract class Sanitizer extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A sensitive source.
|
||||
*/
|
||||
class SensitiveSource extends Source {
|
||||
SensitiveSource() { this.asExpr() instanceof SensitiveExpr }
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression used by a weak cryptographic algorithm.
|
||||
*/
|
||||
class WeakCryptographicOperationSink extends Sink {
|
||||
WeakCryptographicOperationSink() {
|
||||
exists(CryptographicOperation application |
|
||||
application.getAlgorithm().isWeak() and
|
||||
this.asExpr() = application.getInput()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private module Config implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
|
||||
|
||||
predicate observeDiffInformedIncrementalMode() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Tracks taint flow from sensitive information to weak cryptographic
|
||||
* algorithms.
|
||||
*/
|
||||
module Flow = TaintTracking::Global<Config>;
|
||||
}
|
||||
@@ -12,10 +12,10 @@
|
||||
*/
|
||||
|
||||
import go
|
||||
import semmle.go.security.WeakCryptoAlgorithmCustomizations
|
||||
import WeakCryptoAlgorithm::Flow::PathGraph
|
||||
import semmle.go.security.BrokenCryptoAlgorithmQuery
|
||||
import BrokenCryptoAlgorithmFlow::PathGraph
|
||||
|
||||
from WeakCryptoAlgorithm::Flow::PathNode source, WeakCryptoAlgorithm::Flow::PathNode sink
|
||||
where WeakCryptoAlgorithm::Flow::flowPath(source, sink)
|
||||
from BrokenCryptoAlgorithmFlow::PathNode source, BrokenCryptoAlgorithmFlow::PathNode sink
|
||||
where BrokenCryptoAlgorithmFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "$@ is used in a weak cryptographic algorithm.",
|
||||
source.getNode(), "Sensitive data"
|
||||
@@ -1,4 +1,4 @@
|
||||
query: Security/CWE-327/WeakCryptoAlgorithm.ql
|
||||
query: Security/CWE-327/BrokenCryptoAlgorithm.ql
|
||||
postprocess:
|
||||
- utils/test/PrettyPrintModels.ql
|
||||
- utils/test/InlineExpectationsTestQuery.ql
|
||||
Reference in New Issue
Block a user