【Java编码准则】の #02不要在客户端存储未加密的敏感信息

     当构建CS模式的应用程序时,在客户端侧存储敏感信息(例如用户私要信息)可能导致非授权的信息泄漏。

     对于Web应用程序来说,最常见的泄漏问题是在客户端使用cookies存放服务器端获取的敏感信息。Cookies是由web服务器创建的,它具有一个指定的有效时间,保存在客户端。当客户端连接上服务器端时,客户端使用cookies中存储的信息向服务器端进行认证,通过后服务器端返回敏感信息。

     在XSS攻击下,Cookies不能保证敏感信息的安全。无论是通过XSS攻击,还是直接对客户端的攻击,攻击者一旦获取到Cookies,他就可以使用这个Cookies从服务器端获取敏感信息。上面的风险存在时间窗,当Cookies存活超过指定的时间后(例如15分钟),服务器端会使会话无效,这时风险就不存在了。

     Cookies是一个短的字符串,如果它包含了敏感的信息,那么这段信息必须进行加密,敏感信息包括用户名,密码,信用卡号码,社会安全码,以及其他任何个人标识信息。关于管理密码的更多细节,参见“#13使用散列函数来存储密码”。关于如何保证内存中敏感信息安全的更多细节,参见“#01限制内存中敏感数据的生命周期”。


[不符合安全要求的代码示例]

     下面的代码中,login servlet将用户名和密码存储在Cookies中,用于后续请求中标识用户。

	protected void doPost(HttpServletRequest request, HttpServletResponse response) {
		
		// validate input (omitted)
		
		String username = request.getParameter("username");
		char[] password = request.getParameter("password").toCharArray();
		boolean rememberMe = Boolean.valueOf(request.getParameter("rememberme"));
		
		LoginService loginService = new LoginServiceImpl();
		if (rememberMe) {
			if (request.getCookies()[0] != null &&
					request.getCookies()[0].getValue() != null) {
				String[] value = request.getCookies()[0].getValue().split(";");
				
				if (!loginService.isUserValid(value[0], value[1].toCharArray())) {
					// set error and return
				} else {
					// forward to welcome page
				}
			} else {
				boolean validated = loginService.isUserValid(username, password);
				if (validated) {
					Cookie loginCookie = new Cookie("rememberme", username + ";" + new String(password));
					response.addCookie(loginCookie);
					
					// forword to welcome page
				} else {
					// set error and return
				}
			}
		} else {
			// no remember-me functionality selected
			// process with regular authentication;
			// if it fails set error and return
		}
		Array.fill(password, ' ');
	}

     上面代码中实现“记住我”功能的方法不安全的,因为当攻击者可以访问客户端电脑时,他可以直接获取这些敏感信息。上面代码同时违背了“#13使用散列函数来存储密码”。


[符合安全要求的解决方案-会话]

     下面代码以一种安全的方式实现“记住我”功能,它将用户名和一个安全的随机字符串存储在Cookie中,同时使用HttpSession来保存会话状态。

	protected void doPost(HttpServletRequest request, HttpServletResponse response) {
		
		// validate input (omitted)
		
		String username = request.getParameter("username");
		char[] password = request.getParameter("password").toCharArray();
		boolean rememberMe = Boolean.valueOf(request.getParameter("rememberme"));
		
		LoginService loginService = new LoginServiceImpl();
		boolean validated = false;
		if (rememberMe) {
			if (request.getCookies()[0] != null &&
					request.getCookies()[0].getValue() != null) {
				String[] value = request.getCookies()[0].getValue().split(";");
				
				if (value.length != 2) {
					// set error and return
				}
				
				if (!loginService.mappingExists(value[0], value[1])) {
					// (username random) pair is checked
					// set error and return
				} else {
					validated = loginService.isUserValid(username, password);
					if (!validated) {
						// set error and return
					}
				}
				
				String newRandom = loginService.getRandomString();
				// reset the random every time
				loginService.mapUserForRememberMe(username, newRandom);
				HttpSession session = reuqest.getSession();
				session.invalidate();
				session = request.getSession(true);
				
				// set session timeout to 15 minutes
				session.setMaxInactiveInterval(60*15);
				
				// store user attribute and a random attribute in session scope
				session.setAttribute("uset", loginService.getUsername());
				Cookie loginCookie = new Cookie("rememberme", username + ";" + newRandom);
				response.addCookie(loginCookie);
				
				// forword to welcome page
			}
		} else {
			// no remember-me functionality selected
			// process with regular authentication;
			// if it fails set error and return
		}
		Array.fill(password, ' ');
	}

     服务器端保存用户名和安全随机字符串的映射关系,当用户选择“记住我”时,doPost()函数检查客户端提供的Cookies中是否包含有效的用户名和随机字符串映射对。如果映射对是正确的,服务器端通过该用户的认证,并使用户跳转到欢迎页。如果认证没有通过,服务器端返回错误给客户端。如果用户选择“记住我”,但客户度没有有效的Cookie导致认证失败,那么服务器端会要求用户使用认证信息重新进行认证。如果认证成功,服务器端会提供一个包含新的“记住我”特性的Cookie给客户端。

     这个解决方案通过使当前会话无效并创建新的会话,可以避免固定会话攻击。同时通过将会话访问有效时间设置为15分钟来将减少攻击者实施会话劫持攻击的时间窗长度。


——欢迎转载,请注明出处 http://blog.csdn.net/asce1885 ,未经本人同意请勿用于商业用途,谢谢——

【Java编码准则】の #02不要在客户端存储未加密的敏感信息,布布扣,bubuko.com

【Java编码准则】の #02不要在客户端存储未加密的敏感信息

上一篇:【javaScript基础】异常处理


下一篇:ios系统 竖屏拍照 canvas处理后 图片旋转(利用exif.js解决ios手机上传竖拍照片旋转90度问题)