JAVA开发常见安全问题:验证码可重复利用
·
专栏链接
一、数据的校验
二、认证与授权
三、Cookie与会话管理
四、错误处理
五、日志安全
六、未验证的重定向
认证与授权:验证码可重复利用
漏洞描述:
在采用验证码来防护攻击者暴力破解的时候,由于在服务端未能及时更新会话中保存的验证码,导致可以被重复使用。开发人员一般会认为自己明明已经在验证失败的时候会跳转到登录页面,而此时会自动刷新页面和会话中的验证码。殊不知在使用工具去发起请求的时候,可以不用将响应的内容交给浏览器去执行,这个时候也就不会去刷新验证码。
检测方法:
检查对于用户输入的验证码是否进行空串或 null 值判断, 是否用户不输入验证码或者直接丢掉验证码参数也能通过。
检查使用验证码的代码中是否及时删除或更新会话中保存的验证码。
不合规的代码示例:
public String postComplaintInfo(){
try{
HttpServletRequest request=Struts2Util.getRequest();
echnContext = new EchnContext(); //初始化
//echnContext
echnContext.setRequest(request);
//图片验证码校验
String session_seccode = (String)request.getSession().getAttribute("rand")==null?"":(String)request.getSession().getAttribute("rand");
logger.debug("session 中的验证码:" +
session_seccode + ",用户输入的验证码:"+randomCode); if(session_seccode.equals("")|| !randomCode.equalsIgnoreCase(session_seccode)){
retMsg ="验证码错误,请重新输入!";
return ERROR;
}
String loginPhoneType = request.getSession().getAttribute(Constant.LOGIN_PHONE_ TYPE)==null?"":(String) request.getSession().getAttribute(Constant.LOGIN_PHONE_ TYPE);
if("0".equals(loginPhoneType)||"3".equals(loginPhoneTyp e)){
funcCode = "100003";
}else{
funcCode = "100005";
}
LogInfo logInfo = new LogInfo(); logStep = "1";
//操作日志
Tw_servopt_log tw_servopt_log = new Tw_servopt_log();
tw_servopt_log.setBusi_code(funcCode); //
tw_servopt_log.setServ_type("3"); //操作类型0:开通 1:取消,2.变更 3:查询
tw_servopt_log.setStep(logStep); //业务的最后一步记录 1。如业务办理只有订购时记录 1
tw_servopt_log.setClass_id(""); //业务办理录分类 id 录产品 id
tw_servopt_log.setProd_id(""); //业务办理记tw_servopt_log.setProd_prc_id(""); //业务办理记录资费 id
logInfo.setTw_servopt_log(tw_servopt_log); echnContext.setLogInfo(logInfo);
NewWorkSheetIn in = new NewWorkSheetIn();
in.setPhone_no(phoneNo); in.setBizType(busiType);
in.setContactName(userName); in.setContactNo1(teleNo);
in.setEmailAddress(emailAdd);
in.setCaseContent(tContent); in.setContactAddress(address);
in.setCityCode(null==SessionUtil.getRegionId(echnContext)?"":SessionUtil.getRegionId(echnContext));
retInfo = custSrvImpl.newWorkSheetByWebHall(echnContext,in);
if(Constant.SUCCESS_RESULT.equals(retInfo.getResult()))
{
retMsg = retInfo.getRetMsg();
return SUCCESS;
}else{
retMsg = retInfo.getRetMsg(); return ERROR;
}
} catch (Throwable e) {
e.printStackTrace(); retMsg = "业务办理失败"; return ERROR;
}finally{
if(!((null ==
SessionUtil.getSession(echnContext)) || (null == RelateFuncCodeUtil.getOpCode(funcCode)) || ("".equals(RelateFuncCodeUtil.getOpCode(funcCode))) || (null == logStep) || (!"1".equals(logStep)))){
LoggerUtil.addlog(SessionUtil.getPhoneNo(echnContext), RelateFuncCodeUtil.getOpCode(funcCode), retInfo.getOptTime(), IPUtil.getClinetIpByReq(echnContext.getRequest()), ("0".equals(retInfo.getResult())?"0":"1"));
}
}
}
public String postComplaintInfo(){
try{
HttpServletRequest request=Struts2Util.getRequest();
echnContext = new EchnContext();
//初始化echnContext
echnContext.setRequest(request);
//图片验证码校验
String session_seccode = (String)request.getSession().getAttribute("rand")==null?"":(String)request.getSession().getAttribute("rand");
logger.debug("session 中的验证码:" +session_seccode + ",用户输入的验证码:"+randomCode);
if(session_seccode.equals("")||!randomCode.equalsIgnoreCase(session_seccode)){
retMsg ="验证码错误,请重新输入!";
return ERROR;
}
String loginPhoneType = request.getSession().getAttribute(Constant.LOGIN_PHONE_TYPE)==null?"":(String) request.getSession().getAttribute(Constant.LOGIN_PHONE_ TYPE);
if("0".equals(loginPhoneType)||"3".equals(loginPhoneTyp e)){
funcCode = "100003";
}else{
funcCode = "100005";
}
LogInfo logInfo = new LogInfo();
logStep = "1";
//操作日志
Tw_servopt_log tw_servopt_log = new Tw_servopt_log();
tw_servopt_log.setBusi_code(funcCode); // 功能代码
tw_servopt_log.setServ_type("3"); //操作类型0:开通 1:取消,2.变更 3:查询
tw_servopt_log.setStep(logStep); //业务的最后一步记录 1。如业务办理只有订购时记录 1
tw_servopt_log.setClass_id(""); //业务办理记录分类 id 录产品 id
tw_servopt_log.setProd_id(""); //业务办理记tw_servopt_log.setProd_prc_id(""); //业务办理记录资费 id
logInfo.setTw_servopt_log(tw_servopt_log); echnContext.setLogInfo(logInfo);
NewWorkSheetIn in = new NewWorkSheetIn();
in.setPhone_no(phoneNo);
in.setBizType(busiType);
in.setContactName(userName);
in.setContactNo1(teleNo);
in.setEmailAddress(emailAdd);
in.setCaseContent(tContent);
in.setContactAddress(address);
in.setCityCode(null==SessionUtil.getRegionId(echnContex)?"":SessionUtil.getRegionId(echnContext));
retInfo = custSrvImpl.newWorkSheetByWebHall(echnContext,in);
if(Constant.SUCCESS_RESULT.equals(retInfo.getResult()))
{
retMsg = retInfo.getRetMsg();
return SUCCESS;
}else{
retMsg = retInfo.getRetMsg();
return ERROR;
}
} catch (Throwable e) {
e.printStackTrace(); retMsg = "业务办理失败"; return ERROR;
}finally{ if(!((null ==
SessionUtil.getSession(echnContext)) || (null == RelateFuncCodeUtil.getOpCode(funcCode)) || ("".equals(RelateFuncCodeUtil.getOpCode(funcCode))) || (null == logStep) || (!"1".equals(logStep)))){
不合规说明:
程序在比较完验证码之后,并未更新 session 中保存的验证码,造成可以重复使用。
合规的代码示例:
public String postComplaintInfo(){
try{
HttpServletRequest request=Struts2Util.getRequest();
echnContext = new EchnContext(); //初始化
echnContext = echnContext.setRequest(request);
//图片验证码校验
String session_seccode = (String)request.getSession().getAttribute(""rand"")==null?"""":(String)request.getSession().getAttribute(""ran d"");
request.getSession().setAttribute(""rand"","""");
logger.debug(""session 中的验证码:"" +
session_seccode + "",用户输入的验证码:""+randomCode);
if(session_seccode.equals("""")||!randomCode.equalsIgnoreCase(session_seccode)){
retMsg =""验证码错误,请重新输入!"";
return ERROR;
}
String loginPhoneType = request.getSession().getAttribute(Constant.LOGIN_PHONE_ TYPE)==null?"""":(String) request.getSession().getAttribute(Constant.LOGIN_PHONE_ TYPE);
if(""0"".equals(loginPhoneType)||""3"".equals(loginPhon eType)){
funcCode = ""100003"";
}else{
funcCode = ""100005"";
}
LogInfo logInfo = new LogInfo();
logStep = ""1"";
//操作日志
Tw_servopt_log tw_servopt_log = new Tw_servopt_log();
tw_servopt_log.setBusi_code(funcCode); // 功能代码
tw_servopt_log.setServ_type(""3""); //操作类型0:开通 1:取消,2.变更 3:查询
tw_servopt_log.setStep(logStep); //业务的最后一步记录 1。如业务办理只有订购时记录 1
tw_servopt_log.setClass_id(""""); //业务办理记录分类 id
tw_servopt_log.setProd_id(""""); //业务办理记录产品 id
tw_servopt_log.setProd_prc_id(""""); //业务办理记录资费 id
logInfo.setTw_servopt_log(tw_servopt_log); echnContext.setLogInfo(logInfo);
NewWorkSheetIn in = new NewWorkSheetIn(); in.setPhone_no(phoneNo); in.setBizType(busiType); in.setContactName(userName); in.setContactNo1(teleNo); in.setEmailAddress(emailAdd); in.setCaseContent(tContent); in.setContactAddress(address);
in.setCityCode(null==SessionUtil.getRegionId(echnContext)?"""":SessionUtil.getRegionId(echnContext));
retInfo = custSrvImpl.newWorkSheetByWebHall(echnContext,in);
if(Constant.SUCCESS_RESULT.equals(retInfo.getResult()))
{
retMsg = retInfo.getRetMsg();
return SUCCESS;
}else{
retMsg = retInfo.getRetMsg();
return ERROR;
}
} catch (Throwable e) {
e.printStackTrace(); retMsg = ""业务办理失败"";
return ERROR;
}finally{
if(!((null ==
SessionUtil.getSession(echnContext)) || (null == RelateFuncCodeUtil.getOpCode(funcCode)) || ("""".equals(RelateFuncCodeUtil.getOpCode(funcCode)))|| (null == logStep) || (!""1"".equals(logStep)))){
LoggerUtil.addlog(SessionUtil.getPhoneNo(echnContext), RelateFuncCodeUtil.getOpCode(funcCode),retInfo.getOptTime(), IPUtil.getClinetIpByReq(echnContext.getRequest()), (""0"".equals(retInfo.getResult())?""0"":""1""));
}
合规说明:
从 session 中取出验证码后,立即更新为空串,防止验证码可以重复使用的情况。
更多推荐



所有评论(0)