Spring boot Spring REST secure仅删除拥有的(仅由应用程序最终用户创建的)资源

Spring boot Spring REST secure仅删除拥有的(仅由应用程序最终用户创建的)资源,spring-boot,rest,spring-security,Spring Boot,Rest,Spring Security,我试图找到如何安全(仅由所有者)删除REST资源的最佳解决方案 目标: 该资源只能由该资源的所有者/创建者(指其创建该资源的所有者/创建者)删除。 前提: 每次应用程序最终用户创建客户端帐户时,他都会收到一个JWT令牌 为了能够访问REST资源,客户端应该提供有效的JWT 通过客户过滤器对每个来电进行JWT验证: @组件公共类JwtRequestFilter扩展OncePerRequestFilter{ @Autowired private ClientAuthService c

我试图找到如何安全(仅由所有者)删除REST资源的最佳解决方案

目标: 该资源只能由该资源的所有者/创建者(指其创建该资源的所有者/创建者)删除。

前提:

  • 每次应用程序最终用户创建客户端帐户时,他都会收到一个JWT令牌

  • 为了能够访问REST资源,客户端应该提供有效的JWT

  • 通过客户过滤器对每个来电进行JWT验证:

    @组件公共类JwtRequestFilter扩展OncePerRequestFilter{

        @Autowired
        private ClientAuthService clientAuthService;
    
        @Autowired
        private JwtUtil jwtUtil;
    
        @Override
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
                throws ServletException, IOException {
    
            final String authorizationHeaderDate = request.getHeader("Date");
    
            if (authorizationHeaderDate != null){
    
                if (DateTimeUtil.isLaterInMinThenNow(
                        LocalDateTime.parse(authorizationHeaderDate,
                                DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")), 2)) {
    
                    final String authorizationHeader = request.getHeader("Authorization");
    
                    String username = null;
                    String jwt = null;
    
                    if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
                        jwt = authorizationHeader.substring(7);
                        username = jwtUtil.extractUsername(jwt);
                    }
    
                    if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
    
                        UserDetails userDetails = this.clientAuthService.loadUserByUsername(username);
    
                        if (jwtUtil.validateToken(jwt, userDetails)) {
                            UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken
                                    = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                            usernamePasswordAuthenticationToken
                                    .setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                            SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
                        }
                    }
                }
            }
    
            chain.doFilter(request, response);
        }
    
    }
    
  • 删除REST端点的当前实现是:

    @DeleteMapping("/clients/{id}")
    public ResponseEntity<Client> deleteClientById(@PathVariable(required = true) Long id){
        return ResponseEntity.ok(clientService.deleteClientById(id));
    }
    
    @DeleteMapping(“/clients/{id}”)
    public ResponseEntity deleteClientById(@PathVariable(required=true)长id){
    返回ResponseEntity.ok(clientService.deleteClientById(id));
    }
    
  • 让每个拥有有效JWT的最终用户删除另一个最终用户客户端帐户

    对于黑客来说,很容易获得JWT、intuit客户端ID并逐个删除所有客户端帐户


    问题是:如何防止此类安全问题?

    您想使用Spring基于表达式的访问控制:

    您可以对REST端点方法或服务方法进行注释,并使用EL表达式对用户进行授权。以下是Spring文档中的一个示例,您可以进行调整:

    @PreAuthorize("#n == authentication.name")
    Contact findContactByName(@Param("n") String name);
    
    现在-您没有要求,但是您应该考虑遵守HTTP谓词,它使用与您的动作相匹配的HTTP谓词(即对于删除资源的请求使用删除HTTP动作):

    不要使用使用GET HTTP方法删除资源的REST服务-对于任何了解REST的人来说,这是没有意义的:

    @GetMapping(“/clients/{id}”)

    应该是


    @DeleteMapping(“/clients/{id}”)

    要使用Spring基于表达式的访问控制:

    您可以对REST端点方法或服务方法进行注释,并使用EL表达式对用户进行授权。以下是Spring文档中的一个示例,您可以进行调整:

    @PreAuthorize("#n == authentication.name")
    Contact findContactByName(@Param("n") String name);
    
    现在-您没有要求,但是您应该考虑遵守HTTP谓词,它使用与您的动作相匹配的HTTP谓词(即对于删除资源的请求使用删除HTTP动作):

    不要使用使用GET HTTP方法删除资源的REST服务-对于任何了解REST的人来说,这是没有意义的:

    @GetMapping(“/clients/{id}”)

    应该是


    @DeleteMapping(“/clients/{id}”)

    关于使用HTTP DELETE动词,您是完全正确的,对于阅读本主题的人来说。我建议将“您应该考虑”翻译为“强制性”(即使是spring、REST理论,也不要施加如此严格的限制)使用这些动词。我的错误只是一个愚蠢的复制/粘贴,我已经做了,但我还没有纠正。重新考虑这个问题,我会调查,并最终用一个例子来完成这个主题。非常感谢。事实上,情况是这样的:我会尝试看看是否有效,关于使用HTTP删除动词,你是完全正确的一读到这个话题,我建议把“你应该考虑”翻译成“强制性”(即使是弹簧、休息理论,也不要强加这样严格的限制)使用这些动词。我的错误只是一个愚蠢的复制/粘贴我已经做了,我还没有纠正。重新考虑这个问题,我会调查,并最终用一个例子来完成这个主题。非常感谢。事实上,情况是这样的:我会试着看看它是否也起作用