SpringCloud微服务安全实战API安全 3-5 认证

Posted 鮀城小帅

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringCloud微服务安全实战API安全 3-5 认证相关的知识,希望对你有一定的参考价值。

1. 常见问题

日常开发中会遇到的问题:

  • 各种校验: 非空、唯一性等,用于保证数据的完整性
  • 密码加密:对密码进行加密存储,保证安全性
  • Https访问:保证数据传输的安全性

2. 各种校验

2.1 validation 校验

使用  javax.validation 提供的各种规则对参数进行校验

2.2 接口层面的校验

(1)在接口相关的参数上添加校验注解,如:@NotBlank(message="……")

    @NotBlank(message = "用户名不能为空")
    private String username;

    @NotBlank(message = "密码不能为空")
    private String password;

(2)接口形参添加 @Validated 注解开启校验

    @PostMapping
    public UserInfo create(@RequestBody  @Validated UserInfo user){
        return userService.create(user);
    }

(3)重启程序访问接口

测试数据:将username值赋为空串“”,这不符合要求,会被校验到

请求的返回值结果:

Response返回400状态码说明:客户端请求服务端发生错误,这符合我们的测试预期。

开发工具控制台打印校验结果:

从打印的信息可知,当前返回400是因为校验到 username 是空的,所以服务器后续流程没有继续下去。

2.3 数据库层面的校验

    @Column(unique = true)
    @NotBlank(message = "用户名不能为 null")
    private String username;

这是User.java类的参数,对数据库层面进行加密,也就是对插入到数据库的字段进行校验操作。这里虽然有添加了 @NotBlank(message="……") 注解做校验,但这个注解其实是逻辑层面的。它只会校验在代码层面是否为空。

在数据层面要使用 @Column(unique=true)、@Column 这样的注解做校验,前者加 unique 用于校验是否在数据库表中列是唯一的参数,@Column 用于校验插入DB的参数是否为空。

2.4 优化处理validated校验后的返回结果

当前返回给客户端的结果并没有有效的信息,不利于客户端做处理,而且也不适合直接将400状态码抛给用户。

(1)创建   ValidParamExceptionHandler.java 处理类

package com.imooc.security.filter;

import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName ValidParamExceptionHandler
 * @Description TODO
 * @Author wushaopei
 * @Date 2021/5/1 16:44
 * @Version 1.0
 */
@ControllerAdvice
public class ValidParamExceptionHandler {
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public Map<String, Object> allExceptionHandler(Exception e){
        Map<String, Object> map = new HashMap<>(2);
        if(e instanceof BindException) {
            BindException ex = (BindException)e;
            BindingResult bindingResult = ex.getBindingResult();
            StringBuilder errMsg = new StringBuilder(bindingResult.getFieldErrors().size() * 16);
            errMsg.append("Invalid request:");
            for (int i = 0 ; i < bindingResult.getFieldErrors().size() ; i++) {
                if(i > 0) {
                    errMsg.append(",");
                }
                FieldError error = bindingResult.getFieldErrors().get(i);
                errMsg.append(error.getField()+":"+error.getDefaultMessage());
            }
            map.put("errcode", 500);
            map.put("errmsg", errMsg.toString());

        }
        else {
            map.put("errcode", 500);
            map.put("errmsg", e.getMessage());
        }
        return map;
    }
}

(2)优化后的校验返回结果:

上图中,向前端返回的不再是400状态码,而是200。并且也将后台所发生的的问题代表请求处理有问题的 400状态码 以及 “用户名不能为空” 字段抛给了前端,这样有利于前端进行处理。

当然,这是一个比较粗糙的返回结果。最好还是返回一个json格式的结果,更有利于前端的处理。

3. 密码加密

通常用与业务相关的信息做加盐加密。

如:用户登录信息Token用 用户名+32位随机串+时间戳加密。

如果是简单使用用户信息,如:用户名+密码来做加密,这种方式是没有保证的。

3.1 注册用户——加密密码

        // 加密
        user.setPassword(SCryptUtil.scrypt(user.getPassword(),32768,8,1));

注册请求:

加密后的用户密码

3.2 Basic 重构密码校验,添加解密后校验密码

             if(user != null && !SCryptUtil.check(password,user.getPassword())){
                //认证通过,存放用户信息
                request.setAttribute("user", user);
            }

4. Https 访问

  1. 单向认证,就是传输的数据加密过了,但是不会校验客户端的来源 
  2. 双向认证,如果客户端浏览器没有导入客户端证书,是访问不了web系统的,找不到地址

大部分情况下,我们的项目都是双向认证的,使用Https能更安全的保证系统的安全性。

以上是关于SpringCloud微服务安全实战API安全 3-5 认证的主要内容,如果未能解决你的问题,请参考以下文章

Spring Cloud微服务安全实战_3-2_第一个API及注入攻击防护

Spring cloud微服务安全实战完整教程

SpringCloud微服务安全API安全 2-3 限流实现注入攻击防护

SpringCloud 微服务应用安全——Security

SpringCloud微服务安全网关安全 3-1 概述

SpringCloud微服务安全API安全 2-1 API安全概述