guava cache实现防止横向越权

一、问题:忘记密码,在非登录状态下重设密码,回答成功密保问题后,跳转到重置密码页面,如果攻击者看到重设密码接口,就可以输入任意用户名和密码提交,如果用户名存在,就导致这个用户名下密码被修改。

为了防止这种横向越权,我们会在答对密保问题后服务端生成一个token返回。然后重设密码后,浏览器端把相应密码信息连token一起交给服务端。服务端借此验证是否为同一个token。

二、代码实现

我们用guava来实现。

(1)创建一个设置token的类

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;

@Slf4j
public class TokenCache {
    public static final String TOKEN_PREFIX = "token_";
    //LRU算法
    private static LoadingCache<String,String> localCache = CacheBuilder.newBuilder().initialCapacity(1000).maximumSize(10000).expireAfterAccess(12, TimeUnit.HOURS)
            .build(new CacheLoader<String, String>() {
                //默认的数据加载实现,当调用get取值的时候,如果key没有对应的值,就调用这个方法进行加载.
                @Override
                public String load(String s) throws Exception {
                    return "null";
                }
            });

    public static void setKey(String key,String value){
        localCache.put(key,value);
    }

    public static String getKey(String key){
        String value = null;
        try {
            value = localCache.get(key);
            if("null".equals(value)){
                return null;
            }
            return value;
        }catch (Exception e){
            log.error("localCache get error",e);
        }
        return null;
    }
}

(2)service

@Service("iUserService")
public class UserServiceImpl implements IUserService {
    @Autowired
    private UserMapper userMapper;
    public ServerResponse<String> checkAnswer(String username,String question,String answer){
        int resultCount = userMapper.checkAnswer(username,question,answer);
        if(resultCount>0){
            //说明问题及问题答案是这个用户的,并且是正确的
            String portalToken = UUID.randomUUID().toString();
            TokenCache.setKey(TokenCache.TOKEN_PREFIX+username,portalToken);//设置token
            return ServerResponse.createBySuccess(portalToken);
        }
        return ServerResponse.createByErrorMessage("问题的答案错误");
    }

    public ServerResponse<String> forgetResetPassword(String username,String passwordNew,String portalToken){//前端传来token
        if(StringUtils.isBlank(portalToken)){
            return ServerResponse.createByErrorMessage("参数错误,token需要传递");
        }
        String token = TokenCache.getKey(TokenCache.TOKEN_PREFIX+username);//获取token
        if(StringUtils.isBlank(token)){
            return ServerResponse.createByErrorMessage("token无效或者过期");
        }
        if(StringUtils.equals(portalToken,token)){//两个token比较
            String md5Password  = MD5Util.MD5EncodeUtf8(passwordNew);
            int rowCount = userMapper.updatePasswordByUsername(username,md5Password);//重设密码
            if(rowCount > 0){
                return ServerResponse.createBySuccessMessage("修改密码成功");
            }
        }else{
            return ServerResponse.createByErrorMessage("token错误,请重新获取重置密码的token");
        }
        return ServerResponse.createByErrorMessage("修改密码失败");
    }
}

这样条用service接口就可以了。


猜你喜欢

转载自blog.csdn.net/weixin_40459875/article/details/80034267
今日推荐