如何防止数据库字段注入?(How to prevent database field injecti

2019-11-05 11:55发布

我有一个模型 ,以下面的方式描述:

@Table
@Entity
@Data
@Builder
@ToString
@EqualsAndHashCode
@AllArgsConstructor
@NoArgsConstructor
public class User {
    // ...skipped...
    private String foo;
}

我也有,创建一个新的实体的方法的服务

@Service
public class UserService {
    // ...skipped...
    public User createUser(User user) {
        Date currentDate = new Date();
        user.setCreated(currentDate);
        userRepository.save(user);
        return user;
    }
}

我也有一个控制器和一个映射方法:

@Controller
@RequestMapping(UserRouteRegistry.FIRST_LEVEL + "/*")
public class UserController {
    // ...skipped...
    @PostMapping(UserRouteRegistry.SIGN_UP)
    public String signUp(
            @ModelAttribute("user") @Validated(User.CreateUserGroup.class) User user,
            BindingResult result,
            WebRequest request,
            RedirectAttributes redirectAttributes
    ) {
    // ...mercellessly skipped...
                userRegistered = userService.createUser(user);
    // ...mercellessly skipped...
    }

一切都非常简单,不是吗?

我没有在foo在网络表单字段,我并不需要一个网络用户设置此字段,它应该是一些非常私人领域,不应该由网络用户直接受到影响。

当我做一个自定义的POST请求,我看到了一个新的实体正在与创建foo通过在请求中设定的数据填充字段:

POST /user/sign-up HTTP/1.1
Host: 127.0.0.1:8080
Origin:  http://127.0.0.1:8080
Content-Type: application/x-www-form-urlencoded
Referer:  http://127.0.0.1:8080/user/sign-up
Cookie:  SL_G_WPT_TO=ru; SL_GWPT_Show_Hide_tmp=1; SL_wptGlobTipTmp=1; BL_D_PROV=; BL_T_PROV=; JSESSIONID=E1190293BD183C647245BAE03E6DCDDA
cache-control: no-cache
Postman-Token: e572bccf-ff0a-4b0b-a181-dd0aa20dca99
foo=13
> SELECT foo FROM user ORDER BY id DESC LIMIT 1 \G
*************************** 1. row ***************************
foo: 13
1 row in set (0.0005 sec)

是的,这似乎很正确,但还有什么办法阻止 ,不知怎的?

分配“私人”领域null服务水平值? 这将是非常乏味,但它会工作。 设置一些@annotation(顺便说一下,它应该是什么样的注释?)在模型上水平这个领域? 我不知道这将是合乎逻辑的,因为我的意见。 在过滤控制器级别的参数,地方列出所有允许的吗? 可能是这样?

什么是正确的方法是什么?

谢谢!

Answer 1:

这是一个很好的做法,模型和DTO分开 - 你之间传递DTO前端和后端控制器 - 因为有时可以有很多更多的只是一个字段,以排除或不同的处理。 此外,它可以是该领域需要在其他一些情况下,因此不能排除在模型本身。

所以,当你的控制器现在收到User模式应该得到UserDTO只具有所需的允许领域。

当然,这使事情变得有点困难,因为你那么需要映射UserDTO之间的User 。 但幸运的是有库的处理,也喜欢ModelMapper 。



Answer 2:

你可以忽略反序列化的那场

@JsonProperty(access = Access.READ_ONLY)
private String zaloopa;


Answer 3:

如果你要发送表单数据 ,那么你可以通过创建注释的方法也这样做即低于@InitBinder方法,然后设置上所提供的不允许字段列表WebDataBinder实例。

这种方法可以添加到您的控制器,Spring MVC的控制器意见或两者兼而有之。 对于由您可以添加在控制器的意见,然后注册相关的控制器上的其他实体特定字段的所有实体共享领域。

@InitBinder()
public void initBinder(WebDataBinder binder) {
    binder.setDisallowedFields(new String[] { "id", "version" });
}

如果你发布JSON数据 ,那么你可以通过杰克逊注解的方式这样做。 你可以把这些直接的实体的领域,或者您可以使用杰克逊混入类,以避免给“污染”与Web层的关注域模型。

注释领域无论是在实体或混入:

@JsonProperty(access = Access.READ_ONLY)
private String myField;

要注册一个mixin:

@Bean
public Jackson2ObjectMapperBuilderCustomizer addMixin(){
    return new Jackson2ObjectMapperBuilderCustomizer() {
        @Override
        public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) {
            jacksonObjectMapperBuilder.mixIn(User.class, UserMixin.class);                
        }
    };
}


文章来源: How to prevent database field injection?