概述
功能介绍
DefaultHttpFirewall
是Spring Security Web
提供的一个HTTP
防火墙(对应概念模型接口HttpFirewall
)实现。该实现是所谓的缺省实现,但实际上Spring Security Web
缺省使用的并不是DefaultHttpFirewall
,而是严格模式的StrictHttpFirewall
。其原因主要是StrictHttpFirewall
对安全限制更严格,但是开发人员也可以设置Spring Security Web
使用DefaultHttpFirewall
。
DefaultHttpFirewall
所应用的安全规则比较少,主要有:
-
如果请求
URL
不是标准化(normalize
)的URL
则该请求会被拒绝,以避免安全限制被绕过。- 该规则不能被禁用。
- 仅仅检查
servletPath
和pathInfo
部分,不检查contextPath
。
这里标准化的
URL
必须符合以下条件 :
指定路径中,必须不能包含以下字符串序列之一 :
["//","./","/…/","/."] -
如果请求
URL
(URL
编码后)包含了斜杠(%2f
或者%2F
)则该请求会被拒绝。通过开关函数
setAllowUrlEncodedSlash(boolean)
可以设置是否关闭该规则。缺省使用该规则。
如果请求违反了以上安全规则中的任何一条,DefaultHttpFirewall
会通过抛出异常RequestRejectedException
拒绝该请求。
继承关系
使用介绍
缺省情况下DefaultHttpFirewall
并没有被Spring Security Web
使用。如果想使用DefaultHttpFirewall
,可以调用FilterChainProxy#setFirewall
。
源代码
源代码版本 : Spring Security Web 5.1.4.RELEASE
package org.springframework.security.web.firewall;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class DefaultHttpFirewall implements HttpFirewall {
private boolean allowUrlEncodedSlash;
@Override
public FirewalledRequest getFirewalledRequest(HttpServletRequest request) throws RequestRejectedException {
FirewalledRequest fwr = new RequestWrapper(request);
if (!isNormalized(fwr.getServletPath()) || !isNormalized(fwr.getPathInfo())) {
throw new RequestRejectedException("Un-normalized paths are not supported: " + fwr.getServletPath()
+ (fwr.getPathInfo() != null ? fwr.getPathInfo() : ""));
}
String requestURI = fwr.getRequestURI();
if (containsInvalidUrlEncodedSlash(requestURI)) {
throw new RequestRejectedException("The requestURI cannot contain encoded slash. Got " + requestURI);
}
return fwr;
}
@Override
public HttpServletResponse getFirewalledResponse(HttpServletResponse response) {
return new FirewalledResponse(response);
}
public void setAllowUrlEncodedSlash(boolean allowUrlEncodedSlash) {
this.allowUrlEncodedSlash = allowUrlEncodedSlash;
}
private boolean containsInvalidUrlEncodedSlash(String uri) {
if (this.allowUrlEncodedSlash || uri == null) {
return false;
}
if (uri.contains("%2f") || uri.contains("%2F")) {
return true;
}
return false;
}
private boolean isNormalized(String path) {
if (path == null) {
return true;
}
for (int j = path.length(); j > 0;) {
int i = path.lastIndexOf('/', j - 1);
int gap = j - i;
if (gap == 2 && path.charAt(i + 1) == '.') {
// ".", "/./" or "/."
return false;
} else if (gap == 3 && path.charAt(i + 1) == '.' && path.charAt(i + 2) == '.') {
return false;
}
j = i;
}
return true;
}
}