Merge pull request #12427 from aschackmull/java/refactor-dataflow-queries-1

Java: Refactor some dataflow queries to the new API
This commit is contained in:
Anders Schack-Mulligen
2023-03-10 14:40:14 +01:00
committed by GitHub
16 changed files with 175 additions and 136 deletions

View File

@@ -8,9 +8,11 @@ import semmle.code.java.dataflow.FlowSources
import semmle.code.java.security.RequestForgery import semmle.code.java.security.RequestForgery
/** /**
* DEPRECATED: Use `RequestForgeryConfiguration` module instead.
*
* A taint-tracking configuration characterising request-forgery risks. * A taint-tracking configuration characterising request-forgery risks.
*/ */
class RequestForgeryConfiguration extends TaintTracking::Configuration { deprecated class RequestForgeryConfiguration extends TaintTracking::Configuration {
RequestForgeryConfiguration() { this = "Server-Side Request Forgery" } RequestForgeryConfiguration() { this = "Server-Side Request Forgery" }
override predicate isSource(DataFlow::Node source) { override predicate isSource(DataFlow::Node source) {
@@ -29,3 +31,26 @@ class RequestForgeryConfiguration extends TaintTracking::Configuration {
override predicate isSanitizer(DataFlow::Node node) { node instanceof RequestForgerySanitizer } override predicate isSanitizer(DataFlow::Node node) { node instanceof RequestForgerySanitizer }
} }
/**
* A taint-tracking configuration characterising request-forgery risks.
*/
private module RequestForgeryConfiguration implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source instanceof RemoteFlowSource and
// Exclude results of remote HTTP requests: fetching something else based on that result
// is no worse than following a redirect returned by the remote server, and typically
// we're requesting a resource via https which we trust to only send us to safe URLs.
not source.asExpr().(MethodAccess).getCallee() instanceof UrlConnectionGetInputStreamMethod
}
predicate isSink(DataFlow::Node sink) { sink instanceof RequestForgerySink }
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
any(RequestForgeryAdditionalTaintStep r).propagatesTaint(pred, succ)
}
predicate isBarrier(DataFlow::Node node) { node instanceof RequestForgerySanitizer }
}
module RequestForgeryFlow = TaintTracking::Make<RequestForgeryConfiguration>;

View File

@@ -25,8 +25,12 @@ private class TypeType extends RefType {
} }
} }
/** A data-flow configuration for identifying potentially-sensitive data flowing to a log output. */ /**
class SensitiveLoggerConfiguration extends TaintTracking::Configuration { * DEPRECATED: Use `SensitiveLoggerConfiguration` module instead.
*
* A data-flow configuration for identifying potentially-sensitive data flowing to a log output.
*/
deprecated class SensitiveLoggerConfiguration extends TaintTracking::Configuration {
SensitiveLoggerConfiguration() { this = "SensitiveLoggerConfiguration" } SensitiveLoggerConfiguration() { this = "SensitiveLoggerConfiguration" }
override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof CredentialExpr } override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof CredentialExpr }
@@ -43,3 +47,22 @@ class SensitiveLoggerConfiguration extends TaintTracking::Configuration {
override predicate isSanitizerIn(Node node) { this.isSource(node) } override predicate isSanitizerIn(Node node) { this.isSource(node) }
} }
/** A data-flow configuration for identifying potentially-sensitive data flowing to a log output. */
private module SensitiveLoggerConfiguration implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof CredentialExpr }
predicate isSink(DataFlow::Node sink) { sinkNode(sink, "logging") }
predicate isBarrier(DataFlow::Node sanitizer) {
sanitizer.asExpr() instanceof LiveLiteral or
sanitizer.getType() instanceof PrimitiveType or
sanitizer.getType() instanceof BoxedType or
sanitizer.getType() instanceof NumberType or
sanitizer.getType() instanceof TypeType
}
predicate isBarrierIn(Node node) { isSource(node) }
}
module SensitiveLoggerFlow = TaintTracking::Make<SensitiveLoggerConfiguration>;

View File

@@ -7,7 +7,7 @@ import semmle.code.java.frameworks.spring.SpringController
import semmle.code.java.frameworks.spring.SpringHttp import semmle.code.java.frameworks.spring.SpringHttp
import semmle.code.java.frameworks.javaee.jsf.JSFRenderer import semmle.code.java.frameworks.javaee.jsf.JSFRenderer
import semmle.code.java.dataflow.DataFlow import semmle.code.java.dataflow.DataFlow
import semmle.code.java.dataflow.TaintTracking2 import semmle.code.java.dataflow.TaintTracking
private import semmle.code.java.dataflow.ExternalFlow private import semmle.code.java.dataflow.ExternalFlow
/** A sink that represent a method that outputs data without applying contextual output encoding. */ /** A sink that represent a method that outputs data without applying contextual output encoding. */
@@ -41,9 +41,9 @@ private class DefaultXssSink extends XssSink {
DefaultXssSink() { DefaultXssSink() {
sinkNode(this, "xss") sinkNode(this, "xss")
or or
exists(XssVulnerableWriterSourceToWritingMethodFlowConfig writer, MethodAccess ma | exists(MethodAccess ma |
ma.getMethod() instanceof WritingMethod and ma.getMethod() instanceof WritingMethod and
writer.hasFlowToExpr(ma.getQualifier()) and XssVulnerableWriterSourceToWritingMethodFlow::hasFlowToExpr(ma.getQualifier()) and
this.asExpr() = ma.getArgument(_) this.asExpr() = ma.getArgument(_)
) )
} }
@@ -60,23 +60,19 @@ private class DefaultXssSanitizer extends XssSanitizer {
} }
/** A configuration that tracks data from a servlet writer to an output method. */ /** A configuration that tracks data from a servlet writer to an output method. */
private class XssVulnerableWriterSourceToWritingMethodFlowConfig extends TaintTracking2::Configuration private module XssVulnerableWriterSourceToWritingMethodFlowConfig implements DataFlow::ConfigSig {
{ predicate isSource(DataFlow::Node src) { src.asExpr() instanceof XssVulnerableWriterSource }
XssVulnerableWriterSourceToWritingMethodFlowConfig() {
this = "XSS::XssVulnerableWriterSourceToWritingMethodFlowConfig"
}
override predicate isSource(DataFlow::Node src) { predicate isSink(DataFlow::Node sink) {
src.asExpr() instanceof XssVulnerableWriterSource
}
override predicate isSink(DataFlow::Node sink) {
exists(MethodAccess ma | exists(MethodAccess ma |
sink.asExpr() = ma.getQualifier() and ma.getMethod() instanceof WritingMethod sink.asExpr() = ma.getQualifier() and ma.getMethod() instanceof WritingMethod
) )
} }
} }
private module XssVulnerableWriterSourceToWritingMethodFlow =
TaintTracking::Make<XssVulnerableWriterSourceToWritingMethodFlowConfig>;
/** A method that can be used to output data to an output stream or writer. */ /** A method that can be used to output data to an output stream or writer. */
private class WritingMethod extends Method { private class WritingMethod extends Method {
WritingMethod() { WritingMethod() {

View File

@@ -18,32 +18,33 @@ import semmle.code.java.dataflow.FlowSources
private import semmle.code.java.dataflow.ExternalFlow private import semmle.code.java.dataflow.ExternalFlow
import semmle.code.java.security.PathCreation import semmle.code.java.security.PathCreation
import semmle.code.java.security.PathSanitizer import semmle.code.java.security.PathSanitizer
import DataFlow::PathGraph
import TaintedPathCommon import TaintedPathCommon
class TaintedPathConfig extends TaintTracking::Configuration { module TaintedPathConfig implements DataFlow::ConfigSig {
TaintedPathConfig() { this = "TaintedPathConfig" } predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } predicate isSink(DataFlow::Node sink) {
override predicate isSink(DataFlow::Node sink) {
sink.asExpr() = any(PathCreation p).getAnInput() sink.asExpr() = any(PathCreation p).getAnInput()
or or
sinkNode(sink, ["create-file", "read-file"]) sinkNode(sink, ["create-file", "read-file"])
} }
override predicate isSanitizer(DataFlow::Node sanitizer) { predicate isBarrier(DataFlow::Node sanitizer) {
sanitizer.getType() instanceof BoxedType or sanitizer.getType() instanceof BoxedType or
sanitizer.getType() instanceof PrimitiveType or sanitizer.getType() instanceof PrimitiveType or
sanitizer.getType() instanceof NumberType or sanitizer.getType() instanceof NumberType or
sanitizer instanceof PathInjectionSanitizer sanitizer instanceof PathInjectionSanitizer
} }
override predicate isAdditionalTaintStep(DataFlow::Node n1, DataFlow::Node n2) { predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
any(TaintedPathAdditionalTaintStep s).step(n1, n2) any(TaintedPathAdditionalTaintStep s).step(n1, n2)
} }
} }
module TaintedPath = TaintTracking::Make<TaintedPathConfig>;
import TaintedPath::PathGraph
/** /**
* Gets the data-flow node at which to report a path ending at `sink`. * Gets the data-flow node at which to report a path ending at `sink`.
* *
@@ -52,13 +53,13 @@ class TaintedPathConfig extends TaintTracking::Configuration {
* continue to report there; otherwise we report directly at `sink`. * continue to report there; otherwise we report directly at `sink`.
*/ */
DataFlow::Node getReportingNode(DataFlow::Node sink) { DataFlow::Node getReportingNode(DataFlow::Node sink) {
any(TaintedPathConfig c).hasFlowTo(sink) and TaintedPath::hasFlowTo(sink) and
if exists(PathCreation pc | pc.getAnInput() = sink.asExpr()) if exists(PathCreation pc | pc.getAnInput() = sink.asExpr())
then result.asExpr() = any(PathCreation pc | pc.getAnInput() = sink.asExpr()) then result.asExpr() = any(PathCreation pc | pc.getAnInput() = sink.asExpr())
else result = sink else result = sink
} }
from DataFlow::PathNode source, DataFlow::PathNode sink, TaintedPathConfig conf from TaintedPath::PathNode source, TaintedPath::PathNode sink
where conf.hasFlowPath(source, sink) where TaintedPath::hasFlowPath(source, sink)
select getReportingNode(sink.getNode()), source, sink, "This path depends on a $@.", select getReportingNode(sink.getNode()), source, sink, "This path depends on a $@.",
source.getNode(), "user-provided value" source.getNode(), "user-provided value"

View File

@@ -14,25 +14,26 @@
import java import java
import semmle.code.java.dataflow.FlowSources import semmle.code.java.dataflow.FlowSources
import semmle.code.java.security.XSS import semmle.code.java.security.XSS
import DataFlow::PathGraph
class XssConfig extends TaintTracking::Configuration { module XssConfig implements DataFlow::ConfigSig {
XssConfig() { this = "XSSConfig" } predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } predicate isSink(DataFlow::Node sink) { sink instanceof XssSink }
override predicate isSink(DataFlow::Node sink) { sink instanceof XssSink } predicate isBarrier(DataFlow::Node node) { node instanceof XssSanitizer }
override predicate isSanitizer(DataFlow::Node node) { node instanceof XssSanitizer } predicate isBarrierOut(DataFlow::Node node) { node instanceof XssSinkBarrier }
override predicate isSanitizerOut(DataFlow::Node node) { node instanceof XssSinkBarrier } predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
any(XssAdditionalTaintStep s).step(node1, node2) any(XssAdditionalTaintStep s).step(node1, node2)
} }
} }
from DataFlow::PathNode source, DataFlow::PathNode sink, XssConfig conf module XssFlow = TaintTracking::Make<XssConfig>;
where conf.hasFlowPath(source, sink)
import XssFlow::PathGraph
from XssFlow::PathNode source, XssFlow::PathNode sink
where XssFlow::hasFlowPath(source, sink)
select sink.getNode(), source, sink, "Cross-site scripting vulnerability due to a $@.", select sink.getNode(), source, sink, "Cross-site scripting vulnerability due to a $@.",
source.getNode(), "user-provided value" source.getNode(), "user-provided value"

View File

@@ -14,19 +14,16 @@
import java import java
import semmle.code.java.dataflow.FlowSources import semmle.code.java.dataflow.FlowSources
import semmle.code.java.security.ResponseSplitting import semmle.code.java.security.ResponseSplitting
import DataFlow::PathGraph
class ResponseSplittingConfig extends TaintTracking::Configuration { module ResponseSplittingConfig implements DataFlow::ConfigSig {
ResponseSplittingConfig() { this = "ResponseSplittingConfig" } predicate isSource(DataFlow::Node source) {
override predicate isSource(DataFlow::Node source) {
source instanceof RemoteFlowSource and source instanceof RemoteFlowSource and
not source instanceof SafeHeaderSplittingSource not source instanceof SafeHeaderSplittingSource
} }
override predicate isSink(DataFlow::Node sink) { sink instanceof HeaderSplittingSink } predicate isSink(DataFlow::Node sink) { sink instanceof HeaderSplittingSink }
override predicate isSanitizer(DataFlow::Node node) { predicate isBarrier(DataFlow::Node node) {
node.getType() instanceof PrimitiveType node.getType() instanceof PrimitiveType
or or
node.getType() instanceof BoxedType node.getType() instanceof BoxedType
@@ -45,8 +42,12 @@ class ResponseSplittingConfig extends TaintTracking::Configuration {
} }
} }
from DataFlow::PathNode source, DataFlow::PathNode sink, ResponseSplittingConfig conf module ResponseSplitting = TaintTracking::Make<ResponseSplittingConfig>;
where conf.hasFlowPath(source, sink)
import ResponseSplitting::PathGraph
from ResponseSplitting::PathNode source, ResponseSplitting::PathNode sink
where ResponseSplitting::hasFlowPath(source, sink)
select sink.getNode(), source, sink, select sink.getNode(), source, sink,
"This header depends on a $@, which may cause a response-splitting vulnerability.", "This header depends on a $@, which may cause a response-splitting vulnerability.",
source.getNode(), "user-provided value" source.getNode(), "user-provided value"

View File

@@ -14,23 +14,24 @@
import java import java
import semmle.code.java.dataflow.FlowSources import semmle.code.java.dataflow.FlowSources
import semmle.code.java.security.ResponseSplitting import semmle.code.java.security.ResponseSplitting
import DataFlow::PathGraph
class ResponseSplittingLocalConfig extends TaintTracking::Configuration { module ResponseSplittingLocalConfig implements DataFlow::ConfigSig {
ResponseSplittingLocalConfig() { this = "ResponseSplittingLocalConfig" } predicate isSource(DataFlow::Node source) { source instanceof LocalUserInput }
override predicate isSource(DataFlow::Node source) { source instanceof LocalUserInput } predicate isSink(DataFlow::Node sink) { sink instanceof HeaderSplittingSink }
override predicate isSink(DataFlow::Node sink) { sink instanceof HeaderSplittingSink } predicate isBarrier(DataFlow::Node node) {
override predicate isSanitizer(DataFlow::Node node) {
node.getType() instanceof PrimitiveType or node.getType() instanceof PrimitiveType or
node.getType() instanceof BoxedType node.getType() instanceof BoxedType
} }
} }
from DataFlow::PathNode source, DataFlow::PathNode sink, ResponseSplittingLocalConfig conf module ResponseSplitting = TaintTracking::Make<ResponseSplittingLocalConfig>;
where conf.hasFlowPath(source, sink)
import ResponseSplitting::PathGraph
from ResponseSplitting::PathNode source, ResponseSplitting::PathNode sink
where ResponseSplitting::hasFlowPath(source, sink)
select sink.getNode(), source, sink, select sink.getNode(), source, sink,
"This header depends on a $@, which may cause a response-splitting vulnerability.", "This header depends on a $@, which may cause a response-splitting vulnerability.",
source.getNode(), "user-provided value" source.getNode(), "user-provided value"

View File

@@ -31,33 +31,27 @@ class PrintStackTraceMethod extends Method {
} }
} }
class ServletWriterSourceToPrintStackTraceMethodFlowConfig extends TaintTracking::Configuration { module ServletWriterSourceToPrintStackTraceMethodFlowConfig implements DataFlow::ConfigSig {
ServletWriterSourceToPrintStackTraceMethodFlowConfig() { predicate isSource(DataFlow::Node src) { src.asExpr() instanceof XssVulnerableWriterSource }
this = "StackTraceExposure::ServletWriterSourceToPrintStackTraceMethodFlowConfig"
}
override predicate isSource(DataFlow::Node src) { predicate isSink(DataFlow::Node sink) {
src.asExpr() instanceof XssVulnerableWriterSource
}
override predicate isSink(DataFlow::Node sink) {
exists(MethodAccess ma | exists(MethodAccess ma |
sink.asExpr() = ma.getAnArgument() and ma.getMethod() instanceof PrintStackTraceMethod sink.asExpr() = ma.getAnArgument() and ma.getMethod() instanceof PrintStackTraceMethod
) )
} }
} }
module ServletWriterSourceToPrintStackTraceMethodFlow =
TaintTracking::Make<ServletWriterSourceToPrintStackTraceMethodFlowConfig>;
/** /**
* A call that uses `Throwable.printStackTrace()` on a stream that is connected * A call that uses `Throwable.printStackTrace()` on a stream that is connected
* to external output. * to external output.
*/ */
predicate printsStackToWriter(MethodAccess call) { predicate printsStackToWriter(MethodAccess call) {
exists( exists(PrintStackTraceMethod printStackTrace |
ServletWriterSourceToPrintStackTraceMethodFlowConfig writerSource,
PrintStackTraceMethod printStackTrace
|
call.getMethod() = printStackTrace and call.getMethod() = printStackTrace and
writerSource.hasFlowToExpr(call.getAnArgument()) ServletWriterSourceToPrintStackTraceMethodFlow::hasFlowToExpr(call.getAnArgument())
) )
} }
@@ -86,16 +80,15 @@ predicate stackTraceExpr(Expr exception, MethodAccess stackTraceString) {
) )
} }
class StackTraceStringToHttpResponseSinkFlowConfig extends TaintTracking::Configuration { module StackTraceStringToHttpResponseSinkFlowConfig implements DataFlow::ConfigSig {
StackTraceStringToHttpResponseSinkFlowConfig() { predicate isSource(DataFlow::Node src) { stackTraceExpr(_, src.asExpr()) }
this = "StackTraceExposure::StackTraceStringToHttpResponseSinkFlowConfig"
}
override predicate isSource(DataFlow::Node src) { stackTraceExpr(_, src.asExpr()) } predicate isSink(DataFlow::Node sink) { sink instanceof InformationLeakSink }
override predicate isSink(DataFlow::Node sink) { sink instanceof InformationLeakSink }
} }
module StackTraceStringToHttpResponseSinkFlow =
TaintTracking::Make<StackTraceStringToHttpResponseSinkFlowConfig>;
/** /**
* A write of stack trace data to an external stream. * A write of stack trace data to an external stream.
*/ */
@@ -109,9 +102,10 @@ predicate printsStackExternally(MethodAccess call, Expr stackTrace) {
* A stringified stack trace flows to an external sink. * A stringified stack trace flows to an external sink.
*/ */
predicate stringifiedStackFlowsExternally(DataFlow::Node externalExpr, Expr stackTrace) { predicate stringifiedStackFlowsExternally(DataFlow::Node externalExpr, Expr stackTrace) {
exists(MethodAccess stackTraceString, StackTraceStringToHttpResponseSinkFlowConfig conf | exists(MethodAccess stackTraceString |
stackTraceExpr(stackTrace, stackTraceString) and stackTraceExpr(stackTrace, stackTraceString) and
conf.hasFlow(DataFlow::exprNode(stackTraceString), externalExpr) StackTraceStringToHttpResponseSinkFlow::hasFlow(DataFlow::exprNode(stackTraceString),
externalExpr)
) )
} }

View File

@@ -15,7 +15,6 @@ import java
import semmle.code.java.security.Encryption import semmle.code.java.security.Encryption
import semmle.code.java.dataflow.TaintTracking import semmle.code.java.dataflow.TaintTracking
import DataFlow import DataFlow
import PathGraph
private class ShortStringLiteral extends StringLiteral { private class ShortStringLiteral extends StringLiteral {
ShortStringLiteral() { getValue().length() < 100 } ShortStringLiteral() { getValue().length() < 100 }
@@ -29,24 +28,26 @@ class BrokenAlgoLiteral extends ShortStringLiteral {
} }
} }
class InsecureCryptoConfiguration extends TaintTracking::Configuration { module InsecureCryptoConfiguration implements ConfigSig {
InsecureCryptoConfiguration() { this = "BrokenCryptoAlgortihm::InsecureCryptoConfiguration" } predicate isSource(Node n) { n.asExpr() instanceof BrokenAlgoLiteral }
override predicate isSource(Node n) { n.asExpr() instanceof BrokenAlgoLiteral } predicate isSink(Node n) { exists(CryptoAlgoSpec c | n.asExpr() = c.getAlgoSpec()) }
override predicate isSink(Node n) { exists(CryptoAlgoSpec c | n.asExpr() = c.getAlgoSpec()) } predicate isBarrier(DataFlow::Node node) {
override predicate isSanitizer(DataFlow::Node node) {
node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType
} }
} }
module InsecureCryptoFlow = TaintTracking::Make<InsecureCryptoConfiguration>;
import InsecureCryptoFlow::PathGraph
from from
PathNode source, PathNode sink, CryptoAlgoSpec c, BrokenAlgoLiteral s, InsecureCryptoFlow::PathNode source, InsecureCryptoFlow::PathNode sink, CryptoAlgoSpec c,
InsecureCryptoConfiguration conf BrokenAlgoLiteral s
where where
sink.getNode().asExpr() = c.getAlgoSpec() and sink.getNode().asExpr() = c.getAlgoSpec() and
source.getNode().asExpr() = s and source.getNode().asExpr() = s and
conf.hasFlowPath(source, sink) InsecureCryptoFlow::hasFlowPath(source, sink)
select c, source, sink, "Cryptographic algorithm $@ is weak and should not be used.", s, select c, source, sink, "Cryptographic algorithm $@ is weak and should not be used.", s,
s.getValue() s.getValue()

View File

@@ -16,7 +16,6 @@ import semmle.code.java.security.Encryption
import semmle.code.java.dataflow.TaintTracking import semmle.code.java.dataflow.TaintTracking
import DataFlow import DataFlow
import semmle.code.java.dispatch.VirtualDispatch import semmle.code.java.dispatch.VirtualDispatch
import PathGraph
private class ShortStringLiteral extends StringLiteral { private class ShortStringLiteral extends StringLiteral {
ShortStringLiteral() { this.getValue().length() < 100 } ShortStringLiteral() { this.getValue().length() < 100 }
@@ -51,26 +50,28 @@ class StringContainer extends RefType {
} }
} }
class InsecureCryptoConfiguration extends TaintTracking::Configuration { module InsecureCryptoConfiguration implements ConfigSig {
InsecureCryptoConfiguration() { this = "InsecureCryptoConfiguration" } predicate isSource(Node n) { n.asExpr() instanceof InsecureAlgoLiteral }
override predicate isSource(Node n) { n.asExpr() instanceof InsecureAlgoLiteral } predicate isSink(Node n) { exists(CryptoAlgoSpec c | n.asExpr() = c.getAlgoSpec()) }
override predicate isSink(Node n) { exists(CryptoAlgoSpec c | n.asExpr() = c.getAlgoSpec()) } predicate isBarrier(Node n) {
override predicate isSanitizer(Node n) {
objectToString(n.asExpr()) or objectToString(n.asExpr()) or
not n.getType().getErasure() instanceof StringContainer not n.getType().getErasure() instanceof StringContainer
} }
} }
module InsecureCryptoFlow = TaintTracking::Make<InsecureCryptoConfiguration>;
import InsecureCryptoFlow::PathGraph
from from
PathNode source, PathNode sink, CryptoAlgoSpec c, InsecureAlgoLiteral s, InsecureCryptoFlow::PathNode source, InsecureCryptoFlow::PathNode sink, CryptoAlgoSpec c,
InsecureCryptoConfiguration conf InsecureAlgoLiteral s
where where
sink.getNode().asExpr() = c.getAlgoSpec() and sink.getNode().asExpr() = c.getAlgoSpec() and
source.getNode().asExpr() = s and source.getNode().asExpr() = s and
conf.hasFlowPath(source, sink) InsecureCryptoFlow::hasFlowPath(source, sink)
select c, source, sink, select c, source, sink,
"Cryptographic algorithm $@ may not be secure, consider using a different algorithm.", s, "Cryptographic algorithm $@ may not be secure, consider using a different algorithm.", s,
s.getValue() s.getValue()

View File

@@ -13,9 +13,9 @@
import java import java
import semmle.code.java.security.SensitiveLoggingQuery import semmle.code.java.security.SensitiveLoggingQuery
import PathGraph import SensitiveLoggerFlow::PathGraph
from SensitiveLoggerConfiguration cfg, DataFlow::PathNode source, DataFlow::PathNode sink from SensitiveLoggerFlow::PathNode source, SensitiveLoggerFlow::PathNode sink
where cfg.hasFlowPath(source, sink) where SensitiveLoggerFlow::hasFlowPath(source, sink)
select sink.getNode(), source, sink, "This $@ is written to a log file.", source.getNode(), select sink.getNode(), source, sink, "This $@ is written to a log file.", source.getNode(),
"potentially sensitive information" "potentially sensitive information"

View File

@@ -15,19 +15,16 @@
import java import java
import semmle.code.java.dataflow.FlowSources import semmle.code.java.dataflow.FlowSources
import NumericCastCommon import NumericCastCommon
import DataFlow::PathGraph
private class NumericCastFlowConfig extends TaintTracking::Configuration { module NumericCastFlowConfig implements DataFlow::ConfigSig {
NumericCastFlowConfig() { this = "NumericCastTainted::RemoteUserInputToNumericNarrowingCastExpr" } predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource } predicate isSink(DataFlow::Node sink) {
override predicate isSink(DataFlow::Node sink) {
sink.asExpr() = any(NumericNarrowingCastExpr cast).getExpr() and sink.asExpr() = any(NumericNarrowingCastExpr cast).getExpr() and
sink.asExpr() instanceof VarAccess sink.asExpr() instanceof VarAccess
} }
override predicate isSanitizer(DataFlow::Node node) { predicate isBarrier(DataFlow::Node node) {
boundedRead(node.asExpr()) or boundedRead(node.asExpr()) or
castCheck(node.asExpr()) or castCheck(node.asExpr()) or
node.getType() instanceof SmallType or node.getType() instanceof SmallType or
@@ -37,12 +34,14 @@ private class NumericCastFlowConfig extends TaintTracking::Configuration {
} }
} }
from module NumericCastFlow = TaintTracking::Make<NumericCastFlowConfig>;
DataFlow::PathNode source, DataFlow::PathNode sink, NumericNarrowingCastExpr exp,
NumericCastFlowConfig conf import NumericCastFlow::PathGraph
from NumericCastFlow::PathNode source, NumericCastFlow::PathNode sink, NumericNarrowingCastExpr exp
where where
sink.getNode().asExpr() = exp.getExpr() and sink.getNode().asExpr() = exp.getExpr() and
conf.hasFlowPath(source, sink) NumericCastFlow::hasFlowPath(source, sink)
select exp, source, sink, select exp, source, sink,
"This cast to a narrower type depends on a $@, potentially causing truncation.", source.getNode(), "This cast to a narrower type depends on a $@, potentially causing truncation.", source.getNode(),
"user-provided value" "user-provided value"

View File

@@ -15,20 +15,15 @@
import java import java
import semmle.code.java.dataflow.FlowSources import semmle.code.java.dataflow.FlowSources
import NumericCastCommon import NumericCastCommon
import DataFlow::PathGraph
private class NumericCastFlowConfig extends TaintTracking::Configuration { module NumericCastFlowConfig implements DataFlow::ConfigSig {
NumericCastFlowConfig() { predicate isSource(DataFlow::Node src) { src instanceof LocalUserInput }
this = "NumericCastTaintedLocal::LocalUserInputToNumericNarrowingCastExpr"
}
override predicate isSource(DataFlow::Node src) { src instanceof LocalUserInput } predicate isSink(DataFlow::Node sink) {
override predicate isSink(DataFlow::Node sink) {
sink.asExpr() = any(NumericNarrowingCastExpr cast).getExpr() sink.asExpr() = any(NumericNarrowingCastExpr cast).getExpr()
} }
override predicate isSanitizer(DataFlow::Node node) { predicate isBarrier(DataFlow::Node node) {
boundedRead(node.asExpr()) or boundedRead(node.asExpr()) or
castCheck(node.asExpr()) or castCheck(node.asExpr()) or
node.getType() instanceof SmallType or node.getType() instanceof SmallType or
@@ -37,13 +32,17 @@ private class NumericCastFlowConfig extends TaintTracking::Configuration {
} }
} }
module NumericCastFlow = TaintTracking::Make<NumericCastFlowConfig>;
import NumericCastFlow::PathGraph
from from
DataFlow::PathNode source, DataFlow::PathNode sink, NumericNarrowingCastExpr exp, NumericCastFlow::PathNode source, NumericCastFlow::PathNode sink, NumericNarrowingCastExpr exp,
VarAccess tainted, NumericCastFlowConfig conf VarAccess tainted
where where
exp.getExpr() = tainted and exp.getExpr() = tainted and
sink.getNode().asExpr() = tainted and sink.getNode().asExpr() = tainted and
conf.hasFlowPath(source, sink) and NumericCastFlow::hasFlowPath(source, sink) and
not exists(RightShiftOp e | e.getShiftedVariable() = tainted.getVariable()) not exists(RightShiftOp e | e.getShiftedVariable() = tainted.getVariable())
select exp, source, sink, select exp, source, sink,
"This cast to a narrower type depends on a $@, potentially causing truncation.", source.getNode(), "This cast to a narrower type depends on a $@, potentially causing truncation.", source.getNode(),

View File

@@ -13,9 +13,9 @@
import java import java
import semmle.code.java.security.RequestForgeryConfig import semmle.code.java.security.RequestForgeryConfig
import DataFlow::PathGraph import RequestForgeryFlow::PathGraph
from DataFlow::PathNode source, DataFlow::PathNode sink, RequestForgeryConfiguration conf from RequestForgeryFlow::PathNode source, RequestForgeryFlow::PathNode sink
where conf.hasFlowPath(source, sink) where RequestForgeryFlow::hasFlowPath(source, sink)
select sink.getNode(), source, sink, "Potential server-side request forgery due to a $@.", select sink.getNode(), source, sink, "Potential server-side request forgery due to a $@.",
source.getNode(), "user-provided value" source.getNode(), "user-provided value"

View File

@@ -2,14 +2,10 @@ import java
import TestUtilities.InlineFlowTest import TestUtilities.InlineFlowTest
import semmle.code.java.security.SensitiveLoggingQuery import semmle.code.java.security.SensitiveLoggingQuery
class EnableLegacy extends EnableLegacyConfiguration {
EnableLegacy() { exists(this) }
}
class HasFlowTest extends InlineFlowTest { class HasFlowTest extends InlineFlowTest {
override DataFlow::Configuration getTaintFlowConfig() { override predicate hasTaintFlow(DataFlow::Node src, DataFlow::Node sink) {
result instanceof SensitiveLoggerConfiguration SensitiveLoggerFlow::hasFlow(src, sink)
} }
override DataFlow::Configuration getValueFlowConfig() { none() } override predicate hasValueFlow(DataFlow::Node src, DataFlow::Node sink) { none() }
} }

View File

@@ -9,7 +9,8 @@ class HasFlowTest extends InlineExpectationsTest {
override predicate hasActualResult(Location location, string element, string tag, string value) { override predicate hasActualResult(Location location, string element, string tag, string value) {
tag = "SSRF" and tag = "SSRF" and
exists(RequestForgeryConfiguration conf, DataFlow::Node sink | conf.hasFlowTo(sink) | exists(DataFlow::Node sink |
RequestForgeryFlow::hasFlowTo(sink) and
sink.getLocation() = location and sink.getLocation() = location and
element = sink.toString() and element = sink.toString() and
value = "" value = ""