越权问题的解决方案

一、横向越权和纵向越权

越权定义:一个正常的用户A通常只能够对自己的一些信息进行增删改查,但是由于程序员的一时疏忽未对信息进行增删改查的时候没有进行一个判断,判断所需要操作的信息是否属于对应的用户,可以导致用户A可以操作其他人的信息。​

横向越权定义:攻击者尝试访问与他拥有相同权限的用户的资源。Web应用程序接收到用户请求,修改某条数据时,没有判断数据的所属人,或者在判断数据所属人时从用户提交的表单参数中获取了userid。导致攻击者可以自行修改userid修改不属于自己的数据。所有的更新语句操作,都可能产生这个漏洞。

纵向越权定义:低级别攻击者尝试访问高级别用户的资源。由于Web应用没有做权限控制,或仅仅在菜单上做了权限控制,导致恶意用户只要猜测其他管理页面的URL,就可以访问或控制其他角色拥有的数据或页面,达到权限提升的目的。

二、纵向越权问题的解决方案

建议使用基于角色访问控制机制来防止纵向越权攻击,即预先定义不同的权限角色,为每个角色分配不同的权限,每个用户都属于特定的角色,即拥有固定的权限,当用户执行某个动作或产生某种行为时,通过用户所在的角色判定该动作或者行为是否允许。

三、横向越权问题的解决方案

横向越权可能出现的场景有:在用户忘记密码重置密码时,回答对了问题进入密码重置阶段时,如果知道其他用户的用户名,很容易改变此用户的密码,然后就可以进行越权访问了。
这种情况下为了防止横向越权,我们可以使用缓存来进行辅助,当问题回答正确时,我们在缓存中存储一对由用户名和一个唯一的数字组成的数据,然后返回放入的唯一数据。在重置密码时我们的参数不仅需要用户名和密码还需要前面生成的唯一数字,根据用户名在缓存中取出对应的数字,如果取出的数字和参数中传入的相等,则证明重置的当前用户的密码,否则不是,且不予以重置,并且缓存中的唯一数据是有时间限制的,这样可以进一步提高安全性。
重置密码回答问题

public ServerResponse<String> checkAnswer(String username, String question, String answer){
        int resultCount = userMapper.checkAnswer(username, question, answer);
        if(resultCount>0){
            //说明问题及问题答案是用户的,并且是正确的
            String forgetToken = UUID.randomUUID().toString();
            //放入缓存
            TokenCache.setKey(TokenCache.TOKEN_PREFIX+username, forgetToken);
            return ServerResponse.createBySuccess(forgetToken);
        }
        return ServerResponse.createByError("用户答案错误");
    }

重置密码

 public ServerResponse<String> forgetResetPassword(String username, String passwordNew, String forgetToken){
        if(StringUtils.isBlank(forgetToken)){
            return ServerResponse.createByError("参数错误,Token需要传递");
        }
        ServerResponse validResponse = this.checkValid(username, Const.USERNAME);
        if(validResponse.isSuccess()){
            return ServerResponse.createByError("用户不存在");
        }
        //使用Cache而不使用session是因为当应用程序结束时,如果缓存的失效时间未到,则下次启动程序时,缓存数据依然存在
        //但是Seesion中的数据只保存在一次会话中,session容易丢失不够安全,而Cache不会出现这种问题
        String token = TokenCache.getKey(TokenCache.TOKEN_PREFIX+username);
        if(StringUtils.isBlank(token)){
            ServerResponse.createByError("token无效或过期");
        }
        if(StringUtils.equals(token, forgetToken)){
            String md5Password = MD5Util.MD5EncodeUtf8(passwordNew);
            int resultCount = userMapper.updatePasswordByUsername(username, md5Password);
            if(resultCount>0){
                return ServerResponse.createBySuccess("修改密码成功");
            }
        }else{
            return ServerResponse.createByError("token错误,请重新获取修改密码的token");
        }
        return ServerResponse.createByError("密码更新失败");
    }
发布了160 篇原创文章 · 获赞 271 · 访问量 24万+

猜你喜欢

转载自blog.csdn.net/q982151756/article/details/104083325