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中。

相关推荐
雨中飘荡的记忆4 小时前
ElasticJob分布式调度从入门到实战
java·后端
冬奇Lab7 小时前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
cipher8 小时前
ERC-4626 通胀攻击:DeFi 金库的"捐款陷阱"
前端·后端·安全
城东米粉儿10 小时前
Android MediaPlayer 笔记
android
Jony_10 小时前
Android 启动优化方案
android
阿巴斯甜10 小时前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇10 小时前
AOSP15 Input专题InputReader源码分析
android
考虑考虑13 小时前
JDK25模块导入声明
java·后端·java ee
_小马快跑_14 小时前
Java 的 8 大基本数据类型:为何是不可或缺的设计?
java
_小马快跑_14 小时前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android