[JAVA] Comment faire coexister CsrfRequestDataValueProcessor et RequestDataValueProcessor original sur Spring Boot

Lorsque Spring Security est utilisé sur Spring Boot, le CsrfRequestDataValueProcessor (classe de sortie de la valeur du jeton CSRF vers le caché du formulaire) fourni par Spring Security est appliqué et le RequestDataValueProcessor spécifique au projet ne peut pas être appliqué. C'est ... Il semble que le problème de Spring Boot (gh-4676) discute de la façon de le gérer, mais c'est toujours une conclusion. Ne semble pas apparaître.

solution de contournement

En cause ...

Est présenté comme une solution de contournement.

Créez votre propre classe AutoConfigure et essayez de la résoudre

Cette fois, je vais essayer de créer ma propre classe AutoConfigure et utiliser @ AutoConfigureAfter pour remplacer la définition de Bean dans SecurityAutoConfiguration.class. Le «RequestDataValueProcessor» spécifique au projet génère des paramètres communs (_s = date et heure du système en millisecondes) pour éviter la mise en cache dans l'URL sous les éléments «form» et «a».

Créez votre propre classe AutoConfigure

La classe créée cette fois ne considère pas du tout la polyvalence et adopte une méthode d'implémentation qui applique l'implémentation spécifique au projet RequestDataValueProcessor à l'application tout en conservant les fonctions fournies par CsrfRequestDataValueProcessor.

Note:

Si vous considérez la polyvalence ... Il est préférable de créer une classe composite de RequestDataValueProcessor qui délègue le traitement à plusieurs RequestDataValueProcessors.

package com.example;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.web.servlet.support.csrf.CsrfRequestDataValueProcessor;
import org.springframework.web.servlet.support.RequestDataValueProcessor;
import org.springframework.web.util.UriComponentsBuilder;

@Configuration
@AutoConfigureAfter(SecurityAutoConfiguration.class) //★★★ Points ici[1]
public class MyRequestDataValueProcessorAutoConfiguration {
	@Bean
	RequestDataValueProcessor requestDataValueProcessor() { //★★★ Points ici[2]
		CsrfRequestDataValueProcessor csrfRequestDataValueProcessor = new CsrfRequestDataValueProcessor();
		return new RequestDataValueProcessor() {
			@Override
			public String processAction(HttpServletRequest request, String action, String httpMethod) {
				return addCachePreventQueryParameter(csrfRequestDataValueProcessor.processAction(request, action, httpMethod));
			}

			@Override
			public String processFormFieldValue(HttpServletRequest request, String name, String value, String type) {
				return csrfRequestDataValueProcessor.processFormFieldValue(request, name, value, type);
			}

			@Override
			public Map<String, String> getExtraHiddenFields(HttpServletRequest request) {
				return csrfRequestDataValueProcessor.getExtraHiddenFields(request);
			}

			@Override
			public String processUrl(HttpServletRequest request, String url) {
				return addCachePreventQueryParameter(csrfRequestDataValueProcessor.processUrl(request, url));
			}

			private String addCachePreventQueryParameter(String url) {
				return UriComponentsBuilder.fromUriString(url).queryParam("_s", System.currentTimeMillis()).build().encode()
						.toUriString();
			}
		};
	}

}

[1] En permettant à votre propre classe AutoConfigure d'être appelée après SecurityAutoConfiguration, vous pouvez remplacer la définition de Bean fournie par Spring Boot (Spring Security) avec votre propre classe AutoConfigure. [2] Pour remplacer la définition du bean, le nom du bean doit être "requestDataValueProcessor" ".


Fondamentalement, il délègue le processus à CsrfRequestDataValueProcessor et l'implémente pour ajouter un paramètre d'évitement de cache aux valeurs de retour de processAction et processUrl.

Pour rendre la classe de configuration créée reconnue comme classe de configuration automatique, créez src / main / resources / META-INF / spring.factories et utilisez la valeur de clé de propriété ʻorg.springframework.boot.autoconfigure.EnableAutoConfiguration`. Vous devez spécifier la classe dans laquelle vous avez créé.

src/main/resources/META-INF/spring.factories


# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.MyRequestDataValueProcessorAutoConfiguration

Création d'une vue (Thymeleaf)

Créons une vue simple pour la vérification des opérations.

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <title>Demo</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.css" type="text/css"/>
</head>
<body>

<div class="container">

    <h1>Demo</h1>


    <div id="demoForm">
        <form action="index.html" method="post" class="form-horizontal"
              th:action="@{/demo}" th:object="${demoForm}"> <!--★★★ Points ici[3] -->
            <div class="form-group">
                <label for="title" class="col-sm-1 control-label">Title</label>
                <div class="col-sm-10">
                    <input type="text" class="form-control" id="title" th:field="*{title}"/>
                    <span class="text-error" th:errors="*{title}">error message</span>
                </div>
            </div>
            <div class="form-group">
                <div class="col-sm-offset-1 col-sm-10">
                    <button type="submit" class="btn btn-default">Create</button>
                </div>
            </div>
        </form>
    </div>

    <a href="index.html" th:href="@{/demo}">Reload</a> <!--★★★ Points ici[4] -->

</div>
</body>
</html>

[3] L'URL spécifiée dans th: action est traitée par la méthode RequestDataValueProcessor # processAction. [4] L'URL spécifiée dans th: href est traitée par la méthode RequestDataValueProcessor # processUrl.


Lorsque le HTML ci-dessus est exécuté sur Spring Boot, le HTML suivant est généré. Il y a un paramètre d'évitement de cache dans l'URL de l'attribut ʻaction de l'élément " form "et de l'attribut" href de l'élément "ʻa", et le paramètre hiddenpour lier la valeur du jeton CSRF dans l'élémentform`. Vous pouvez voir que l'élément est sorti.

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Demo</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.css" type="text/css" />
</head>
<body>

<div class="container">

    <h1>Demo</h1>


    <div id="demoForm">
        <form action="/demo?_s=1488222896002" method="post" class="form-horizontal"> <!--★★★ Le paramètre d'évitement du cache est donné-->
            <div class="form-group">
                <label for="title" class="col-sm-1 control-label">Title</label>
                <div class="col-sm-10">
                    <input type="text" class="form-control" id="title" name="title" value="" />
                    
                </div>
            </div>
            <div class="form-group">
                <div class="col-sm-offset-1 col-sm-10">
                    <button type="submit" class="btn btn-default">Create</button>
                </div>
            </div>
        <input type="hidden" name="_csrf" value="b952a1bf-222a-4a99-b889-6878935a5784" /></form> <!--★★★ Le lien caché de la valeur du jeton CSRF est donné.-->
    </div>

    <a href="/demo?_s=1488222896002">Reload</a> <!--★★★ Le paramètre d'évitement du cache est donné-->

</div>
</body>
</html>

Créer un contrôleur

RequestDataValueProcessor # processUrl est lié à la fonction de redirection de Spring MVC, nous allons donc vérifier l'opération ici également.

package com.example;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@RequestMapping("/demo")
@Controller
public class DemoController {

	@ModelAttribute
	DemoForm setUpForm() {
		return new DemoForm();
	}

	@GetMapping
	String index() {
		return "index";
	}

	@PostMapping
	String submit(DemoForm form) {
		return "redirect:/demo"; //★★★ Points ici[5]
	}

	static class DemoForm {
		private String title;

		public String getTitle() {
			return title;
		}

		public void setTitle(String title) {
			this.title = title;
		}
	}

}

[5] L'URL spécifiée lors de l'utilisation de la fonctionnalité de redirection Spring MVC est traitée par la méthode RequestDataValueProcessor # processUrl.


Si vous vérifiez l'URL de redirection avec l'outil de développement du navigateur, vous pouvez voir que le paramètre d'évitement de cache est correctement attribué.

HTTP/1.1 302
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Location: http://localhost:8080/demo?_s=1488223437196 #★★★ Le paramètre d'évitement du cache est donné
Content-Language: en-US
Content-Length: 0
Date: Mon, 27 Feb 2017 19:23:57 GMT

Résumé

En créant ma propre classe AutoConfigure, j'ai pu faire coexister CsrfRequestDataValueProcessor et mon propre RequestDataValueProcessor. Il a également été confirmé qu'en utilisant RequestDataValueProcessor, des paramètres communs peuvent être ajoutés aux URL gérées sous Spring MVC. Cependant ... Lors de la gestion d'URL en dehors de la gestion Spring MVC (par exemple, lors de la gestion directe de la méthode de HttpServletResponse), elle n'est pas sous la juridiction de RequestDataValueProcessor, donc les paramètres communs ne peuvent pas être affectés. Si vous souhaitez ajouter des paramètres communs aux URL non gérées par Spring MVC, vous devez créer HttpServletResponseWrapper pour donner des paramètres communs, l'envelopper dans la classe créée par Servlet Filter et appeler le traitement suivant. Je vais.

Recommended Posts

Comment faire coexister CsrfRequestDataValueProcessor et RequestDataValueProcessor original sur Spring Boot
Comment réduire l'image de Spring Boot Docker
Comment appeler et utiliser l'API en Java (Spring Boot)
Comment configurer Spring Boot + PostgreSQL
Comment utiliser ModelMapper (Spring boot)
Comment créer un hinadan pour un projet Spring Boot à l'aide de SPRING INITIALIZR
Comment diviser un fichier de message Spring Boot
Ajoutez une botte de printemps et un dégradé à éclipse
Comment afficher les caractères saisis dans Spring Boot sur le navigateur et les liens de référence [Introduction à Spring Boot / Pour les débutants]
Comment utiliser MyBatis2 (iBatis) avec Spring Boot 1.4 (Spring 4)
Comment utiliser h2db intégré avec Spring Boot
Comment utiliser les attributs de session Spring Boot (@SessionAttributes)
Comment ajouter un chemin de classe dans Spring Boot
Comment se lier avec un fichier de propriétés dans Spring Boot
[Spring Boot] Comment se référer au fichier de propriétés
Spring Boot - Comment définir le délai d'expiration de la session
Plans pour prendre en charge JDK 11 pour Eclipse et Spring Boot
Comment définir l'injection de dépendance Spring Boot (DI)
Comment écrire un test unitaire pour Spring Boot 2
Comment implémenter le processus d'authentification en spécifiant le nom d'utilisateur et le mot de passe dans Spring Boot
Comment créer un projet Spring Boot dans IntelliJ
[Spring Boot] Comment créer un projet (pour les débutants)
Comment faire fonctionner JavaScript sur une page spécifique
Comment utiliser CommandLineRunner dans Spring Batch of Spring Boot
Déployer le projet Spring Boot sur Tomcat dans XAMPP
Comment démarrer par environnement avec Spring Boot de Maven
Tentative de SSR Vue.js avec Spring Boot et GraalJS
(Ruby on Rails6) Comment créer un modèle et une table
Comment utiliser OpenCV 4 sur Android et afficher la vue en direct de la caméra
Comment modifier la valeur de paramètre de application.properties au moment du démarrage dans Spring Boot
Jusqu'à INSERT et SELECT sur Postgres avec botte de printemps et feuille de thym
J'ai essayé de faire coexister Java Optional et la clause de garde
Connectez-vous à la base de données avec spring boot + spring jpa et effectuez l'opération CRUD
Comment exécuter React et Rails sur le même serveur
8 choses à insérer dans DB en utilisant Spring Boot et JPA
Comment contrôler les transactions dans Spring Boot sans utiliser @Transactional
Essayez Spring Boot de 0 à 100.
Spring Boot sur Microsoft Azure
Java - Comment créer JTable
Comment déployer avec heroku
Introduction à Spring Boot ① ~ DI ~
Introduction à Spring Boot, partie 1
Essayez Spring Boot sur Mac
[Rails] Comment faire des graines
Comment installer et utiliser Composer sur une instance ECS sur Ubuntu 16.04
Configuration minimale pour exécuter l'application Spring Boot sur Azure Web Apps
Comment créer votre propre contrôleur correspondant à / error avec Spring Boot
Comment définir et utiliser un profil avec une configuration basée sur des annotations dans le framework Spring
Comment installer et configurer l'outil de surveillance "Graphite" sur Ubuntu
Comment charger un fichier de téléchargement Spring et afficher son contenu
Comment utiliser Lombok au printemps
Comment utiliser StringBurrer et Arrays.toString.
Comment faire un test unitaire de Spring AOP
gRPC sur Spring Boot avec grpc-spring-boot-starter
Comment "évider" une vue sur Android
Remarques sur l'utilisation de Spring Data JDBC