FirewalledResponse是Spring Security Web提供的一个HttpServletResponse实现,是一个带有防火墙增强安全能力的HttpServletResponse实现,被HttpFirewall对象用于对一个HttpServletResponse进行安全增强的包装器。
通过FirewalledResponse的包装,它对HttpServletResponse做了如下安全增强:
设置或者添加响应头部时,确保写入的头部值不包含\r或者\n;有关方法 : #setHeader,#addHeader
添加cookie时,确保写入的值不包含\r或者\n;有关方法 : #addCookie
重定向时,确保重定向location中不包含\r或者\n;有关方法 : #sendRedirect
FirewalledResponse对写入响应的值所做的增强逻辑中,如果所写入的值违反了规则,则会抛出异常IllegalArgumentException。
HttpFirewall的两个实现类StrictHttpFirewall,DefaultHttpFirewall都用到了FirewalledResponse,具体用法如下 :
@Override public HttpServletResponse getFirewalledResponse(HttpServletResponse response) { return new FirewalledResponse(response); }源代码版本 : Spring Security Web 5.1.4.RELEASE
package org.springframework.security.web.firewall; import java.io.IOException; import java.util.regex.Pattern; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; class FirewalledResponse extends HttpServletResponseWrapper { private static final Pattern CR_OR_LF = Pattern.compile("\\r|\\n"); private static final String LOCATION_HEADER = "Location"; private static final String SET_COOKIE_HEADER = "Set-Cookie"; public FirewalledResponse(HttpServletResponse response) { super(response); } @Override public void sendRedirect(String location) throws IOException { // TODO: implement pluggable validation, instead of simple blacklisting. // SEC-1790. Prevent redirects containing CRLF validateCrlf(LOCATION_HEADER, location); super.sendRedirect(location); } @Override public void setHeader(String name, String value) { validateCrlf(name, value); super.setHeader(name, value); } @Override public void addHeader(String name, String value) { validateCrlf(name, value); super.addHeader(name, value); } @Override public void addCookie(Cookie cookie) { if (cookie != null) { validateCrlf(SET_COOKIE_HEADER, cookie.getName()); validateCrlf(SET_COOKIE_HEADER, cookie.getValue()); validateCrlf(SET_COOKIE_HEADER, cookie.getPath()); validateCrlf(SET_COOKIE_HEADER, cookie.getDomain()); validateCrlf(SET_COOKIE_HEADER, cookie.getComment()); } super.addCookie(cookie); } void validateCrlf(String name, String value) { if (hasCrlf(name) || hasCrlf(value)) { throw new IllegalArgumentException( "Invalid characters (CR/LF) in header " + name); } } private boolean hasCrlf(String value) { return value != null && CR_OR_LF.matcher(value).find(); } }