大数跨境
0
0

当心!SpringBoot错误的数据绑定带来安全隐患

当心!SpringBoot错误的数据绑定带来安全隐患 Spring全家桶实战案例
2024-08-31
0
导读:环境:SpringBoot3.2.51. 简介web请求的数据绑定涉及将请求参数绑定到模型对象。

环境:SpringBoot3.2.5



1. 简介

web请求的数据绑定涉及将请求参数绑定到模型对象。默认情况下,请求参数可以绑定到模型对象的任何公共属性,这意味着恶意客户端可以为模型对象中存在的属性提供额外的值,但这些属性并不期望被设置。所以在进行模型对象设计时需要仔细考虑,避免不合理的设计代理不必要的麻烦或安全问题。如下示例:

// 模型数据public class User {  private Integer age ;  private String name ;  private String password ;  private String email ;  // getters, setters}// 接口定义;这里只希望更新年龄字段age和邮箱email2个字段@GetMapping("/updateBasicInfo")public R updateAgeAndEmail(User user) {  // 更新操作  userMapper.updateUserInfo(user) ;  return R.success("更新成功") ;}// UserMapper#updateAgeAndEmail更新操作<update id="updateUserInfo" parameterType="com.pack.User">      UPDATE t_user      <set>          <if test="name != null and name != ''">              name = #{name},          </if>          <if test="email != null and email != ''">              email = #{email},          </if>          <if test="password != null and password != ''">              password = #{password},          </if>          <if test="age != null">              age = #{age},          </if>      </set>      WHERE id = #{id}</update>

在上面的示例代码中,我们通过User接收客户端的请求参数信息,注意这里参数前并没有添加@RequestBody注解,Spring也是可以根据你请求的参数进行数据绑定。

我们期望的是只更新age和email,但客户端请求中可能包含其他不需要更新的字段,那么直接在User实体上接收所有请求参数可能会导致意外的字段更新。

2. 解决办法

2.1 使用DTO

创建一个只包含你需要更新的字段的DTO类。这个DTO类将用于接收客户端的请求数据。然后,在你的服务层中,你可以将DTO的数据复制到你的User实体中,只更新必要的字段。

public class UserBasicDTO {    private Integer age ;    private String email ;  // getters and setters  }

Controller接口接收参数时使用UserBasicDTO对象。

@GetMapping("/updateBasicInfo")public R updateAgeAndEmail(UserBasicDTO dto)

这种方式挺好就是需要再定义一个类,有没有不定义类的方式呢?有,也是今天本篇文章的重点要介绍的。

2.2 使用@InitBinder注解

设置允许绑定的属性

通过WebDataBinder 对象设置 allowedFields 模式(区分大小写),以防止设置意外属性,如下示例:

@InitBinderpublic void initBinder(WebDataBinder binder) {  binder.setAllowedFields("age", "email") ;}

通过如上的设置后,不管你传入的有哪些参数,都只会绑定age和email字段。相反你也可以设置不允许绑定的字段

binder.setDisallowedFields("name", "password") ;

不过,"允许"配置比 "不允许"配置更受欢迎,因为它更明确,不容易出错。

设置构造函数绑定

默认情况下,构造函数和属性绑定都会被使用。如果只想使用构造函数绑定,可以通过 @InitBinder方法在控制器中本地或通过@ControllerAdvice 全局设置 WebDataBinder上的 declarativeBinding 标志。打开该标记可确保只使用构造函数绑定,而不使用属性绑定,除非配置了 allowedFields 模式,如下示例:

@InitBinderpublic void initBinder(WebDataBinder binder) {  // 设置构造函数绑定  binder.setDeclarativeBinding(true) ;}

接下来还需要修改User实体对象

public static class User {  private Integer age ;  private String name ;  private String password ;  private String email ;  public User(Integer age, String email) {    this.age = age ;    this.email = email ;  }}

请求的参数只会根据这里的构造函数进行绑定;如果有多个构造函数呢?

当定义多个构造函数后,程序将抛出错误。

@InitBinder其它高级配置

配置必须的字段

@InitBinderpublic void initBinder(WebDataBinder binder) {  binder.setRequiredFields("id") ;}

虽然实体中没有定义id,但是我们要求请求的参数中必须有id字段,否则将抛出下面异常。

添加验证器

你也可以添加自定义的参数验证器

@InitBinderpublic void initBinder(WebDataBinder binder) {  binder.addValidators(new UserValidator()) ;}// 自定义验证器public class UserValidator implements Validator {  public boolean supports(Class<?> clazz) {    return User.class.isAssignableFrom(clazz) ;  }  public void validate(Object target, Errors errors) {    User user = (User) target ;    if (user.getAge() < 0) {      errors.reject("user.error.age", "年龄错误") ;    }  }}// 接口添加注解@GetMapping("/model")public User model(@Valid User user)

当有错误,将抛出如下异常。

以上是本篇文章的全部内容,如对你有帮助帮忙点赞+转发+收藏

推荐文章

在SpringBoot中拦截修改请求Body的2种正确方式

SpringBoot异步任务@Async你真的会用吗?这6点细节你知道吗?

借一古老技术考察你对SpringBoot掌握程度

神器!API接口限流就是这么简单

请不要自己写!Spring Boot非常实用的内置功能

掌握Spring Boot最佳途径!就该如此做

高性能缓存神器Caffeine

基于SpringBoot支持任意文件在线预览

优雅重构Spring Boot代码,我用这6种策略消灭if else

强大!实时监控SpringBoot运行时状态及应用运行时信息(数据库, Redis,MQ等)

SpringBoot这几个工具类太有用了

警惕!SpringBoot错误发布事件,造成死锁Deadlock

接口响应慢?掌握这优化技巧速度飙升

一文让你彻底搞定Spring Security的基本使用

SpringBatch高阶应用:大数据批处理框架实战指南

强大的Spring Data 还能这么玩 Redis,太强了

@InitBinder注解会用吗?该如何使用?

放弃ThreadLocal!TTL真香

【声明】内容源于网络
0
0
Spring全家桶实战案例
Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
内容 832
粉丝 0
Spring全家桶实战案例 Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
总阅读7
粉丝0
内容832