[JAVA] JSESSIONID konnte bei Verwendung von Spring Security nicht der URL zugewiesen werden

Beim Aktualisieren von Spring Security in einer Anwendung, die die JSESSIONID in der URL enthält, tritt jetzt ein Fehler auf. Ich habe die Ursache untersucht und werde sie zusammenfassen.

Warum nicht jetzt JSESSIONID in die URL aufnehmen?

Umgebung

Reproduzieren Sie das Ereignis

Einige Vorbereitungen sind erforderlich, um das Ereignis zu reproduzieren.

JSESSIONID nach URL verwalten

Bei einem Browser, der Cookies verwenden kann, wird JSESSIONID mithilfe von Cookies verwaltet. Ändern Sie die Einstellungen des Servlet-Containers, um die Verwaltung per URL zu erzwingen.

Wenn Sie Spring Boot verwenden, können Sie dies festlegen, indem Sie "ServletContextInitializer" wie folgt als Bean definieren.

@Bean
public ServletContextInitializer servletContextInitializer() {
    return servletContext -> servletContext.setSessionTrackingModes(EnumSet.of(SessionTrackingMode.URL));
}

Aktivieren Sie das Umschreiben von URLs

Spring Security verfügt über eine Standardfunktion, die das Umschreiben von URLs deaktiviert. Ändern Sie die Einstellungen in der Klasse, die "WebSecurityConfigurerAdapter" erbt, wie unten gezeigt.

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.sessionManagement().enableSessionUrlRewriting(true);
    }
}

Erstellen Sie eine Anmeldeseite

Das Umschreiben von URLs ist auf der von Spring Security bereitgestellten Anmeldeseite standardmäßig nicht verfügbar. Erstellen Sie daher eine Anmeldeseite.

login.html


<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>login</title>
</head>
<body>
<form th:action="@{/login}" method="post">
    <div>
        <label>Nutzername: <input type="text" name="username"/></label>
    </div>
    <div>
        <label>Passwort: <input type="password" name="password"/></label>
    </div>
    <input type="submit" value="login"/>
</form>
</body>
</html>

Erstellen Sie außerdem eine Controller-Methode, um diese Seite anzuzeigen.

@Controller
public class HelloController {
    @GetMapping("/login")
    public String login() {
        return "login";
    }
}

Fügen Sie abschließend die Einstellungen hinzu. Außerdem werden der Benutzername und das Kennwort für die Anmeldung angegeben.

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/login").permitAll().anyRequest().authenticated()
                .and()
                .formLogin().loginPage("/login")
                .and()
                .sessionManagement().enableSessionUrlRewriting(true);
    }
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("user").password("{noop}user").roles("ADMIN");
    }
}

Standardmäßig wird "DelegatingPasswordEncoder" verwendet, daher muss das Kennwort ein Präfix haben. Da es sich diesmal um Klartext handelt, wird "{noop}" hinzugefügt.

Die Forschung zu "DelegatingPasswordEncoder" ist unten zusammengefasst. https://qiita.com/d-yosh/items/bb52152318391e5e07aa

Erstellen Sie nach dem Login eine Seite

Dadurch wird auch eine HTML- und Controller-Methode erstellt.

hello.html


<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>Hello</title>
</head>
<body>
<h1>Ich konnte mich einloggen</h1>
</body>
</html>
@Controller
public class HelloController {

    @GetMapping("/")
    public String index() {
        return "hello";
    }

    @GetMapping("/login")
    public String login() {
        return "login";
    }
}

Ereignisbestätigung

Ein Fehler tritt auf, wenn ich die Anwendung starte und darauf zugreife. (Um genau zu sein, tritt ein Fehler auf und leitet zum Fehlerbildschirm weiter, aber es tritt auch ein Fehler auf und die Umleitungsschleifen.) エラー.png

Wenn Sie sich das Protokoll ansehen, können Sie feststellen, dass eine "RequestRefectedException" aufgetreten ist.

org.springframework.security.web.firewall.RequestRejectedException: The request was rejected because the URL contained a potentially malicious String ";"

Ursache

Spring Security verwendet "HttpFirewall", um Anforderungen zu überprüfen, und eine seiner Implementierungen, "StrictHttpFirewall", lehnt URLs ab, die Semikolon enthalten. Wenn Sie die JSESSIONID in die URL aufnehmen, wird der URL ein Semikolon hinzugefügt, das von "StrictHttpFirewall" abgelehnt wird, und eine Ausnahme wird ausgelöst.

Die standardmäßig verwendete "HttpFirewall" unterscheidet sich je nach Version von Spring Security. In der Vergangenheit wurde "DefaultHttpFirewall" verwendet. Diese Klasse lehnt eine Anforderung nicht ab, wenn die URL ein Semikolon enthält. Dieses Mal, als ich die Version auflistete, trat ein Fehler auf, weil sich die Standard-HttpFirewall geändert hat.

Aktion 1

Es ist möglich, die Einstellung von "StrictHttpFirewall" zu ändern, um ein Semikolon zuzulassen.

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    //Verschiedene Auslassungen ...

    @Override
    public void configure(WebSecurity web) throws Exception {
        StrictHttpFirewall firewall = new StrictHttpFirewall();
        firewall.setAllowSemicolon(true);
        web.httpFirewall(firewall);
    }

}

Aktion 2

Ändern Sie die Einstellung, um "DefaultHttpFirewall" zu verwenden.

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    //Verschiedene Auslassungen ...

    @Override
    public void configure(WebSecurity web) throws Exception {
        DefaultHttpFirewall firewall = new DefaultHttpFirewall();
        web.httpFirewall(firewall);
    }
}

Bestätigung

Wenn Sie nach Aktion 1 oder 2 darauf zugreifen, kann der Anmeldebildschirm angezeigt werden. login.png

Sie können sich mit Benutzername: Benutzer und Passwort: Benutzer anmelden. logindekita.png

Der Grund, warum sich JSESSIONID vor und nach der Anmeldung ändert, ist übrigens, dass die Gegenmaßnahmen für Sitzungsfixierungsangriffe von Spring Security aktiviert sind. https://docs.spring.io/spring-security/site/docs/5.1.6.RELEASE/reference/htmlsingle/#ns-session-fixation

schließlich

Sitzungen sollten nicht per URL verwaltet werden.

Recommended Posts

JSESSIONID konnte bei Verwendung von Spring Security nicht der URL zugewiesen werden
Die Geschichte, dass das erzwungene Update nicht implementiert werden konnte
Statische Ressourcen konnten nicht über WebFlux verteilt werden, als @EnableWebFlux in Spring Boot gewährt wurde
Stellen Sie Spring Boot-Anwendungen für Heroku bereit, ohne die Heroku-CLI zu verwenden
Der Fall, dass @Autowired in JUnit5 nicht verwendet werden konnte
Antwortheader werden in Spring Security 4.1 möglicherweise nicht korrekt ausgegeben
[In 5.2.1 behoben] Spring Security 5.2.0.RELEASE weist Inkompatibilitäten auf, die im Versionshinweis nicht erwähnt sind
Was tun, wenn die Änderungen im Servlet nicht berücksichtigt werden?
Vorsichtsmaßnahmen bei der Verwendung von Spring AOP mit Jersery-Ressourcenklassen
Feder sollte vermutet werden, wenn Rails-Befehle nicht richtig funktionieren
Einfache Möglichkeit zum Erstellen einer Zuordnungsklasse bei Verwendung der API
Ein Memo über den Fall, dass das Einfügen mit Spring Data JDBC nicht durchgeführt werden konnte
Die Geschichte des Anhaltens, weil der Schienentest nicht durchgeführt werden konnte
So beheben Sie den unbekannten Fehler, der bei der Verwendung von slf4j in Java aufgetreten ist
Die Geschichte, dass der Erstellungsfehler bei Verwendung von Eclipse 2020 nicht aufgehört hat
[Rails 5] Anzeigen des Bildschirms zum Ändern des Kennworts bei Verwendung von devise
Entspricht "Fehler, dass die Basisauthentifizierung nicht bestanden wird" im Testcode "Die Geschichte, die nicht gemacht werden konnte".
So lösen Sie das Problem, dass die Bean beim Verschachteln in Spring Batch nicht ordnungsgemäß verarbeitet wird