Description
Hello, I am currently trying to create a query that will allow me to determine whether a servlet message contains sensitive information.
import java
import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.frameworks.Servlets
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.dataflow.DataFlow
import CommonSinks.CommonSinks
import SensitiveInfo.SensitiveInfo
module Flow = TaintTracking::Global<SensitiveInfoLeakServletConfig>;
import Flow::PathGraph
module SensitiveInfoLeakServletConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
exists(SensitiveVariableExpr sve | source.asExpr() = sve) // Assume this has a list of sensitive variables in a file
or exists(CatchClause cc, MethodCall mc | mc.getQualifier() = cc.getVariable().getAnAccess() and source.asExpr() = mc)
}
predicate isSink(DataFlow::Node sink) {
// Consider the case where the sink exposes sensitive info within a catch clause of type ServletException
exists(CatchClause cc, MethodCall mc |
// Ensure the CatchClause is catching ServletException
cc.getACaughtType().hasQualifiedName("javax.servlet", "ServletException") and
// Ensure the MethodCall is within the CatchClause for the ServletException
mc.getEnclosingStmt().getEnclosingStmt*() = cc.getBlock() and
// Ensure the sink matches one of the known sensitive sinks
(
getSinkAny(sink)
) and
// Link the sink to the argument of the MethodCall
sink.asExpr() = mc.getAnArgument()
)
}
}
from Flow::PathNode source, Flow::PathNode sink
where Flow::flowPath(source, sink)
select sink.getNode(), source, sink,
"Servlet Runtime Error Message Containing Sensitive Information."
I almost have this working, however, the issue that I am having has to do with false positives.
Say I have this code
throw new ServletException("Invalid database connection parameters" + dbUrl + dbUser + dbPass);
} catch (ServletException e) {
// Catch the ServletException and send an error response
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "An error occurred while processing the request: " + e.getMessage());
}
In this example, there is sensitive information (dbUrl + dbUser + dbPass) in the e.getMessage() so this would be valid.
However, say we change it to
throw new ServletException("Invalid database connection parameters");
} catch (ServletException e) {
// Catch the ServletException and send an error response
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "An error occurred while processing the request: " + e.getMessage());
}
Now we no longer have sensitive information exposed. However, I am still detecting this. I believe this issue is in this line.
exists(CatchClause cc, MethodCall mc | mc.getQualifier() = cc.getVariable().getAnAccess() and source.asExpr() = mc)
Without it, I don't detect any usages of e.getMessage(), but with it, I detect all of them. When I only want to detect them with sensitive information in them. I believe this should be moved to the isSink check, however, I am not sure how to integrate it.
I appreciate any help, thank you.