JAVA开发常见安全问题:Cookie 中明文存储用户名、密码

专栏链接

一、数据的校验

  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 重定向

Cookie与会话管理:Cookie 中明文存储用户名、密码

漏洞描述:

Cookie 的一个典型的应用是当登录一个网站时,网站往往会请求用户输入用户名和密码,并且用户可以勾选"下次自动登录"。如果勾选了,那么下次访问同一网站时,用户会发现没输入用户名和密码就已经登录了。这正是因为前一次登录时,服务器发送了包含登录凭据(用户名和密码)的 Cookie 到用户的硬盘上。从安全的角度来讲,用户名、密码需要经过某种加密形式加密后再存储。

不合规的代码示例:

java 复制代码
private ModelAndView userLogin(HttpServletRequest request, MuserLogin user, Model model, HttpServletResponse response, String companyId) throws Exception {
	if (!imageCodeCheck(request, IMAGE_CODE, OAConstants.IMAGE_CODE)) {
		return new ModelAndView("redirect:../?error_code=" +OAConstants.IMAGE_CODE_ERROR);
	}
	MuserLogin user1 = userLoginService.checkLogin(user.getUserCode(), MD5Tools.getStringMD5(user.getUserPass()), companyId);
	Map<String, Object> map = new HashMap<String, Object>();
	
	if (user1 == null) { 
		user1 = userLoginService.get(user.getUserCode());
		if (null != user1) { 
			Company comp =this.companyService.get(user1.getCompanyId()); // 用户名 存在取所属企业的删除标志
			if (ZERO.equals(comp.getDelFlag())) { // 为1 表示企业删除、用户名输入正确,密码输入错误的情况
				if (userLoginErrorCount(user1.getUserCode(), companyId)) {
					return new ModelAndView("redirect:../?error_code=9999");
				} else {
					// 更新用户登录失败次数
					MLoginError mle = new MLoginError();
					GetGuid guid = new GetGuid();
					mle.setLoginErrorCode(guid.getGuid());
					mle.setLoginErrorDate(new Date());
					mle.setUserCode(user1.getUserCode());
					mle.setLoginErrorIp(InetAddress.getLocalHost().toString());
					mle.setCompanyId(companyId);
					errorService.save(mle);
				}
			} else {
				return new ModelAndView("redirect:../?error_code=8888");
			}
		}
		return new ModelAndView("redirect:../?error_code=0001");
	} else {
		/***** 这段解决保存用户名,密码的 ****/
		String userCode = user.getUserCode();
		String userpd = user.getUserPass();
		String flag = StringTools.sqlInj(request.getParameter("ck"));
		String name = null;
		int ss = 0; // 判断是不是重复保存
		// set cookie
		GetGuid gid = new GetGuid();
		String guid = gid.getGuid();
		if (flag != null && flag.equals("1")){ 
			Cookie[] cookies = request.getCookies();
			for (int i = 0; cookies != null && i < cookies.length; i++) {
				if (cookies[i].getName().contains(COOKIE_USER)) {
					name = cookies[i].getValue().split(HORIZONTAL)[0];
					if (name.equals(userCode)){
						Cookie cook = new
						Cookie(cookies[i].getName(), null);
						cook.setMaxAge(0);
						cook.setPath(RIGHT_DIAGONAL);
						response.addCookie(cook);
						Cookie cookie = new
						Cookie(COOKIE_USER + guid, userCode + HORIZONTAL + userpd);
						cookie.setMaxAge(SIXTY * SIXTY * TWELVE);
						// cookie 保存半天
						cookie.setPath(RIGHT_DIAGONAL);
						response.addCookie(cookie);
					}
				}
			}
			ss = 1;
			break;
			if (ss == 0) {
				Cookie cookie = new Cookie(COOKIE_USER + guid, userCode + HORIZONTAL + userpd);
				cookie.setMaxAge(SIXTY * SIXTY * TWELVE); // cookie 保存半天
				cookie.setPath(RIGHT_DIAGONAL);
				response.addCookie(cookie);
			}
		} else {
			Cookie[] cookie = request.getCookies(); // 获取 cookie
			for (int i = 0; cookie != null && i < cookie.length; i++) {
				if (cookie[i].getName().contains(COOKIE_USER)) {
					Cookie cook = new
					Cookie(cookie[i].getName(), null);
					cook.setMaxAge(0);
					cook.setPath(RIGHT_DIAGONAL);
					response.addCookie(cook);
				}
			}
		}
		/*******************************/
		// 取所属企业的删除标志
		Company comp = this.companyService.get(companyId);
		if(!ZERO.equals(comp.getDelFlag())){ 
			return newModelAndView("redirect:../?error_code=8888");
		}
		if (userLoginErrorCount(user1.getUserCode(), companyId)) {
			return new ModelAndView("redirect:../?error_code=9999");
		}
		request.getSession(true).setAttribute(USER2, user1);
		model.addAttribute(OAConstants.USER_INFO_SESSION, user1);
		// 名为 Constants.USER_INFO_SESSION 的属性放到Session 属性列表中
		String viewName = DEFAULT;
		// 菜 单 树
		List<MFunctree> lstTree = mfunctreeService.getTreeListBySupFuncid(ZERO,
		user1.getUserCode(), companyId);
		map.put(TREE, lstTree);
		ModelAndView mav = new ModelAndView();
		mav.setViewName("redirect:" + viewName);
		mav.addObject(TREELIST, lstTree);
		//ip 地址 // 更新登录次数,最后登录时间,最后登录
		user1.setLastlogintime(new Date());
		int logincount = 0;
		try {
			logincount = user1.getLogincount();
		}catch(Exception ex){ 
			ex.printStackTrace() ;
		}
		user1.setLogincount(logincount + 1);
		user1.setLoginip(request.getLocalAddr());
		user1.setCompanyId(companyId);
		userLoginService.update(user1);
		// 记录操作日志
		String funcname = "登录";
		String operContent = "登录进入系统";
		String logKind = "I";
		String ouserCode = user1.getUserCode();String loginip =
		request.getRemoteHost();
		String cId = user1.getCompanyId();
		dLogService.saveDetail(funcname,
		operContent, logKind, ouserCode, loginip, cId);
		// 登 录 信 息Session 保 存
		LoginedUserInfo userinfo = new LoginedUserInfo();
		userinfo.setMuser(user1);
		MDepartment department = user1.getMDepartment();
		if (department != null) {
			userinfo.setDeptName(department.getDeptName());
		}
		MHeadShip headship = user1.getMHeadship();
		if (headship != null) {
			userinfo.setHeadshipName(headship.getRoleDesc());
		}
		Company company = this.companyService.get(userinfo.getMuser().getCompanyId());
		// 登录排名
		int order = userLoginService.getUserlogincountOrder(user1.getUserCode(), cId);
		userinfo.setLogin_number(order);
		request.getSession(true).setAttribute(OAConstants.SESSION_USERINFO, userinfo);
		request.getSession(true).setAttribute(COMPANY_ID,
		userinfo.getMuser().getCompanyId());
		request.getSession(true).setAttribute("password_",
		user.getUserPass());
		mav.addObject(COMPANY2, company);
		return mav;
		}
	}

不合规说明:

登录成功之后将用户名和密码明文存储在 Cookie 中。

合规的代码示例:

java 复制代码
private ModelAndView userLogin(HttpServletRequest request, MuserLogin user, Model model, HttpServletResponse response, String companyId) throws Exception {
	if (!imageCodeCheck(request, IMAGE_CODE, OAConstants.IMAGE_CODE)) {
		return new ModelAndView("redirect:../?error_code=" + OAConstants.IMAGE_CODE_ERROR);
	}
	// 将 用 户 名 和 密 码 进 行 解 密
	EncryptionDecryption des = new EncryptionDecryption("8e5d4a9e5c");
	try {
		user.setUserCode(des.decrypt(user.getUserCode()));
		user.setUserPass(des.encrypt(user.getUserPass()));
	} catch (Exception e) {
		e.printStackTrace();
	}
	MuserLogin user1 = userLoginService.checkLogin(user.getUserCode(),
	user.getUserPass(), companyId);
	Map<String, Object> map = new HashMap<String, Object>();
	if (user1 == null){ 
		user1 = userLoginService.get(user.getUserCode());
		if (null != user1) {
			Company comp = this.companyService.get(user1.getCompanyId()); // 用户名 存在取所属企业的删除标志
			if (ZERO.equals(comp.getDelFlag())) { 
				// 为1 表示企业删除、用户名输入正确,密码输入错误的情况
				if (userLoginErrorCount(user1.getUserCode(), companyId)) {
					return new ModelAndView("redirect:../?error_code=9999");
				} else {
					MLoginError();
					// 更新用户登录失败次数
					MLoginError mle = new
					GetGuid guid = new GetGuid();
					mle.setLoginErrorCode(guid.getGuid());
					mle.setLoginErrorDate(new Date());
					mle.setUserCode(user1.getUserCode());
					mle.setLoginErrorIp(InetAddress.getLocalHost().toString());
					mle.setCompanyId(companyId);
					errorService.save(mle);
				}
			} else {
				return new ModelAndView("redirect:../?error_code=8888");
			}
		}
		return new ModelAndView("redirect:../?error_code=0001");
	} else {
	/***** 这段解决保存用户名,密码的 ****/
	String userCode = user.getUserCode();
	String userpd = user.getUserPass();
	String flag = StringTools.sqlInj(request.getParameter("ck"));
	String name = null;
	int ss = 0; // 判断是不是重复保存
	// set cookie
	GetGuid gid = new GetGuid();
	String guid = gid.getGuid();
	if (flag != null && flag.equals("1")){ 
		Cookie[] cookies = request.getCookies();
		for (int i = 0; cookies != null && i < cookies.length; i++) {
			if (cookies[i].getName().contains(COOKIE_USER)) {
				name =cookies[i].getValue().split(HORIZONTAL)[0];
				if (name.equals(userCode)){
					Cookie cook = new Cookie(cookies[i].getName(), null);
					cook.setMaxAge(0);
					cook.setPath(RIGHT_DIAGONAL);
					response.addCookie(cook);
					Cookie cookie = new Cookie(COOKIE_USER + guid, des.encrypt(userCode) + HORIZONTAL + des.encrypt(userpd));//将用户名和密码进行加密
					cookie.setMaxAge(SIXTY * SIXTY * TWELVE); // cookie 保存半天
					cookie.setPath(RIGHT_DIAGONAL);
					response.addCookie(cookie);
					ss = 1;
					break;
				}
			}
		}
		if (ss == 0) {
			Cookie cookie = new Cookie(COOKIE_USER + guid,
			des.encrypt(userCode) + HORIZONTAL + des.encrypt(userpd));//将用户名和密码进行加密
			cookie.setMaxAge(SIXTY * SIXTY * TWELVE); // cookie 保存半天
			cookie.setPath(RIGHT_DIAGONAL);
			response.addCookie(cookie);
		}
	} else {
		Cookie[] cookie = request.getCookies(); // 获取 cookie
		for (int i = 0; cookie != null && i < cookie.length; i++) {
			if (cookie[i].getName().contains(COOKIE_USER)) {
				Cookie cook = newCookie(cookie[i].getName(), null);
				cook.setMaxAge(0);
				cook.setPath(RIGHT_DIAGONAL);
				response.addCookie(cook);
			}
		}
	}
	/*******************************/
	// 取所属企业的删除标志
	Company comp = this.companyService.get(companyId);
	if (!ZERO.equals(comp.getDelFlag())){ 
		return new ModelAndView("redirect:../?error_code=8888");
	}
	if (userLoginErrorCount(user1.getUserCode(), companyId)) {
		return new ModelAndView("redirect:../?error_code=9999");
	}
	model.addAttribute(OAConstants.USER_INFO_SESSION, user1);
	// 名为 Constants.USER_INFO_SESSION 的属性放到Session 属性列表中
	String viewName = DEFAULT;
	// 菜 单 树
	List<MFunctree> lstTree = mfunctreeService.getTreeListBySupFuncid(ZERO, user1.getUserCode(), companyId);
	map.put(TREE, lstTree);
	ModelAndView mav = new ModelAndView();
	mav.setViewName("redirect:" + viewName);
	mav.addObject(TREELIST, lstTree);
	// 更新登录次数,最后登录时间,最后登录 ip 地址
	user1.setLastlogintime(new Date());
	int logincount = 0;
	request.getSession(true).setAttribute(USER2, user1);
	}
	catch (Exception ex){ 
		ex.printStackTrace();
	}
	user1.setLogincount(logincount + 1);
	user1.setLoginip(request.getLocalAddr());
	user1.setCompanyId(companyId);
	userLoginService.update(user1);
	// 记录操作日志
	String funcname = "登录";
	String operContent = "登录进入系统";
	String logKind = "I";
	String ouserCode = user1.getUserCode();
	String loginip = request.getRemoteHost();
	String cId = user1.getCompanyId();
	dLogService.saveDetail(funcname, operContent, logKind, ouserCode, loginip, cId);
	try {
		logincount = user1.getLogincount();userinfo.setMuser(user1);
		MDepartment department = user1.getMDepartment();
		if (department != null) {
			userinfo.setDeptName(department.getDeptName());
		}
		MHeadShip headship = user1.getMHeadship();
		if (headship != null) {
			userinfo.setHeadshipName(headship.getRoleDesc());
		}
		Company company = this.companyService.get(userinfo.getMuser().getCompanyId());
		// 登录排名
		int order = userLoginService.getUserlogincountOrder(user1.getUserCode(), cId);
		LoginedUserInfo userinfo = new
		LoginedUserInfo();userinfo.setLogin_number(order);
		request.getSession(true).setAttribute(OAConstants.SESSION_USERINFO, userinfo);
		request.getSession(true).setAttribute(COMPANY_ID, userinfo.getMuser().getCompanyId());
		request.getSession(true).setAttribute("password_", user.getUserPass());
		mav.addObject(COMPANY2, company);
		return mav;
	}
}

合规说明:

登录成功之后将用户名和密码进行加密后存储在 Cookie中。

相关推荐
噢,我明白了15 分钟前
java中唯一键和幂等键的应用
java·后端
程序猿乐锅21 分钟前
【黑马点评 | 第八篇】Redisson分布式锁
java·数据库·spring boot·redis·分布式·spring·缓存
考虑考虑33 分钟前
synchronized字符串常量
java·后端·java ee
长谷深风1111 小时前
Tool与Skill:AI能力设计的分水岭
java·人工智能·ai·大模型·aiagent
m0_587383001 小时前
广州24小时自助健身房解决方案实战指南与系统部署要点
java·spring·小程序·架构·需求分析
Escalating_xu1 小时前
【C 语言】深入理解指针(1·下):指针运算、野指针、assert 与传址实战
java·c语言·开发语言
蒸鱼Yuzheng1 小时前
设备端性能工件可靠导出:断点续传、哈希、manifest 与失败恢复
android·自动化测试·python·adb·数据完整性
小蒋观天下1 小时前
两轮车检测AI摄像头——2026行业竞争格局、商业模式与核心痛点
大数据·人工智能·安全·计算机视觉·ai大模型
周杰偷奶茶1 小时前
【Java】数据类型与变量
java·开发语言
code斗1 小时前
Java数据结构:堆详解
java·开发语言·数据结构