专栏链接

一、数据的校验

  1. SQL注入
  2. 命令注入
  3. 跨站脚本
  4. 任意文件上传
  5. 任意文件下载
  6. 任意文件删除
  7. 任意文件读取与写入
  8. Iframe 框架钓鱼
  9. 负值支付漏洞

二、认证与授权

  1. 密码修改(无需原密码)
  2. 密码策略不足
  3. 用户名密码(敏感信息)明文传输
  4. 验证码可重复利用
  5. 缺少验证码功能
  6. 用户名枚举(用户名和密码单独验证)
  7. 登录尝试次数限制功能失效
  8. 登录后门
  9. 横向越权
  10. 纵向越权

三、Cookie与会话管理

  1. 直接关闭浏览器“退出“系统
  2. 会话标识未更新
  3. Cookie 中明文存储用户名、密码

四、错误处理

  1. 数据库交互中的异常处理

五、日志安全

  1. 日志记录敏感信息

六、未验证的重定向

  1. URL 重定向

认证与授权:验证码可重复利用

漏洞描述:

在采用验证码来防护攻击者暴力破解的时候,由于在服务端未能及时更新会话中保存的验证码,导致可以被重复使用。开发人员一般会认为自己明明已经在验证失败的时候会跳转到登录页面,而此时会自动刷新页面和会话中的验证码。殊不知在使用工具去发起请求的时候,可以不用将响应的内容交给浏览器去执行,这个时候也就不会去刷新验证码。

检测方法:

检查对于用户输入的验证码是否进行空串或 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 中取出验证码后,立即更新为空串,防止验证码可以重复使用的情况。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐