概述
功能介绍
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();
}
}