AppScan安全扫描:加密会话(SSL)Cookie中缺少Secure、会话 cookie 中缺少 HttpOnly 属性

1、创建拦截器,对请求进行拦截处理Cookie问题

因为涉及到登录,因此需要添加登录URL白单信息:xml配置cookieHttpOnlyNoUrl或修改bdUris对应的默认值

因为图片、css样式、js无需做cookie处理,因此需添加后缀白单信息:xml配置noSuffixs或修改suffixList对应的默认值

package cn.com.zwjp.framework.filter;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.com.zwjp.framework.filter.util.CookieUtil;

/**
 * 1、AppScan 加密会话(SSL)Cookie中缺少Secure
 * 2、会话 cookie 中缺少 HttpOnly 属性
 * @author 爱兰河少
 * @data 2019年1月29日
 * cn.com.zwjp.framework.filter.CookieFilter
 */
public class CookieFilter extends HttpServlet implements Filter {

	private static final long serialVersionUID = 831349987977760012L;

	private static final Logger log = LoggerFactory.getLogger(CookieFilter.class);
	
	//不拦截的
	private List bdUris = new ArrayList(){{
		add("/framework/ums/login.jsp");
		add("/dologin.do");
	}};
	
	//不拦截的
	private List suffixList = new ArrayList(){{
		/*add("jpg");
		add("png");
		add("gif");
		add("js");
		add("css");*/
	}};

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		if (request instanceof HttpServletRequest) {
			HttpServletRequest httpRequest = (HttpServletRequest) request;
			HttpServletResponse httpResponse = (HttpServletResponse) response;
			
			//验证请求uri、请求后缀白单
			if (!CookieUtil.validataUri(httpRequest, bdUris) && !CookieUtil.validataSuffix(httpRequest, suffixList)) {
				HttpSession session = httpRequest.getSession();
				//JSESSIONID参数设置
				if (session != null) {
					CookieUtil.setCookie(httpResponse, "JSESSIONID", session.getId(), httpRequest.getContextPath(), -1, true, true, true);
				}else{//当sessionId为空时通过uuid设置JSESSIONIDId
					CookieUtil.setCookie(httpResponse, "JSESSIONID", CookieUtil.generateUUID(), httpRequest.getContextPath(), -1, true, true, true);
				}
			}
		}
		chain.doFilter(request, response);
	}

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		//url白单
		String _cookieHttpOnlyNoUrl=filterConfig.getInitParameter("cookieHttpOnlyNoUrl");
		if (StringUtils.isNotBlank(_cookieHttpOnlyNoUrl)) {
			bdUris = Arrays.asList(_cookieHttpOnlyNoUrl.trim().split(","));
		}
		//文件类型白单
		String _noSuffixs=filterConfig.getInitParameter("noSuffixs");
		if (StringUtils.isNotBlank(_noSuffixs)) {
			suffixList = Arrays.asList(_noSuffixs.trim().split(","));
		}
	}

	@Override
	public void destroy() {
	}
}

2、创建Cookie工具类

因为低版本的Cookie未对Secure参数进行封装,因此需手工对该参数进行封装处理

通过login.https参数配置是否为https请求,若是则对cookie封装Secure信息

package cn.com.zwjp.framework.filter.util;

import java.util.List;
import java.util.UUID;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;

import cn.com.zwjp.framework.util.Configuration;

/**
 * Cookie 
 * @author 爱兰河少
 * @data 2018年6月25日
 * cn.com.zwjp.framework.filter.util.CookieUtil
 */
public class CookieUtil {
	/*
	String name    :该Cookie的名称。Cookie一旦创建,名称便不可更改
	Object value   :该Cookie的值。如果值为Unicode字符,需要为字符编码。如果值为二进制数据,则需要使用BASE64编码
	int maxAge     :该Cookie失效的时间,单位秒。如果为正数,则该Cookie在maxAge秒之后失效。如果为负数,该Cookie为临时Cookie,关闭浏览器即失效,浏览器也不会以任何形式保存该Cookie。如果为0,表示删除该Cookie。默认为–1
	boolean secure :该Cookie是否仅被使用安全协议传输。安全协议。安全协议有HTTPS,SSL等,在网络上传输数据之前先将数据加密。默认为false
	String path    :该Cookie的使用路径。如果设置为“/sessionWeb/”,则只有contextPath为“/sessionWeb”的程序可以访问该Cookie。如果设置为“/”,则本域名下contextPath都可以访问该Cookie。注意最后一个字符必须为“/”
	String domain  :可以访问该Cookie的域名。如果设置为“.google.com”,则所有以“google.com”结尾的域名都可以访问该Cookie。注意第一个字符必须为“.”
	String comment :该Cookie的用处说明。浏览器显示Cookie信息的时候显示该说明
	int version    :该Cookie使用的版本号。0表示遵循Netscape的Cookie规范,1表示遵循W3C的RFC 2109规范
	boolean HttpOnly :通过js脚本将无法读取或修改cookie信息
	
	Cookie的有效期
			Cookie的maxAge决定着Cookie的有效期,单位为秒(Second)。Cookie中通过getMaxAge()方法与setMaxAge(int maxAge)方法来读写maxAge属性。
     	如果maxAge属性为正数,则表示该Cookie会在maxAge秒之后自动失效。浏览器会将maxAge为正数的Cookie持久化,即写到对应的Cookie文件中。无论客户关闭了浏览器还是电脑,只要还在maxAge秒之前,登录网站时该Cookie仍然有效。
		下面代码中的Cookie信息将永远有效:
		Cookie cookie = new Cookie("username","helloweenvsfei");   // 新建Cookie
		cookie.setMaxAge(Integer.MAX_VALUE);           // 设置生命周期为MAX_VALUE
		response.addCookie(cookie);                    // 输出到客户端
	
			如果maxAge为负数,则表示该Cookie仅在本浏览器窗口以及本窗口打开的子窗口内有效,关闭窗口后该Cookie即失效。maxAge为负数的Cookie,为临时性Cookie,不会被持久化,不会被写到Cookie文件中。Cookie信息保存在浏览器内存中,因此关闭浏览器该Cookie就消失了。Cookie默认的maxAge值为–1。
		如果maxAge为0,则表示删除该Cookie。Cookie机制没有提供删除Cookie的方法,因此通过设置该Cookie即时失效实现删除Cookie的效果。失效的Cookie会被浏览器从Cookie文件或者内存中删除,
		例如:
		Cookie cookie = new Cookie("username","helloweenvsfei");   // 新建Cookie
		cookie.setMaxAge(0);                          // 设置生命周期为0,不能为负数
		response.addCookie(cookie);                    // 必须执行这一句
	*/
	public static Cookie getCookie(HttpServletRequest httpRequest, String cookieName) {
		if (StringUtils.isNotBlank(cookieName)) {
			Cookie[] cookies = httpRequest.getCookies();
			if (cookies != null && cookies.length > 0) {
				for (Cookie cookie : cookies) {
					if (cookieName.toLowerCase().equals(cookie.getName().toLowerCase())) {
						return cookie;
					}
				}
			}
		}
		return null;
	}

	public static String getCookieValue(HttpServletRequest httpRequest, String cookieName) {
		Cookie cookie = getCookie(httpRequest, cookieName);
		if (cookie != null) {
			return cookie.getValue();
		}
		return null;
	}

	/**
	 * 
	 * @title
	 * @date 2019年1月11日
	 * @author 爱兰河少
	 * @param response 响应请求
	 * @param name Cookie名称
	 * @param value Cookie值
	 * @param path path信息
	 * @param maxAge Cookie有效时长
	 * @param secure secure参数,https请求时开启
	 * @param httpOnly Cookie信息设置为httpOnly
	 * @param isAddCookie Cookie以Add方式还是set方式添加
	 */
	public static void setCookie(final HttpServletResponse response, final String name, final String value,
			final String path, final int maxAge, final boolean secure, final boolean httpOnly,
			final boolean isAddCookie) {
		setCookie(response, name, value, path, maxAge, secure, null, null, httpOnly, isAddCookie);
	}

	/**
	 * 
	 * @title
	 * @date 2019年1月11日
	 * @author 爱兰河少
	 * @param response 响应请求
	 * @param name Cookie名称
	 * @param value Cookie值
	 * @param path path信息
	 * @param maxAge Cookie有效时长
	 * @param secure secure参数,https情书时开启
	 * @param comment
	 * @param domain
	 * @param httpOnly Cookie信息设置为httpOnly
	 * @param isAddCookie Cookie以Add方式还是set方式添加
	 */
	public static void setCookie(final HttpServletResponse response, final String name, final String value,
			final String path, final int maxAge, final boolean secure, final String comment, final String domain,
			final boolean httpOnly, final boolean isAddCookie) {
		String cookieName = StringUtils.isBlank(name) ? "none" : name;
		String cookieVal = StringUtils.isBlank(value) ? "cookieVal" : value;
		final Cookie cookie = new Cookie(cookieName, cookieVal);
		cookie.setPath(path);
		cookie.setComment(comment);
		cookie.setDomain(StringUtils.isBlank(domain) ? "" : domain);
		cookie.setMaxAge(maxAge);
		cookie.setSecure(secure);
		// cookie.setVersion(version);

		// 设置cookie
		setCookie(cookie, response, httpOnly, isAddCookie);
	}

	/**
	 * 调整Set-Cookie设置
	 * 
	 * @title
	 * @date 2018年6月25日
	 * @author 爱兰河少
	 * @param cookie
	 * @param response
	 */
	public static void setCookie(final Cookie cookie, final HttpServletResponse response, final boolean httpOnly,
			final boolean isAddCookie) {
		/*
		 * response.addCookie(cookie);
		 */
		// 改造
		StringBuilder sb = new StringBuilder(200);
		boolean addName = false;
		if (!"none".equals(cookie.getName())) {
			addName = true;
			String cookieVal = StringUtils.isBlank(cookie.getValue()) ? "" : cookie.getValue();
			sb.append(cookie.getName()).append("=").append(cookieVal);
		}
		if (addName) {
			sb.append(addName ? "; " : "");
		}
		if (cookie.getPath() != null && !"".equals(cookie.getPath())) {
			sb.append("Path=").append(cookie.getPath());
		} else {
			sb.append("Path=/");
		}
		if (cookie.getDomain() != null && !"".equals(cookie.getDomain())) {
			sb.append("; Domain=").append(cookie.getDomain());
		}
		if (cookie.getMaxAge() > -1) {
			if (cookie.getMaxAge() > 0) {
				sb.append("; Max-Age=").append(cookie.getMaxAge());
				// Calendar cal = Calendar.getInstance(Locale.US);
				// cal.add(Calendar.SECOND, cookie.getMaxAge());
				// DateFormat df = new SimpleDateFormat("EEE, d-MMM-yyyy
				// HH:mm:ss
				// z", Locale.US);
				// df.setTimeZone(TimeZone.getTimeZone("GMT"));
				// String expires = df.format(cal.getTime());
				// if (cookie.getMaxAge() <= 0) {
				// expires = "Thu, 01-Jan-1970 00:00:10 GMT";
				// }
				// sb.append("; Expires=").append(expires);
			} else if (cookie.getMaxAge() == 0) {
				sb.append("; Max-Age=").append(cookie.getMaxAge());
			}
		}
		if (httpOnly) {
			sb.append("; HttpOnly");
		}
		if (cookie.getSecure() && isHttps()) {
			sb.append("; Secure");
		}
		if (isAddCookie) {
			response.addHeader("Set-Cookie", sb.toString());
		} else {
			response.setHeader("Set-Cookie", sb.toString());
		}
	}
	/**
	 * 是否开启https请求
	 * @title
	 * @date 2018年9月3日
	 * @author 爱兰河少
	 * @return
	 */
	public static boolean isHttps(){
		Configuration configuration = Configuration.getInstance();
		String isHttpsScheme = configuration.getValue("login.https");
		if ("true".equals(isHttpsScheme)) {
			return true;
		}else{
			return false;
		}
	}
	
	public static String generateUUID(){
		String uuid = UUID.randomUUID().toString(); 
		return uuid.replaceAll("-", ""); 
	}
	
	/**
	 * 获取请求后缀
	 * @title
	 * @date 2019年1月30日
	 * @author 爱兰河少
	 * @param request
	 * @return
	 */
	public static String getUrlSuffix(HttpServletRequest request){
		String postUrl = request.getRequestURI();// 返回值类似:/index.asp
		String serverName = request.getContextPath();
		postUrl = postUrl.replaceFirst(serverName, "");
		return getSuffix(postUrl);
	}
	/**
	 * 获取请求URI
	 * @title
	 * @date 2019年1月30日
	 * @author 爱兰河少
	 * @param request
	 * @return
	 */
	public static String getUri(HttpServletRequest request){
		String postUrl = request.getRequestURI();// 返回值类似:/index.asp
		String serverName = request.getContextPath();
		postUrl = postUrl.replaceFirst(serverName, "");
		int index = postUrl.indexOf(";");
		if (index >= 0) {
			postUrl=postUrl.substring(0,index);
		}
		index = postUrl.indexOf("?");
		if (index >= 0) {
			postUrl=postUrl.substring(0,index);
		}
		return postUrl;
	}
	/**
	 * 获取文件后缀
	 * @title
	 * @date 2019年1月30日
	 * @author 爱兰河少
	 * @param source
	 * @return
	 */
	public static String getSuffix(String source){
		String reSuffix=null;
		int index = source.indexOf(";");
		if (index >= 0) {
			source=source.substring(0,index);
		}
		index = source.indexOf("?");
		if (index >= 0) {
			source=source.substring(0,index);
		}
		int lastIndex = source.lastIndexOf(".");
		if (lastIndex > 0) {
			reSuffix = source.substring(lastIndex + 1).toLowerCase();
		}
		return reSuffix;
	}
	
	/**
	 * 验证URL后缀是否为白单
	 * @title
	 * @date 2019年1月30日
	 * @author 爱兰河少
	 * @param request
	 * @param suffixList
	 * @return
	 */
	public static boolean validataSuffix(HttpServletRequest request,List suffixList){
		String suffix=getUrlSuffix(request);
		if (StringUtils.isNotBlank(suffix)) {
			if (suffixList.contains(suffix)) {
				return true;
			}
		}
		return false;
	}
	/**
	 * 验证URI是否为白单
	 * @title
	 * @date 2019年1月30日
	 * @author 爱兰河少
	 * @param request
	 * @param uriList
	 * @return
	 */
	public static boolean validataUri(HttpServletRequest request,List uriList){
		String uri=getUri(request);
		if (StringUtils.isNotBlank(uri)) {
			if (uriList.contains(uri)) {
				return true;
			}
		}
		return false;
	}
}

三、web.xml配置


	
        CookieFilter
        cn.com.zwjp.framework.filter.CookieFilter
    
    
        CookieFilter
        /*
        REQUEST
    

 

你可能感兴趣的:(AppScan安全扫描,安全扫描,AppScan,Secure,Cookie,HttpOnly)