Grundlegende und systematische Geschichte Zertifizierungs- / Autorisierungsgeschichte Remember-Me-Geschichte CSRF-Geschichte Die Geschichte des Antwortheaders Method Security Story CORS-Geschichte Die Geschichte von Run-As Die Geschichte von ACL Teststory Sprechen Sie über die Zusammenarbeit mit MVC und Boot
Sonderedition Was Spring Security kann und was nicht
Standardmäßig kann derselbe Benutzer mehrere Sitzungen erstellen. Mit anderen Worten, derselbe Benutzer kann sich von verschiedenen Terminals aus beliebig oft anmelden.
Durch Ändern der Einstellungen können Sie die Anzahl der gleichzeitigen Sitzungen begrenzen oder mehrere Anmeldungen verhindern.
namespace
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
</web-app>
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:sec="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<sec:http>
<sec:intercept-url pattern="/login" access="permitAll" />
<sec:intercept-url pattern="/**" access="isAuthenticated()" />
<sec:form-login />
<sec:logout />
<sec:session-management>
<sec:concurrency-control max-sessions="1" />
</sec:session-management>
</sec:http>
<sec:authentication-manager>
<sec:authentication-provider>
<sec:user-service>
<sec:user name="hoge" password="hoge" authorities="" />
</sec:user-service>
</sec:authentication-provider>
</sec:authentication-manager>
</beans>
Java Configuration
MySpringSecurityInitializer.java
package sample.spring.security;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
public class MySpringSecurityInitializer extends AbstractSecurityWebApplicationInitializer {
public MySpringSecurityInitializer() {
super(MySpringSecurityConfig.class);
}
@Override
protected boolean enableHttpSessionEventPublisher() {
return true;
}
}
MySpringSecurityConfig.java
package sample.spring.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import java.util.Collections;
@EnableWebSecurity
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.sessionManagement().maximumSessions(1);
}
@Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("hoge")
.password("hoge")
.authorities(Collections.emptyList());
}
}
Melden Sie sich mit dem ersten Browser an.
Melden Sie sich als derselbe Benutzer in einem anderen Browser an.
Wenn ich den ersten Browser erneut anzeige, wird eine Fehlermeldung angezeigt.
web.xml
<listener>
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
MySpringSecurityInitializer.java
@Override
protected boolean enableHttpSessionEventPublisher() {
return true;
}
HttpSessionEventPublisher
als Listener registrieren, damit Spring Security erkennen kann, dass eine neue Sitzung erstellt wurde.applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:sec="http://www.springframework.org/schema/security"
...>
<sec:http>
...
<sec:session-management>
<sec:concurrency-control max-sessions="1" />
</sec:session-management>
</sec:http>
...
</beans>
MySpringSecurityConfig.java
...
@EnableWebSecurity
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
...
.and()
.sessionManagement().maximumSessions(1);
}
...
}
Standardmäßig wird auf dem Bildschirm nur eine Fehlermeldung angezeigt. Wechseln Sie daher zur angegebenen Seite (z. B. Anmeldeseite).
namespace
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:sec="http://www.springframework.org/schema/security"
...>
<sec:http>
...
<sec:session-management >
<sec:concurrency-control max-sessions="1" expired-url="/login" />
</sec:session-management>
</sec:http>
...
</beans>
expired-url
an.Java Configuration
MySpringSecurityConfig.java
...
@EnableWebSecurity
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
...
.and()
.sessionManagement().maximumSessions(1).expiredUrl("/login");
}
...
}
expiredUrl (String)
an.MySessionInformationExpiredStrategy.java
package sample.spring.security.session;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.session.SessionInformationExpiredEvent;
import org.springframework.security.web.session.SessionInformationExpiredStrategy;
import javax.servlet.ServletException;
import java.io.IOException;
public class MySessionInformationExpiredStrategy implements SessionInformationExpiredStrategy {
@Override
public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException, ServletException {
DefaultRedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
redirectStrategy.sendRedirect(event.getRequest(), event.getResponse(), "/login");
}
}
--Erstellen Sie eine Klasse, die "SessionInformationExpiredStrategy" implementiert.
/ login
weiter.namespace
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:sec="http://www.springframework.org/schema/security"
...>
<bean id="sies" class="sample.spring.security.session.MySessionInformationExpiredStrategy" />
<sec:http>
...
<sec:session-management >
<sec:concurrency-control max-sessions="1" expired-session-strategy-ref="sies" />
</sec:session-management>
</sec:http>
...
</beans>
Java Configuration
MySpringSecurityConfig.java
...
import sample.spring.security.session.MySessionInformationExpiredStrategy;
@EnableWebSecurity
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
...
.and()
.sessionManagement()
.maximumSessions(1)
.expiredSessionStrategy(new MySessionInformationExpiredStrategy());
}
...
}
expiredSessionStrategy (SessionInformationExpiredStrategy)
.Wenn Sie nur "max-session" ("maximumSessions") angeben und sich über die Obergrenze hinaus anmelden, wird die älteste Sitzung zuerst verworfen.
Wenn Sie dagegen versuchen, sich über das Limit hinaus anzumelden, können Sie einen Fehler machen, wenn Sie versuchen, eine neue Sitzung zu erstellen. Beachten Sie jedoch, dass Sie sich bei Aktivierung dieser Einstellung möglicherweise erst wieder anmelden können, wenn Ihre alte Sitzung abläuft oder Sie sich explizit abmelden.
namespace
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:sec="http://www.springframework.org/schema/security"
...>
<sec:http>
...
<sec:session-management >
<sec:concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
</sec:session-management>
</sec:http>
...
</beans>
Java Configuration
MySpringSecurityConfig.java
...
@EnableWebSecurity
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
...
.and()
.sessionManagement()
.maximumSessions(1)
.maxSessionsPreventsLogin(true);
}
...
}
--Pass true
in der maxSessionsPreventsLogin (boolean)
Methode.
** Funktionsprüfung **
Melden Sie sich mit dem ersten Browser an.
Wenn Sie versuchen, sich im zweiten Browser als derselbe Benutzer anzumelden, tritt ein Fehler auf.
max-session-error.jsp
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Max Session</title>
</head>
<body>
<h1>Die Anzahl der Sitzungen hat das Limit erreicht</h1>
<%@page import="org.springframework.security.core.AuthenticationException" %>
<%@page import="org.springframework.security.web.WebAttributes" %>
<%
AuthenticationException e = (AuthenticationException)session.getAttribute(WebAttributes.AUTHENTICATION_EXCEPTION);
pageContext.setAttribute("errorMessage", e.getMessage());
%>
<h2 style="color: red;">${errorMessage}</h2>
</body>
</html>
Die Seite, die das Übergangsziel sein soll. Eine Fehlermeldung wird angezeigt.
namespace
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:sec="http://www.springframework.org/schema/security"
...>
<sec:http>
<sec:intercept-url pattern="/login" access="permitAll" />
<sec:intercept-url pattern="/max-session-error.jsp" access="permitAll" />
<sec:intercept-url pattern="/**" access="isAuthenticated()" />
<sec:form-login authentication-failure-url="/max-session-error.jsp" />
<sec:logout />
<sec:session-management>
<sec:concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
</sec:session-management>
</sec:http>
...
</beans>
Java Configuration
MySpringSecurityConfig.java
...
@EnableWebSecurity
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login").permitAll()
.antMatchers("/max-session-error.jsp").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.failureUrl("/max-session-error.jsp")
.and()
.sessionManagement()
.maximumSessions(1)
.maxSessionsPreventsLogin(true);
}
...
}
Melden Sie sich mit dem ersten Browser an.
Wenn Sie sich mit dem zweiten Browser anmelden, werden Sie zur angegebenen Fehlerseite (max-session-error.jsp
) weitergeleitet.
applicationContext.xml
<sec:intercept-url pattern="/login" access="permitAll" />
<sec:intercept-url pattern="/max-session-error.jsp" access="permitAll" />
<sec:intercept-url pattern="/**" access="isAuthenticated()" />
<sec:form-login authentication-failure-url="/max-session-error.jsp" />
--Wenn die Anzahl der Sitzungen die Obergrenze überschreitet und Sie versuchen, sich bei Form anzumelden, wird die Fehlerseite mit dem Attribut "Authentifizierungsfehler-URL" des Tags "
Warum wird die Angabe des Übergangsziels, wenn ein Fehler bei der Prüfung der maximalen Anzahl von Sitzungen auftritt, auf das Tag "
applicationContext.xml
<sec:session-management>
<sec:concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
</sec:session-management>
--Wenn Sie das Tag "
SessionManagementFilter
wartet nach UsernamePasswordAuthenticationFilter
.--SessionManagementFilter
ist für die Verarbeitung verantwortlich, wenn er durch nicht interaktive Authentifizierungsverarbeitung angemeldet ist.
Dies ist eine persönliche Vermutung und ich weiß nicht, ob sie korrekt ist </ font>
SessionManagementFilter
ein Filter nach UsernamePasswordAuthenticationFilter
ist, ist es nicht möglich, die Sitzungsprüfung zum Zeitpunkt der Formularanmeldung SessionManagementFilter
anzuvertrauen.
--Was passiert, wenn Sie "SessionManagementFilter" vor "UsernamePasswordAuthenticationFilter" setzen? Ich dachte, aber es kann sein, dass es überwältigend ist, "SessionManagementFilter", der nach erfolgreicher Anmeldung überprüft werden sollte, vor "UsernamePasswordAuthenticationFilter" zu setzen, wo die Anmeldeverarbeitung durchgeführt wird.Implementierung
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:sec="http://www.springframework.org/schema/security"
...>
<sec:http>
<sec:intercept-url pattern="/login" access="permitAll" />
<sec:intercept-url pattern="/**" access="isAuthenticated()" />
<sec:form-login />
<sec:remember-me />
<sec:logout />
<sec:session-management>
<sec:concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
</sec:session-management>
</sec:http>
...
</beans>
** Betriebsergebnis **
Melden Sie sich mit aktiviertem Remember-Me an (Browser A).
Lassen Sie es eine Weile stehen und warten Sie, bis die Sitzung abgelaufen ist (vorausgesetzt, das Remember-Me-Token ist nicht abgelaufen).
Melden Sie sich mit einem anderen Browser (Browser B) an und zeichnen Sie den Bildschirm mit dem Timeout-Browser (Browser A) neu.
Sie werden zum 401-Fehlerbildschirm (Browser A) übersprungen.
Wenn Remember-Me das Sitzungslimit nicht überschreitet, führt dies standardmäßig zu einem 401-Fehler wie oben beschrieben und wird zur Serverfehlerseite übersprungen.
Um zu einem beliebigen Pfad zu springen, heißt es in der Referenz, dass Sie das Attribut "Sitzungsauthentifizierungsfehler-URL" des Tags "
If the second authentication takes place through another non-interactive mechanism, such as "remember-me", an "unauthorized" (401) error will be sent to the client. If instead you want to use an error page, you can add the attribute session-authentication-error-url to the session-management element. (Übersetzung) Wenn die zweite Authentifizierung durch einen anderen nicht interaktiven Mechanismus (z. B. Remember-Me) (außer Formularanmeldung) erfolgt, wird ein nicht autorisierter 401-Fehler an den Client gesendet. Wenn Sie stattdessen die Fehlerseite verwenden möchten, können Sie dem Element "Sitzungsverwaltung" das Attribut "Sitzungsauthentifizierungsfehler-URL" hinzufügen.
https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#ns-concurrent-sessions
Wenn Sie diesen Pfad jedoch tatsächlich angeben, tritt eine Umleitungsschleife auf.
Implementierung
my-login.jsp
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>My Login Page</title>
</head>
<body>
<h1>My Login Page</h1>
<c:url var="loginUrl" value="/login" />
<form action="${loginUrl}" method="post">
<div>
<label>Nutzername: <input type="text" name="username" /></label>
</div>
<div>
<label>Passwort: <input type="password" name="password" /></label>
</div>
<div>
<label>Remember-Me : <input type="checkbox" name="remember-me"></label>
</div>
<input type="submit" value="login" />
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
</form>
</body>
</html>
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:sec="http://www.springframework.org/schema/security"
...>
<sec:http>
<sec:intercept-url pattern="/login" access="permitAll" />
<sec:intercept-url pattern="/my-login.jsp" access="permitAll" />
<sec:intercept-url pattern="/**" access="isAuthenticated()" />
<sec:form-login login-page="/my-login.jsp" />
<sec:remember-me />
<sec:logout />
<sec:session-management session-authentication-error-url="/my-login.jsp">
<sec:concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
</sec:session-management>
</sec:http>
...
</beans>
** Betriebsergebnis **
Im Fall von Remember-Me wird die Anzahl der Sitzungen mit "SessionManagementFilter" überprüft. Hier wird die Umleitung zu der durch "Sitzungsauthentifizierungsfehler-URL" angegebenen URL durchgeführt.
Wenn Sie dann zur URL umgeleitet werden, wird eine Reihe von Filtern erneut ausgeführt, und Remember-Me meldet sich automatisch an, und SessionManagementFilter
überprüft die Anzahl der Sitzungen.
Natürlich tritt der Fehler erneut auf und die Umleitung erfolgt zu der durch "Sitzungsauthentifizierungsfehler-URL" angegebenen URL.
Infolgedessen tritt eine Umleitungsschleife auf.
Ich habe gesucht, aber ich konnte keine Probleme mit der gleichen Geschichte finden. Ich kann keine Problemumgehung finden.
Verstehe ich etwas falsch ...?
Dieses Verhalten tritt übrigens nicht auf, wenn Sie die Anmeldeseite verwenden, die Spring Security standardmäßig generiert. Dies wird vermieden, da der "DefaultLoginPageGeneratingFilter" vor dem "SessionManagementFilter" vorhanden ist und die Standard-Anmeldeseite vor der Wiederholung der Überprüfung der Sitzungsanzahl auf gewechselt wird.
Eine Beschreibung des Sitzungsfixierungsangriffs selbst finden Sie unter IPA-Erklärungsseite.
Als Gegenmaßnahme wird empfohlen, die Sitzungs-ID vor und nach der Anmeldung zu ändern. In Spring Security ist diese Gegenmaßnahme standardmäßig aktiviert, und die Sitzungs-ID ("JSESSIONID") wird vor und nach der Anmeldung geändert.
JSESSIONID
vor dem Login ist 376D515 ...
Anmeldung
Sie können sehen, dass die "JSESSIONID" nach der Anmeldung in "30194EA ..." geändert wurde.
Ob die Sitzungs-ID nach dieser Anmeldung geändert werden soll oder nicht, kann vorerst in den Einstellungen geändert werden.
namespace
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:sec="http://www.springframework.org/schema/security"
...>
<sec:http>
...
<sec:session-management session-fixation-protection="none" />
</sec:http>
...
</beans>
Java Configuration
MySpringSecurityConfig.java
...
@EnableWebSecurity
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
...
.and()
.sessionManagement()
.sessionFixation().none();
}
...
}
sessionFixation (). None ()
festlegenVor dem Login 8CC8D2 ...
Auch nach dem Einloggen von 8CC8D2 ...
Es hat sich nicht geändert. Ich kann mir jedoch keine Situation vorstellen, in der Sie "none" angeben müssen. .. ..
Sie können die folgenden Werte für "Sitzungsfixierungsschutz" angeben:
Wert | Erläuterung |
---|---|
none |
Ändern Sie die Sitzungs-ID nicht |
newSession |
Erstellen Sie eine neue Sitzung. Alle Attribute außer den von Spring Security verwalteten werden verworfen. |
migrateSession |
Erstellen Sie auch neue Sitzungs- und Portattribute (Servlet 3)..Standard in Umgebungen unter 0) |
changeSessionId |
HttpServletRequest Hinzugefügt zuchangeSessionId() Weisen Sie die ID mit (Servlet 3) neu zu..Standard in Umgebungen ab 1) |
Recommended Posts