Merge pull request #18288 from jcogs33/jcogs33/csrf-unprotected-request-type

Java: add CSRF query
This commit is contained in:
Jami
2025-02-11 15:32:56 -05:00
committed by GitHub
38 changed files with 1654 additions and 4 deletions

View File

@@ -0,0 +1,72 @@
<!DOCTYPE qhelp SYSTEM "qhelp.dtd">
<qhelp>
<overview>
<p>
Cross-site request forgery (CSRF) is a type of vulnerability in which an
attacker is able to force a user to carry out an action that the user did
not intend.
</p>
<p>
The attacker tricks an authenticated user into submitting a request to the
web application. Typically, this request will result in a state change on
the server, such as changing the user's password. The request can be
initiated when the user visits a site controlled by the attacker. If the
web application relies only on cookies for authentication, or on other
credentials that are automatically included in the request, then this
request will appear as legitimate to the server.
</p>
</overview>
<recommendation>
<p>Make sure any requests that change application state are protected from CSRF. Some application
frameworks provide default CSRF protection for unsafe HTTP request methods (such as <code>POST</code>)
which may change the state of the application. Safe HTTP request methods (such as <code>GET</code>)
should only perform read-only operations and should not be used for actions that change application
state.</p>
<p>This query currently supports the Spring and Stapler web frameworks. Spring provides default CSRF protection
for all unsafe HTTP methods whereas Stapler provides default CSRF protection for the <code>POST</code> method.</p>
</recommendation>
<example>
<p> The following examples show Spring request handlers allowing safe HTTP request methods for state-changing actions.
Since safe HTTP request methods do not have default CSRF protection in Spring, they should not be used when modifying
application state. Instead, use one of the unsafe HTTP methods which Spring default-protects from CSRF.</p>
<sample src="CsrfUnprotectedRequestTypeBadSpring.java" />
<sample src="CsrfUnprotectedRequestTypeGoodSpring.java" />
<p> The following examples show Stapler web methods allowing safe HTTP request methods for state-changing actions.
Since safe HTTP request methods do not have default CSRF protection in Stapler, they should not be used when modifying
application state. Instead, use the <code>POST</code> method which Stapler default-protects from CSRF.</p>
<sample src="CsrfUnprotectedRequestTypeBadStapler.java" />
<sample src="CsrfUnprotectedRequestTypeGoodStapler.java" />
</example>
<references>
<li>
OWASP:
<a href="https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)">Cross Site Request Forgery (CSRF)</a>.
</li>
<li>
Spring Security Reference:
<a href="https://docs.spring.io/spring-security/reference/servlet/exploits/csrf.html">
Cross Site Request Forgery (CSRF)</a>.
</li>
<li>
Jenkins Developer Documentation:
<a href="https://www.jenkins.io/doc/developer/security/form-validation/#protecting-from-csrf">
Protecting from CSRF</a>.
</li>
<li>
MDN web docs:
<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods">
HTTP request methods</a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,24 @@
/**
* @name HTTP request type unprotected from CSRF
* @description Using an HTTP request type that is not default-protected from CSRF for a
* state-changing action makes the application vulnerable to a Cross-Site
* Request Forgery (CSRF) attack.
* @kind path-problem
* @problem.severity error
* @security-severity 8.8
* @precision medium
* @id java/csrf-unprotected-request-type
* @tags security
* external/cwe/cwe-352
*/
import java
import semmle.code.java.security.CsrfUnprotectedRequestTypeQuery
query predicate edges(CallPathNode pred, CallPathNode succ) { CallGraph::edges(pred, succ) }
from CallPathNode source, CallPathNode sink
where unprotectedStateChange(source, sink)
select source.asMethod(), source, sink,
"Potential CSRF vulnerability due to using an HTTP request type which is not default-protected from CSRF for an apparent $@.",
sink, "state-changing action"

View File

@@ -0,0 +1,14 @@
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
// BAD - a safe HTTP request like GET should not be used for a state-changing action
@RequestMapping(value="/transfer", method=RequestMethod.GET)
public boolean doTransfer(HttpServletRequest request, HttpServletResponse response){
return transfer(request, response);
}
// BAD - no HTTP request type is specified, so safe HTTP requests are allowed
@RequestMapping(value="/delete")
public boolean doDelete(HttpServletRequest request, HttpServletResponse response){
return delete(request, response);
}

View File

@@ -0,0 +1,12 @@
import org.kohsuke.stapler.verb.GET;
// BAD - a safe HTTP request like GET should not be used for a state-changing action
@GET
public HttpRedirect doTransfer() {
return transfer();
}
// BAD - no HTTP request type is specified, so safe HTTP requests are allowed
public HttpRedirect doPost() {
return post();
}

View File

@@ -0,0 +1,15 @@
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.DeleteMapping;
// GOOD - use an unsafe HTTP request like POST
@RequestMapping(value="/transfer", method=RequestMethod.POST)
public boolean doTransfer(HttpServletRequest request, HttpServletResponse response){
return transfer(request, response);
}
// GOOD - use an unsafe HTTP request like DELETE
@DeleteMapping(value="/delete")
public boolean doDelete(HttpServletRequest request, HttpServletResponse response){
return delete(request, response);
}

View File

@@ -0,0 +1,13 @@
import org.kohsuke.stapler.verb.POST;
// GOOD - use POST
@POST
public HttpRedirect doTransfer() {
return transfer();
}
// GOOD - use POST
@POST
public HttpRedirect doPost() {
return post();
}

View File

@@ -0,0 +1,4 @@
---
category: newQuery
---
* Added a new query, `java/csrf-unprotected-request-type`, to detect Cross-Site Request Forgery (CSRF) vulnerabilities due to using HTTP request types that are not default-protected from CSRF.

View File

@@ -4,7 +4,6 @@
deprecated module;
import java
import semmle.code.xml.MyBatisMapperXML
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.frameworks.MyBatis
import semmle.code.java.frameworks.Properties

View File

@@ -15,7 +15,6 @@
import java
deprecated import MyBatisCommonLib
deprecated import MyBatisMapperXmlSqlInjectionLib
deprecated import semmle.code.xml.MyBatisMapperXML
import semmle.code.java.dataflow.FlowSources
private import semmle.code.java.security.Sanitizers
deprecated import MyBatisMapperXmlSqlInjectionFlow::PathGraph

View File

@@ -4,7 +4,7 @@
deprecated module;
import java
import semmle.code.xml.MyBatisMapperXML
import semmle.code.java.frameworks.MyBatis
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.frameworks.Properties