Recipe Name:
Session management: Avoid CSRF: Use narrow mapping for state-changing methods
Description:
Non-specified RequestMapping method will map to any HTTP request
Level:
error
Language:
  • java
Tags:
  • Spring
  • security
  • framework specific
  • web
  • Spring Web
  • CSRF
Documentation

Secure coding practices prescribe that state-changing methods should be annoted with narrowed mapping to the HTTP request methods POST, PUT, DELETE, or PATCH.

Methods annotated with RequestMapping are by default mapped to all the HTTP request methods. However, Spring Security's CSRF protection is not enabled by default for the HTTP request methods GET, HEAD, TRACE, and OPTIONS, as this could cause the tokens to be leaked. Therefore, it is advised to annotate state-changing methods with more narrowing mappings to the HTTP methods POSt, PUT, DELETE, or PATCH. Class information:

package org.springframework.web.bind.annotation
    PostMapping
    GetMapping
    PutMapping
    DeleteMapping
    PatchMapping
Correct code example:
@Controller
public class SafeController {

    /**
     * For methods without side-effects use @GetMapping.
     */
    @GetMapping("/path")
    public String readData() {
        // No state-changing operations performed within this method.
        return "";
    }

    /**
     * For state-changing methods use either @PostMapping, @PutMapping, @DeleteMapping, or @PatchMapping.
     */
    @PostMapping("/path")
    public void writeData() {
        // State-changing operations performed within this method.
    }
}
Recipe
id: scw:spring:web:csrf:state-changing-methods-mapping
version: 10
metadata:
  name: 'Session management: Avoid CSRF: Use narrow mapping for state-changing methods'
  shortDescription: Non-specified RequestMapping method will map to any HTTP request
  level: error
  language: java
  newCodeOnly: false
  scwCategory: session:csrf
  enabled: true
  descriptionFile: descriptions/SessionmanagementAvoidCSRFUsenarrowmappingforstate-changingmethods.html
  tags: Spring;security;framework specific;web;Spring Web;CSRF
search:
  annotation:
    owner:
      method: {}
    not:
      parameters:
      - name: method
    in:
      typeDeclaration:
        with:
          annotation:
            type: org.springframework.stereotype.Controller
    type: org.springframework.web.bind.annotation.RequestMapping
availableFixes:
- name: Set to @GetMapping
  actions:
  - rewrite:
      to: '@org.springframework.web.bind.annotation.GetMapping({{{ elementValuePairs }}})'
- name: Set to @PostMapping
  actions:
  - rewrite:
      to: '@org.springframework.web.bind.annotation.PostMapping({{{ elementValuePairs }}})'
- name: Set to @PutMapping
  actions:
  - rewrite:
      to: '@org.springframework.web.bind.annotation.PutMapping({{{ elementValuePairs }}})'
- name: Set to @DeleteMapping
  actions:
  - rewrite:
      to: '@org.springframework.web.bind.annotation.DeleteMapping({{{ elementValuePairs }}})'
- name: Set to @PatchMapping
  actions:
  - rewrite:
      to: '@org.springframework.web.bind.annotation.PatchMapping({{{ elementValuePairs }}})'
- name: Set to HEAD by adding method parameter
  actions:
  - rewrite:
      to: '@RequestMapping(method = org.springframework.web.bind.annotation.RequestMethod.HEAD)'
- name: Set to OPTIONS by adding method parameter
  actions:
  - rewrite:
      to: '@RequestMapping(method = org.springframework.web.bind.annotation.RequestMethod.OPTIONS)'
- name: Set to TRACE by adding method parameter
  actions:
  - rewrite:
      to: '@RequestMapping(method = org.springframework.web.bind.annotation.RequestMethod.TRACE)'