background

Recently, the customer made a series of vulnerability scans for our system, and finally concluded the general vulnerabilities are as follows:

  1. Repeat user login
  2. Unauthorized interface
  3. The unauthorized access of the interface

In view of the above vulnerabilities, solutions are recorded in three articles for subsequent recall and learning. This paper first deals with the vulnerability of user repeated login

plan

Spring Boot is used to build the system, and Spring Security + JWT is used as the security framework

  1. After the user logs in successfully, the token is generated to the user and stored in redIS. The key value is the user name (ID). The value is the generated token
  2. The token information contained in the request parameters of users accessing the system again is intercepted and compared through filters
  3. If the token match is successful, the system permits the match. If the token match is unsuccessful, the two tokens are inconsistent. If the timestamp of the token match is larger than that of the token match, the current token is overwritten The time stamp is later than the token time in the current redis (token has been updated).

Thinking figure

The core code

  • Configuring filters

  • Filter implementation

RepeatLoginFilter.java

@Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String jwt = resolveToken(request); / / repeat login only check with legal JWT pass verification code as well as from those authentication request if (null = = JWT | | "null". EqualsIgnoreCase (JWT) | |! this.tokenProvider.validateToken(jwt)) { filterChain.doFilter(request, response); return; } if (isAccessAllowed(jwt)) { filterChain.doFilter(request, response); return; Logout logout(response); } /** ** Repeat login core verification * @param Token Current token * @return true Pass through */ private Boolean isAccessAllowed(String token) { Authentication authentication = this.tokenProvider.getAuthentication(token); String redisToken = redisTemplate.opsForValue().get(Constants.PREFIX_LOGIN_USER+authentication.getName()); // If redisToken is empty, enter redis if(! StringUtils.hasLength(redisToken)){ redisTemplate.opsForValue().set(Constants.PREFIX_LOGIN_USER+authentication.getName(),token, 86400, TimeUnit.SECONDS); return true; } // If (token.equals(redisToken)){return true; // If redistoken is larger than redistoken, redistoken is the latest token. If redistoken is larger than Redistoken, redistoken is the latest token. No release Date Date = this. TokenProvider. GetIssueAt (token); Date redisDate = this.tokenProvider.getIssueAt(redisToken); if(date.after(redisDate)){ redisTemplate.opsForValue().set(Constants.PREFIX_LOGIN_USER+authentication.getName(),token, 86400, TimeUnit.SECONDS); return true; }else{ return false; } /** * private String resolveToken(HttpServletRequest Request) {String bearerToken = request.getHeader("Authorization"); if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { return bearerToken.substring(7); } return null; } @param response */ private void logout(HttpServletResponse Response){ response.setStatus(HttpStatus.FORBIDDEN.value()); response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE); try { JSONObject resultObj = new JSONObject(); Resultobj.putonce ("data"," Account has been logged in elsewhere, please log in again "); response.getWriter().print(resultObj.toString()); } catch (IOException e) { e.printStackTrace(); }}Copy the code