Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Java: add CSRF query #18288

Merged
merged 38 commits into from
Feb 11, 2025
Merged
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
0c69253
Java: add qhelp
Dec 16, 2024
506d668
Java: add class for Spring request mapping methods that are not defau…
Nov 27, 2024
8e9f21d
Java: add a class for MyBatis Mapper methods that update a database
Nov 27, 2024
b88731d
Java: move contents of MyBatisMapperXML.qll in src to MyBatis.qll in …
Nov 27, 2024
43a2880
Java: add a class for PreparedStatement methods that update a database
Nov 27, 2024
87a8746
Java: add a class for methods that update a sql database (found using…
Nov 27, 2024
c553e31
Java: add CallGraph module for displaying call graph paths
Nov 27, 2024
178b032
Java: add query
Nov 27, 2024
df77d49
Java: initial tests
Dec 3, 2024
97aaf4c
Java: handle MyBatis annotations for insert/update/delete
Dec 4, 2024
0f39011
Java: add taint-tracking config for execute to exclude FPs from non-u…
Dec 12, 2024
286c655
Java: add class for Stapler web methods that are not default-protecte…
Dec 13, 2024
39ccde0
Java: add name-based heuristic
Dec 16, 2024
c9ad15c
Java: update .expected file contents
Dec 16, 2024
48d1fe0
Java: remove exists variable
Dec 16, 2024
ede9e78
Java: remove exists variable in test
Dec 16, 2024
48d55ec
Java: performance fix
Dec 16, 2024
fa27689
Java: update InlineExpectationsTest import for new location
Dec 16, 2024
27aa9c9
Java: add change note
Dec 16, 2024
26b7c1a
Java: qldocs for CallGraph module
Dec 17, 2024
3bf6dc2
Java: Stapler tests and stubs
Dec 18, 2024
0ab3768
Java: more database update tests and stubs
Dec 18, 2024
d4114f6
Java: more name-based heuristic tests to test regex
Dec 19, 2024
20e8eb4
Java: some clean-up and refactoring
Dec 20, 2024
0462425
Java: rename getMethod to getMethodValue
Jan 8, 2025
8173fd0
Java: use two negations
Jan 8, 2025
530a77e
Java: refactor into canTargetDatabaseUpdateMethod
Jan 8, 2025
f3721eb
Java: refactor unprotectedDatabaseUpdate
Jan 8, 2025
096f6f8
Java: precision to medium
Jan 21, 2025
ead224c
Java: expand qhelp, include Stapler examples
Jan 24, 2025
530103e
Java: narrow query
Jan 30, 2025
577152e
Java: minor qhelp update
Jan 30, 2025
0071e1a
Java: resolve merge conflict
Jan 30, 2025
516df3b
Java: qhelp wording updates
Feb 3, 2025
283c3b1
Java: minor qhelp updates
Feb 4, 2025
f438282
Java: rewrite qhelp overview section; aligns with overview section us…
Feb 4, 2025
0367846
Java: remove token section from qhelp overview
Feb 4, 2025
c6a71cd
Java: minor qhelp updates
Feb 5, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions java/ql/lib/semmle/code/java/frameworks/Jdbc.qll
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,19 @@ class ResultSetGetStringMethod extends Method {
this.getReturnType() instanceof TypeString
}
}

/** A method with the name `executeUpdate` declared in `java.sql.PreparedStatement`. */
class PreparedStatementExecuteUpdateMethod extends Method {
PreparedStatementExecuteUpdateMethod() {
this.getDeclaringType() instanceof TypePreparedStatement and
this.hasName("executeUpdate")
}
}

/** A method with the name `executeLargeUpdate` declared in `java.sql.PreparedStatement`. */
class PreparedStatementExecuteLargeUpdateMethod extends Method {
PreparedStatementExecuteLargeUpdateMethod() {
this.getDeclaringType() instanceof TypePreparedStatement and
this.hasName("executeLargeUpdate")
}
}
111 changes: 111 additions & 0 deletions java/ql/lib/semmle/code/java/frameworks/MyBatis.qll
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,114 @@ private class MyBatisProviderStep extends TaintTracking::AdditionalValueStep {
)
}
}

/**
* A MyBatis Mapper XML file.
*/
class MyBatisMapperXmlFile extends XmlFile {
MyBatisMapperXmlFile() {
count(XmlElement e | e = this.getAChild()) = 1 and
this.getAChild().getName() = "mapper"
}
}

/**
* An XML element in a `MyBatisMapperXMLFile`.
*/
class MyBatisMapperXmlElement extends XmlElement {
MyBatisMapperXmlElement() { this.getFile() instanceof MyBatisMapperXmlFile }

/**
* Gets the value for this element, with leading and trailing whitespace trimmed.
*/
string getValue() { result = this.allCharactersString().trim() }

/**
* Gets the reference type bound to MyBatis Mapper XML File.
*/
RefType getNamespaceRefType() {
result.getQualifiedName() = this.getAttribute("namespace").getValue()
}
}

/**
* An MyBatis Mapper sql operation element.
*/
abstract class MyBatisMapperSqlOperation extends MyBatisMapperXmlElement {
/**
* Gets the value of the `id` attribute of MyBatis Mapper sql operation element.
*/
string getId() { result = this.getAttribute("id").getValue() }

/**
* Gets the `<include>` element in a `MyBatisMapperSqlOperation`.
*/
MyBatisMapperInclude getInclude() { result = this.getAChild*() }

/**
* Gets the method bound to MyBatis Mapper XML File.
*/
Method getMapperMethod() {
result.getName() = this.getId() and
result.getDeclaringType() = this.getParent().(MyBatisMapperXmlElement).getNamespaceRefType()
}
}

/**
* A `<insert>` element in a `MyBatisMapperSqlOperation`.
*/
class MyBatisMapperInsert extends MyBatisMapperSqlOperation {
MyBatisMapperInsert() { this.getName() = "insert" }
}

/**
* A `<update>` element in a `MyBatisMapperSqlOperation`.
*/
class MyBatisMapperUpdate extends MyBatisMapperSqlOperation {
MyBatisMapperUpdate() { this.getName() = "update" }
}

/**
* A `<delete>` element in a `MyBatisMapperSqlOperation`.
*/
class MyBatisMapperDelete extends MyBatisMapperSqlOperation {
MyBatisMapperDelete() { this.getName() = "delete" }
}

/**
* A `<select>` element in a `MyBatisMapperSqlOperation`.
*/
class MyBatisMapperSelect extends MyBatisMapperSqlOperation {
MyBatisMapperSelect() { this.getName() = "select" }
}

/**
* A `<sql>` element in a `MyBatisMapperXMLElement`.
*/
class MyBatisMapperSql extends MyBatisMapperXmlElement {
MyBatisMapperSql() { this.getName() = "sql" }

/**
* Gets the value of the `id` attribute of this `<sql>`.
*/
string getId() { result = this.getAttribute("id").getValue() }
}

/**
* A `<include>` element in a `MyBatisMapperXMLElement`.
*/
class MyBatisMapperInclude extends MyBatisMapperXmlElement {
MyBatisMapperInclude() { this.getName() = "include" }

/**
* Gets the value of the `refid` attribute of this `<include>`.
*/
string getRefid() { result = this.getAttribute("refid").getValue() }
}

/**
* A `<foreach>` element in a `MyBatisMapperXMLElement`.
*/
class MyBatisMapperForeach extends MyBatisMapperXmlElement {
MyBatisMapperForeach() { this.getName() = "foreach" }
}
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,11 @@ class SpringRequestMappingMethod extends SpringControllerMethod {
/** Gets the "value" @RequestMapping annotation value, if present. */
string getValue() { result = requestMappingAnnotation.getStringValue("value") }

/** Gets the "method" @RequestMapping annotation value, if present. */
string getMethodValue() {
result = requestMappingAnnotation.getAnEnumConstantArrayValue("method").getName()
}

/** Holds if this is considered an `@ResponseBody` method. */
predicate isResponseBody() {
this.getAnAnnotation().getType() instanceof SpringResponseBodyAnnotationType or
Expand Down
37 changes: 37 additions & 0 deletions java/ql/lib/semmle/code/java/frameworks/stapler/Stapler.qll
Original file line number Diff line number Diff line change
Expand Up @@ -122,3 +122,40 @@ private class PostConstructDataBoundMethod extends Method {
this.getAnAnnotation() instanceof PostConstructAnnotation
}
}

/**
* A method intended for Stapler request routing.
*
* From: https://www.jenkins.io/doc/developer/handling-requests/actions/
* Web methods need to provide some indication that they are intended for Stapler routing:
* - Any applicable annotation recognized by Stapler, e.g., @RequirePOST.
* - Any inferable parameter type, e.g., StaplerRequest.
* - Any applicable parameter annotation, recognized by Stapler, e.g., @AncestorInPath.
* - Any declared exception type implementing HttpResponse, e.g., HttpResponseException.
* - A return type implementing HttpResponse.
*/
class StaplerWebMethod extends Method {
StaplerWebMethod() {
// Any applicable annotation recognized by Stapler, e.g., @RequirePOST.
this.hasAnnotation("org.kohsuke.stapler", "WebMethod")
or
this.hasAnnotation("org.kohsuke.stapler.interceptor", ["RequirePOST", "RespondSuccess"])
or
this.hasAnnotation("org.kohsuke.stapler.verb", ["DELETE", "GET", "POST", "PUT"])
or
// Any inferable parameter type, e.g., StaplerRequest.
this.getAParamType()
.(RefType)
.hasQualifiedName("org.kohsuke.stapler", ["StaplerRequest", "StaplerRequest2"])
or
// Any applicable parameter annotation, recognized by Stapler, e.g., @AncestorInPath
this.getAParameter()
.hasAnnotation("org.kohsuke.stapler", ["AncestorInPath", "QueryParameter", "Header"])
or
// A return type implementing HttpResponse
this.getReturnType().(RefType).getASourceSupertype*() instanceof HttpResponse
or
// Any declared exception type implementing HttpResponse, e.g., HttpResponseException
this.getAThrownExceptionType().getASourceSupertype*() instanceof HttpResponse
}
}
Loading