mirror of
https://github.com/github/codeql.git
synced 2026-05-01 19:55:15 +02:00
add qldoc and customizations module
This commit is contained in:
@@ -11,59 +11,30 @@
|
||||
* external/cwe/cwe-116
|
||||
*/
|
||||
|
||||
// TODO: Proper customizations module, Source class Sink class etc. and qldoc.
|
||||
import javascript
|
||||
import semmle.javascript.security.dataflow.ImproperCodeSanitization::ImproperCodeSanitization
|
||||
import DataFlow::PathGraph
|
||||
private import semmle.javascript.heuristics.HeuristicSinks
|
||||
private import semmle.javascript.security.dataflow.CodeInjectionCustomizations
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for reasoning about improper code sanitization vulnerabilities.
|
||||
* Gets a type-tracked instance of `RemoteFlowSource` using type-tracker `t`.
|
||||
*/
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "ImproperCodeSanitization" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source = source() }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink = sink() }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node sanitizer) {
|
||||
sanitizer instanceof StringReplaceCall // any string-replace that happens after the bad-sanitizer, is assumed to be a good sanitizer.
|
||||
// TODO: Specialize? This regexp sanitizes: /[<>\b\f\n\r\t\0\u2028\u2029]/g
|
||||
}
|
||||
}
|
||||
|
||||
private DataFlow::CallNode source() {
|
||||
result instanceof HtmlSanitizerCall
|
||||
or
|
||||
result = DataFlow::globalVarRef("JSON").getAMemberCall("stringify")
|
||||
}
|
||||
|
||||
private StringOps::ConcatenationLeaf sink() {
|
||||
exists(StringOps::ConcatenationRoot root, int i |
|
||||
root.getOperand(i) = result and
|
||||
not exists(result.getStringValue())
|
||||
|
|
||||
exists(StringOps::ConcatenationLeaf functionLeaf |
|
||||
functionLeaf = root.getOperand(any(int j | j < i))
|
||||
|
|
||||
functionLeaf
|
||||
.getStringValue()
|
||||
.regexpMatch([".*function( )?([a-zA-Z0-9]+)?( )?\\(.*", ".*eval\\(.*",
|
||||
".*new Function\\(.*", "(^|.*[^a-zA-Z0-9])\\(.*\\)( )?=>.*"])
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
DataFlow::SourceNode remoteFlow(DataFlow::TypeTracker t) {
|
||||
private DataFlow::SourceNode remoteFlow(DataFlow::TypeTracker t) {
|
||||
t.start() and
|
||||
result instanceof RemoteFlowSource
|
||||
or
|
||||
exists(DataFlow::TypeTracker t2 | result = remoteFlow(t2).track(t2, t))
|
||||
}
|
||||
|
||||
DataFlow::SourceNode remoteFlow() { result = remoteFlow(DataFlow::TypeTracker::end()) }
|
||||
/**
|
||||
* Gets a type-tracked reference to a `RemoteFlowSource`.
|
||||
*/
|
||||
private DataFlow::SourceNode remoteFlow() { result = remoteFlow(DataFlow::TypeTracker::end()) }
|
||||
|
||||
/**
|
||||
* Gets a type-back-tracked instance of a code-injection sink using type-tracker `t`.
|
||||
*/
|
||||
private DataFlow::Node endsInCodeInjectionSink(DataFlow::TypeBackTracker t) {
|
||||
t.start() and
|
||||
(
|
||||
@@ -76,9 +47,11 @@ private DataFlow::Node endsInCodeInjectionSink(DataFlow::TypeBackTracker t) {
|
||||
exists(DataFlow::TypeBackTracker t2 | t = t2.smallstep(result, endsInCodeInjectionSink(t2)))
|
||||
}
|
||||
|
||||
DataFlow::Node endsInCodeInjectionSink() {
|
||||
result = endsInCodeInjectionSink(DataFlow::TypeBackTracker::end()) and
|
||||
result.getFile().getBaseName() = "bad-code-sanitization.js" // TODO: TMp
|
||||
/**
|
||||
* Gets a reference to to a data-flow node that ends in a code-injection sink.
|
||||
*/
|
||||
private DataFlow::Node endsInCodeInjectionSink() {
|
||||
result = endsInCodeInjectionSink(DataFlow::TypeBackTracker::end())
|
||||
}
|
||||
|
||||
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Provides a taint-tracking configuration for reasoning about improper code
|
||||
* sanitization.
|
||||
*
|
||||
* Note, for performance reasons: only import this file if
|
||||
* `ImproperCodeSanitization::Configuration` is needed, otherwise
|
||||
* `ImproperCodeSanitizationCustomizations` should be imported instead.
|
||||
*/
|
||||
|
||||
import javascript
|
||||
|
||||
module ImproperCodeSanitization {
|
||||
import ImproperCodeSanitizationCustomizations::ImproperCodeSanitization
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for reasoning about improper code sanitization vulnerabilities.
|
||||
*/
|
||||
class Configuration extends TaintTracking::Configuration {
|
||||
Configuration() { this = "ImproperCodeSanitization" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node sanitizer) { sanitizer instanceof Sanitizer }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Provides default sources, sinks and sanitizers for reasoning about
|
||||
* improper code sanitization, as well as extension points for
|
||||
* adding your own.
|
||||
*/
|
||||
|
||||
import javascript
|
||||
|
||||
module ImproperCodeSanitization {
|
||||
/**
|
||||
* A data flow source for improper code sanitization.
|
||||
*/
|
||||
abstract class Source extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A data flow sink for improper code sanitization.
|
||||
*/
|
||||
abstract class Sink extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A sanitizer for improper code sanitization.
|
||||
*/
|
||||
abstract class Sanitizer extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A call to a HTML sanitizer seen as a source for improper code sanitization
|
||||
*/
|
||||
class HtmlSanitizerCallAsSource extends Source {
|
||||
HtmlSanitizerCallAsSource() { this instanceof HtmlSanitizerCall }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `JSON.stringify()` seen as a source for improper code sanitization
|
||||
*/
|
||||
class JSONStringifyAsSource extends Source {
|
||||
JSONStringifyAsSource() { this = DataFlow::globalVarRef("JSON").getAMemberCall("stringify") }
|
||||
}
|
||||
|
||||
/**
|
||||
* A leaf in a string-concatenation, where the string-concatenation constructs code that looks like a function.
|
||||
*/
|
||||
class FunctionStringConstruction extends Sink, StringOps::ConcatenationLeaf {
|
||||
FunctionStringConstruction() {
|
||||
exists(StringOps::ConcatenationRoot root, int i |
|
||||
root.getOperand(i) = this and
|
||||
not exists(this.getStringValue())
|
||||
|
|
||||
exists(StringOps::ConcatenationLeaf functionLeaf |
|
||||
functionLeaf = root.getOperand(any(int j | j < i))
|
||||
|
|
||||
functionLeaf
|
||||
.getStringValue()
|
||||
.regexpMatch([".*function( )?([a-zA-Z0-9]+)?( )?\\(.*", ".*eval\\(.*",
|
||||
".*new Function\\(.*", "(^|.*[^a-zA-Z0-9])\\(.*\\)( )?=>.*"])
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `String.prototype.replace` seen as a sanitizer for improper code sanitization.
|
||||
* All calls to replace that happens after the initial improper sanitization is seen as a sanitizer.
|
||||
*/
|
||||
class StringReplaceCallAsSanitizer extends Sanitizer, StringReplaceCall { }
|
||||
}
|
||||
Reference in New Issue
Block a user