输入类型为“”时可能存在的危险和安全问题;“隐藏的”;使用Spring MVC

输入类型为“”时可能存在的危险和安全问题;“隐藏的”;使用Spring MVC,spring,security,spring-mvc,spring-security,httprequest,Spring,Security,Spring Mvc,Spring Security,Httprequest,我在我的项目Spring MVC和Thymeleaf中使用。假设我想实现非常简单的用法——编辑用户表单。我使用SessionalAttributes: @Controller @RequestMapping(value="/admin/") @SessionAttributes(value={"user"}) public class UsersController implements Serializable 在request GET I中,我们得到了简单的映射: @RequestMap

我在我的项目Spring MVC和Thymeleaf中使用。假设我想实现非常简单的用法——编辑用户表单。我使用SessionalAttributes:

@Controller
@RequestMapping(value="/admin/")
@SessionAttributes(value={"user"})
public class UsersController implements Serializable 
在request GET I中,我们得到了简单的映射:

@RequestMapping(value={"user/{id}", "{user/{id}/}"}, method=RequestMethod.GET)
public String edit(Model model, @PathVariable(value="id") Long id, RedirectAttributes redirectAttributes){
    String username = SecurityUtils.getLoggedUsername();    //for example, Spring Security
    User user = userService.getByIdAndUsername(id, username);
    model.addAttribute("user", user);
    return "admin/user";
}
简单-检查会话登录用户是否有权编辑具有指定ID的用户(在本例中,仅限其ID)。id为的字段不会通过“隐藏”字段填充到他的HTML表单上,它将存储在SessionAttributes中,并在调用POST方法后合并。 到现在为止,一直都还不错。但是有一个问题。如果-比方说-“非常聪明”的用户在他的HTML调试器中插入/使用手动添加的隐藏输入生成POST请求,并使用name=“user.id”(或general=“[object name].[object property]和call POST方法,该怎么办?SessionAttribute将不会合并,因为在我的HTTP请求中存在属性“id”

@RequestMapping(value="user/{id}", method=RequestMethod.POST)
    public String action(@ModelAttribute("user") User user, BindingResult bindingResult, Model model, RedirectAttributes redirectAttributes){
通过这种方式,任何人都可以编辑某人的ID(假设其他用户的ID已知)和编辑其他用户。如何保护系统的这一部分? 目前,我只有一个解决方案-将任何用户视为潜在窃贼,并使用与GET方法相同的方法检查POST方法:

@RequestMapping(value="user/{id}", method=RequestMethod.POST)
    public String action(User user, BindingResult bindingResult, Model model, RedirectAttributes redirectAttributes){
        String username = SecurityUtils.getLoggedUsername();    //for example, Spring Security
        User otherButTheSameUser = userService.getByIdAndUsername(id, username); //remember to evict this user from hibernate session
        if(otherButTheSameUser!=null){
            userService.update(user);
        }
    }

这应该足够安全,但SQL性能问题就来了,因为存在双重SQL检查查询。这是一种好方法吗?有没有其他方法可以实现这一点?也许可以将@SessionAttributes与具有SessionAttributes优先级的请求对象合并?如何实现这一点?据我所知,您可以利用或方法:

因此,我建议尝试以下方法:

@InitBinder
protected void initBinder(WebDataBinder binder) {
    // please check that it's really working
    binder.setDisallowedFields("user.id");
}

是的,“setDisallowedFields”是一个很好的解决方案,但据我所知,您必须指定具体字段的列表,而不是通过“user.*”放置所有字段,因为用户表单中允许修改的任何字段都不会更改。是的,我已更新了我的答案。但我还试图表明,您可以使用星号作为简单的regexp.1)带有尾随斜杠的映射是多余的。2)整个方法需要重新设计;在尝试修改时需要进行授权检查。这会使您现在遇到的问题消失。请注意,这并不是只适用于Spring MVC,而是基本上适用于任何绑定请求参数。例如,使用Spring Security,您可以简单地检查当前用户是否正在编辑同一个用户(不需要SQL,只需要一个带有SpEL表达式的
@PreAuthorize
注释)。
@InitBinder
protected void initBinder(WebDataBinder binder) {
    // please check that it's really working
    binder.setDisallowedFields("user.id");
}