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

Conversation

jcogs33
Copy link
Contributor

@jcogs33 jcogs33 commented Dec 16, 2024

Description

Adds a query for CSRF vulnerabilities caused by using HTTP request types that are not default-protected by a given framework for apparent state-changing actions. Supports Spring and Stapler frameworks for now. State-changing actions are determined heuristically based on whether the request handling method updates a database or whether its name suggests that it might change application state. Due to the heuristic nature of determining state changes, this is a low precision query.

Consideration

  • Let me know if you have any suggestions for improving the heuristics used for identifying state changes.
  • See inline comments/questions regarding some code structure that should maybe be improved.
  • Let me know if you have any suggestions for better ways to word the query name/id/description/alert message/qhelp. I went through a few iterations of different wording for these, and I'm not sure if what I ended up with is clear enough.

Pull Request checklist

All query authors

Internal query authors only

  • Changes are validated at scale (internal access required).
  • Adding a new query? Consider also adding the query to autofix.
  • Autofixes generated based on these changes are valid, only needed if this PR makes significant changes to .ql, .qll, or .qhelp files. See the documentation (internal access required).

@github-actions github-actions bot added the Java label Dec 16, 2024
@jcogs33 jcogs33 force-pushed the jcogs33/csrf-unprotected-request-type branch 2 times, most recently from ff0477c to 13753dd Compare December 17, 2024 00:24
Copy link
Contributor

github-actions bot commented Dec 17, 2024

QHelp previews:

java/ql/src/Security/CWE/CWE-352/CsrfUnprotectedRequestType.qhelp

HTTP request type unprotected from CSRF

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.

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.

Recommendation

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 POST) which may change the state of the application. Safe HTTP request methods (such as GET) should only perform read-only operations and should not be used for actions that change application state.

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 POST method.

Example

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.

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);
}
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);
}

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 POST method which Stapler default-protects from CSRF.

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();
}
import org.kohsuke.stapler.verb.POST;

// GOOD - use POST
@POST
public HttpRedirect doTransfer() {
  return transfer();
}

// GOOD - use POST
@POST
public HttpRedirect doPost() {
  return post();
}

References

@jcogs33 jcogs33 force-pushed the jcogs33/csrf-unprotected-request-type branch 2 times, most recently from c217d7f to 3d14e16 Compare December 18, 2024 22:46
@jcogs33 jcogs33 force-pushed the jcogs33/csrf-unprotected-request-type branch 2 times, most recently from 2472aad to 695eca6 Compare December 20, 2024 03:33
@jcogs33 jcogs33 changed the title [DRAFT] Java: add CSRF query Java: add CSRF query Dec 20, 2024
@jcogs33 jcogs33 force-pushed the jcogs33/csrf-unprotected-request-type branch from 695eca6 to b56a8d8 Compare December 20, 2024 16:12
@jcogs33 jcogs33 marked this pull request as ready for review December 20, 2024 21:00
@jcogs33 jcogs33 requested a review from a team as a code owner December 20, 2024 21:00
Copy link
Contributor

@aschackmull aschackmull left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QL part LGTM now, but be sure to verify performance with an additional dca run.

@jcogs33
Copy link
Contributor Author

jcogs33 commented Jan 9, 2025

Performance looks fine in the new DCA run.

Jami Cogswell added 9 commits January 30, 2025 10:14
remove PUT and DELETE from StaplerCsrfUnprotectedMethod

remove OPTIONS and TRACE from SpringCsrfUnprotectedMethod
remove import no longer needed since contents of MyBatisMapperXML.qll have been moved to MyBatis.qll
@jcogs33 jcogs33 force-pushed the jcogs33/csrf-unprotected-request-type branch from d2a6fb9 to 0071e1a Compare January 30, 2025 15:20
@jcogs33 jcogs33 added the ready-for-doc-review This PR requires and is ready for review from the GitHub docs team. label Feb 3, 2025
@mchammer01 mchammer01 self-requested a review February 4, 2025 10:35
@mchammer01
Copy link
Contributor

I'll review this on behalf of Docs.

mchammer01
mchammer01 previously approved these changes Feb 4, 2025
Copy link
Contributor

@mchammer01 mchammer01 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jcogs33 👋🏻 - Approving this on behalf of Docs in order not to block you ⚡
I have left a few minor comments and suggestions. Hope these help!

Jami Cogswell added 2 commits February 4, 2025 13:21
discussing tokens is not directly relevant to this query's recommendation and examples
@jcogs33
Copy link
Contributor Author

jcogs33 commented Feb 4, 2025

@mchammer01, Thanks for the review! Regarding the wording in the overview section, I've changed that section completely so that it aligns more closely with the QHelp overviews in some of our other CSRF queries (c.f. Python, Ruby). Would you mind re-reviewing the overview section and confirming that this re-write looks okay? 🙏

For context: I copied the original overview section from the Java SpringCSRFProtection.qhelp since I wanted to align with our other Java CSRF query, but I agree that the wording could be improved. If you think the re-write is okay, then I'll open a follow-up PR to update SpringCSRFProtection.qhelp as well.

mchammer01
mchammer01 previously approved these changes Feb 5, 2025
Copy link
Contributor

@mchammer01 mchammer01 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jcogs33 - reviewed as requested. Left a couple of minor suggestions and asked a question.
As usual, feel free to ignore anything you don't agree with 😄

@jcogs33
Copy link
Contributor Author

jcogs33 commented Feb 5, 2025

Thanks for the review @mchammer01! I've addressed your comments.

Copy link
Contributor

@egregius313 egregius313 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@jcogs33 jcogs33 merged commit 2a8cc00 into github:main Feb 11, 2025
17 checks passed
@jcogs33 jcogs33 deleted the jcogs33/csrf-unprotected-request-type branch February 11, 2025 20:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Java ready-for-doc-review This PR requires and is ready for review from the GitHub docs team.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants