Skip to content

Commit 2a8cc00

Browse files
authored
Merge pull request github#18288 from jcogs33/jcogs33/csrf-unprotected-request-type
Java: add CSRF query
2 parents a42480d + c6a71cd commit 2a8cc00

38 files changed

+1654
-4
lines changed

java/ql/lib/semmle/code/java/frameworks/Jdbc.qll

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,19 @@ class ResultSetGetStringMethod extends Method {
3434
this.getReturnType() instanceof TypeString
3535
}
3636
}
37+
38+
/** A method with the name `executeUpdate` declared in `java.sql.PreparedStatement`. */
39+
class PreparedStatementExecuteUpdateMethod extends Method {
40+
PreparedStatementExecuteUpdateMethod() {
41+
this.getDeclaringType() instanceof TypePreparedStatement and
42+
this.hasName("executeUpdate")
43+
}
44+
}
45+
46+
/** A method with the name `executeLargeUpdate` declared in `java.sql.PreparedStatement`. */
47+
class PreparedStatementExecuteLargeUpdateMethod extends Method {
48+
PreparedStatementExecuteLargeUpdateMethod() {
49+
this.getDeclaringType() instanceof TypePreparedStatement and
50+
this.hasName("executeLargeUpdate")
51+
}
52+
}

java/ql/lib/semmle/code/java/frameworks/MyBatis.qll

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,3 +128,114 @@ private class MyBatisProviderStep extends TaintTracking::AdditionalValueStep {
128128
)
129129
}
130130
}
131+
132+
/**
133+
* A MyBatis Mapper XML file.
134+
*/
135+
class MyBatisMapperXmlFile extends XmlFile {
136+
MyBatisMapperXmlFile() {
137+
count(XmlElement e | e = this.getAChild()) = 1 and
138+
this.getAChild().getName() = "mapper"
139+
}
140+
}
141+
142+
/**
143+
* An XML element in a `MyBatisMapperXMLFile`.
144+
*/
145+
class MyBatisMapperXmlElement extends XmlElement {
146+
MyBatisMapperXmlElement() { this.getFile() instanceof MyBatisMapperXmlFile }
147+
148+
/**
149+
* Gets the value for this element, with leading and trailing whitespace trimmed.
150+
*/
151+
string getValue() { result = this.allCharactersString().trim() }
152+
153+
/**
154+
* Gets the reference type bound to MyBatis Mapper XML File.
155+
*/
156+
RefType getNamespaceRefType() {
157+
result.getQualifiedName() = this.getAttribute("namespace").getValue()
158+
}
159+
}
160+
161+
/**
162+
* An MyBatis Mapper sql operation element.
163+
*/
164+
abstract class MyBatisMapperSqlOperation extends MyBatisMapperXmlElement {
165+
/**
166+
* Gets the value of the `id` attribute of MyBatis Mapper sql operation element.
167+
*/
168+
string getId() { result = this.getAttribute("id").getValue() }
169+
170+
/**
171+
* Gets the `<include>` element in a `MyBatisMapperSqlOperation`.
172+
*/
173+
MyBatisMapperInclude getInclude() { result = this.getAChild*() }
174+
175+
/**
176+
* Gets the method bound to MyBatis Mapper XML File.
177+
*/
178+
Method getMapperMethod() {
179+
result.getName() = this.getId() and
180+
result.getDeclaringType() = this.getParent().(MyBatisMapperXmlElement).getNamespaceRefType()
181+
}
182+
}
183+
184+
/**
185+
* A `<insert>` element in a `MyBatisMapperSqlOperation`.
186+
*/
187+
class MyBatisMapperInsert extends MyBatisMapperSqlOperation {
188+
MyBatisMapperInsert() { this.getName() = "insert" }
189+
}
190+
191+
/**
192+
* A `<update>` element in a `MyBatisMapperSqlOperation`.
193+
*/
194+
class MyBatisMapperUpdate extends MyBatisMapperSqlOperation {
195+
MyBatisMapperUpdate() { this.getName() = "update" }
196+
}
197+
198+
/**
199+
* A `<delete>` element in a `MyBatisMapperSqlOperation`.
200+
*/
201+
class MyBatisMapperDelete extends MyBatisMapperSqlOperation {
202+
MyBatisMapperDelete() { this.getName() = "delete" }
203+
}
204+
205+
/**
206+
* A `<select>` element in a `MyBatisMapperSqlOperation`.
207+
*/
208+
class MyBatisMapperSelect extends MyBatisMapperSqlOperation {
209+
MyBatisMapperSelect() { this.getName() = "select" }
210+
}
211+
212+
/**
213+
* A `<sql>` element in a `MyBatisMapperXMLElement`.
214+
*/
215+
class MyBatisMapperSql extends MyBatisMapperXmlElement {
216+
MyBatisMapperSql() { this.getName() = "sql" }
217+
218+
/**
219+
* Gets the value of the `id` attribute of this `<sql>`.
220+
*/
221+
string getId() { result = this.getAttribute("id").getValue() }
222+
}
223+
224+
/**
225+
* A `<include>` element in a `MyBatisMapperXMLElement`.
226+
*/
227+
class MyBatisMapperInclude extends MyBatisMapperXmlElement {
228+
MyBatisMapperInclude() { this.getName() = "include" }
229+
230+
/**
231+
* Gets the value of the `refid` attribute of this `<include>`.
232+
*/
233+
string getRefid() { result = this.getAttribute("refid").getValue() }
234+
}
235+
236+
/**
237+
* A `<foreach>` element in a `MyBatisMapperXMLElement`.
238+
*/
239+
class MyBatisMapperForeach extends MyBatisMapperXmlElement {
240+
MyBatisMapperForeach() { this.getName() = "foreach" }
241+
}

java/ql/lib/semmle/code/java/frameworks/spring/SpringController.qll

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,11 @@ class SpringRequestMappingMethod extends SpringControllerMethod {
156156
/** Gets the "value" @RequestMapping annotation value, if present. */
157157
string getValue() { result = requestMappingAnnotation.getStringValue("value") }
158158

159+
/** Gets the "method" @RequestMapping annotation value, if present. */
160+
string getMethodValue() {
161+
result = requestMappingAnnotation.getAnEnumConstantArrayValue("method").getName()
162+
}
163+
159164
/** Holds if this is considered an `@ResponseBody` method. */
160165
predicate isResponseBody() {
161166
this.getAnAnnotation().getType() instanceof SpringResponseBodyAnnotationType or

java/ql/lib/semmle/code/java/frameworks/stapler/Stapler.qll

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,3 +122,40 @@ private class PostConstructDataBoundMethod extends Method {
122122
this.getAnAnnotation() instanceof PostConstructAnnotation
123123
}
124124
}
125+
126+
/**
127+
* A method intended for Stapler request routing.
128+
*
129+
* From: https://www.jenkins.io/doc/developer/handling-requests/actions/
130+
* Web methods need to provide some indication that they are intended for Stapler routing:
131+
* - Any applicable annotation recognized by Stapler, e.g., @RequirePOST.
132+
* - Any inferable parameter type, e.g., StaplerRequest.
133+
* - Any applicable parameter annotation, recognized by Stapler, e.g., @AncestorInPath.
134+
* - Any declared exception type implementing HttpResponse, e.g., HttpResponseException.
135+
* - A return type implementing HttpResponse.
136+
*/
137+
class StaplerWebMethod extends Method {
138+
StaplerWebMethod() {
139+
// Any applicable annotation recognized by Stapler, e.g., @RequirePOST.
140+
this.hasAnnotation("org.kohsuke.stapler", "WebMethod")
141+
or
142+
this.hasAnnotation("org.kohsuke.stapler.interceptor", ["RequirePOST", "RespondSuccess"])
143+
or
144+
this.hasAnnotation("org.kohsuke.stapler.verb", ["DELETE", "GET", "POST", "PUT"])
145+
or
146+
// Any inferable parameter type, e.g., StaplerRequest.
147+
this.getAParamType()
148+
.(RefType)
149+
.hasQualifiedName("org.kohsuke.stapler", ["StaplerRequest", "StaplerRequest2"])
150+
or
151+
// Any applicable parameter annotation, recognized by Stapler, e.g., @AncestorInPath
152+
this.getAParameter()
153+
.hasAnnotation("org.kohsuke.stapler", ["AncestorInPath", "QueryParameter", "Header"])
154+
or
155+
// A return type implementing HttpResponse
156+
this.getReturnType().(RefType).getASourceSupertype*() instanceof HttpResponse
157+
or
158+
// Any declared exception type implementing HttpResponse, e.g., HttpResponseException
159+
this.getAThrownExceptionType().getASourceSupertype*() instanceof HttpResponse
160+
}
161+
}

0 commit comments

Comments
 (0)