“This is my 12th day of the November Gwen Challenge.The final text challenge in 2021”.

preface

Because HTTP is a stateless protocol, every request is the same to the server, and there is no state to distinguish whether the request comes from different users so that the server can provide different services. So we need some mechanism to record the identity information of different users. And that mechanism is Session and that’s where cookies come into play

  • When a client first requests a server
  • The server generates a sessionId for the user, saves it in a cookie, and brings it back to the client, which saves the cookie.
  • The client carries the cookie with each subsequent request
  • The server can easily tell which user the request is from.

However, for security reasons, sometimes users disable cookies in the browser. In this case, the URL can be used to re-concatenate the sessionId behind the new URL and return it to the authorized user.

1. Defend against fixed session attacks

Session attacks

  • The attacker accesses the system normally, and the system assigns a sessionId to the attacker
  • The attacker forged a system login link with his sessionId
  • The victim logged in using the link, so the sessionId is bound to the user’s information
  • An attacker can use the sessionId in his hand to impersonate a victim

When we log in successfully, we will generate a new onesession, can be avoided

Spring Security comes with this functionality, and its HTTP firewall will help you block any concatenated invalid urls

SessionManagement is a configurator of sessionManagement. There are four strategies to defend against session fixed attacks:

  • None: No changes are made and the old session is used after login.
  • NewSession: creates a newSession after login.
  • MigrateSession: Creates a new session after logging in and copies the data in the old session.
  • ChangeSessionId: Instead of creating a new session, use the session fixation protection provided by the Servlet container.

MigrateSession is enabled by default and can be modified if necessary.

@Override
protected void configure(HttpSecurity http) throws Exception {
    JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
    jdbcTokenRepository.setDataSource(dataSource);
    http.authorizeRequests()
        .antMatchers("/admin/api/**").hasRole("ADMIN")
        .antMatchers("/user/api/**").hasRole("USER")
        .antMatchers("/app/api/**"."/captcha.jpg").permitAll()
        .anyRequest()
        .authenticated()
        .and()
        .formLogin()
        //AuthenticationDetailsSource
        // .authenticationDetailsSource(myWebAuthenticationDetailsSource)
        .loginPage("/myLogin.html")
        // Specify the path to process the login request. Modify the path of the request. The default path is /login
        .loginProcessingUrl("/mylogin").permitAll()
        .failureHandler(new MyAuthenticationFailureHandler())
        .and()
        // Add automatic login function, default hash encryption
        .rememberMe()
        .userDetailsService(myUserDetailsService)
        .tokenRepository(jdbcTokenRepository)
        // Set the sessionManagement policy
        .and()
        .sessionManagement()
        .sessionFixation()
        .none()
        .and()
        .csrf().disable();
    	/ / add filter before UsernamePasswordAuthenticationFilter
    http.addFilterBefore(new VerificationCodeFilter(), UsernamePasswordAuthenticationFilter.class);
}
Copy the code

Session expiration

You can configure a session expiration policy

  • Overdue jump
    .sessionManagement()
      .invalidSessionUrl("/")
    Copy the code
  • Expiration time
    The minimum limit is 60 seconds. If it is less than 60, it will be corrected to 60 seconds
    server:
      servlet:
        session:
          timeout: 90
    Copy the code

Session concurrency control

  • Remote login Deletes the current login user

    .sessionManagement()
        // Set the maximum number of sessions to 1
        .maximumSessions(1)
    Copy the code

    Re-login on another client will squeeze out the account previously logged in, and the previous page will be displayed

    This session has been expired (possibly due to multiple concurrent logins being attempted as the same user).
    Copy the code

    Specific implementation can see ConcurrentSessionControlAuthenticationStrategy class source code.

  • You have logged in. Remote login is prohibited

    .sessionManagement()
        // Set the maximum number of sessions to 1
        .maximumSessions(1)
        // Prevents new sessions from logging in. Default is false
        .maxSessionsPreventsLogin(true)
    Copy the code

    The remote login failed. Procedure

    {
       "error_code": 401."error_name":"org.springframework.security.web.authentication.session.SessionAuthenticationException"."message": "Request failed,Maximum sessions of 1 for this principal exceeded"
    }
    Copy the code

    It seems that there is no problem, but we logged out of the session (by request /logout) and then tried to log in again, but it was still not logged in. This is because we triggered the table-related cleaning of session information by listening to the session’s destruction, but we have not registered the relevant listener. As a result, Spring Security cannot properly clean up expired or deregistered sessions.

    In a Servlet, the way to listen for session-related events is to implement the HttpSessionListener interface and register the listener with the system.

    Spring Security is realized in HttpSessionEventPublisher class HttpSessionEventPublisher interface, and translating the Spring event mechanism.

    In the Spring event mechanism, the publishing and subscription of events are hosted by the Spring container, so we can easily subscribe to the events we care about by registering beans.

    @Bean
    public HttpSessionEventPublisher httpSessionEventPublisher(a){
        return new HttpSessionEventPublisher();
    }
    Copy the code

Note:principalsUsing user information askeyThe design must be overriddenUserhashCodeequalsTwo methods

Cluster session solution

When the system is clustered, requests are usually concentrated on one middleware (Nginx) and then forwarded to the corresponding service to achieve load balancing. I have logged in to service A, but when the request is forwarded to service B, the user has to log in again. This is A typical session state cluster out of sync problem.

Common solutions:

  • sessionkeep
    • An IP hash load policy is typically used to forward requests from the same client to the same server for processing.
    • The load is unbalanced to some extent
  • sessioncopy
    • Session replication refers to synchronizing session data between cluster servers so that the session status of each instance is consistent.
    • It consumes data bandwidth and takes up a lot of resources.
  • sessionShared
    • Session sharing means that sessions are removed from the server memory, stored in an independent data container, and shared by all servers.
    • Independent data containers increase network interaction, and the read/write performance, stability, and network I/O speed of data containers become performance bottlenecks.

Five, the integration ofSpring SessionResolve cluster session problems

Session sharing is essentially a change of storage container

Spring SessionSupports multiple types of storage containers

Redis based integration

  • Introduce dependencies for the project
<! -- Spring Session interconnect with Redis
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
</dependency>
<! -- Spring Boot -- Redis
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
Copy the code
  • Spring Sessions can then be configured, primarily to provide a cluster-supported Session registry for Spring Security.
  • Modifying a Configuration File
spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://localhost:3306/springSecurityDemo? useUnicode=true&&characterEncoding=utf8&&useSSL=false&&serverTimezone=Asia/Shanghai
    driver-class-name: com.mysql.cj.jdbc.Driver
  redis:
    host: 127.0. 01.
    port: 6379
    database: 2
    timeout: 1000s
  session:
    store-type: redis
    timeout: 1800000
Copy the code
  • Restart project Login
  • View through the Redis client