我正在使用tomcat 8.52修复CSRF问题。在那里面 在使用org.apache.catalina.filters.CsrfPreventionFilter。
如何使用带有正则表达式模式匹配的entryPoints参数。
如何避免在登录页面中检查CSRF。
我的登录页面加载了20个js,40个imags,23个CSS。我该如何在入口点参数中提及?
我的web.xml:
<filter>
<filter-name>CsrfFilter</filter-name>
<filter-class>org.apache.catalina.filters.CsrfPreventionFilter</filter-class>
<init-param>
<param-name>denyStatus</param-name>
<param-value>404</param-value>
</init-param>
<init-param>
<param-name>entryPoints</param-name>
<param-value>/mUser/login,/js/encrypt.js,/js/json-min.js,/m User/homepage,/dispatch/sendtemplate</param-value>
</init-param>
当我尝试登录自己的页面时,我看到只有crypto.js,json-min.js仅加载的其他人显示404错误。 登录该页面时还会获得404页面。
答案 0 :(得分:1)
我这样定义自己的CsrfPreventionFilter类,并将我的JS和CSS和img放在名为“ static”的文件夹中
package filters.myCatalina;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.Serializable;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
public class MyCsrfPreventionFilter extends MyCsrfPreventionFilterBase {
private Logger logger = Logger.getLogger(getClass().getName());
private final Set<String> entryPoints = new HashSet<>();
private int nonceCacheSize = 5;
public void setEntryPoints(String entryPoints) {
String values[] = entryPoints.split(",");
for (String value : values) {
this.entryPoints.add(value.trim());
}
}
public void setNonceCacheSize(int nonceCacheSize) {
this.nonceCacheSize = nonceCacheSize;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
ServletResponse wResponse = null;
if (request instanceof HttpServletRequest &&
response instanceof HttpServletResponse) {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
boolean skipNonceCheck = false;
logger.info(getRequestedPath(req));
if ("/".equals(getRequestedPath(req)))
skipNonceCheck = true;
if ("/static/".equals(getRequestedPath(req).substring(0, 8)))
skipNonceCheck = true;
if (MyConstants.METHOD_GET.equals(req.getMethod())
&& entryPoints.contains(getRequestedPath(req))) {
skipNonceCheck = true;
}
HttpSession session = req.getSession(false);
@SuppressWarnings("unchecked")
LruCache<String> nonceCache = (session == null) ? null
: (LruCache<String>) session.getAttribute(
MyConstants.CSRF_NONCE_SESSION_ATTR_NAME);
if (!skipNonceCheck) {
String previousNonce =
req.getParameter(MyConstants.CSRF_NONCE_REQUEST_PARAM);
if (nonceCache == null || previousNonce == null ||
!nonceCache.contains(previousNonce)) {
res.sendError(getDenyStatus());
return;
}
}
if (nonceCache == null) {
nonceCache = new LruCache<>(nonceCacheSize);
if (session == null) {
session = req.getSession(true);
}
session.setAttribute(
MyConstants.CSRF_NONCE_SESSION_ATTR_NAME, nonceCache);
}
String newNonce = generateNonce();
nonceCache.add(newNonce);
wResponse = new CsrfResponseWrapper(res, newNonce);
} else {
wResponse = response;
}
chain.doFilter(request, wResponse);
}
protected static class CsrfResponseWrapper
extends HttpServletResponseWrapper {
private final String nonce;
public CsrfResponseWrapper(HttpServletResponse response, String nonce) {
super(response);
this.nonce = nonce;
}
@Override
@Deprecated
public String encodeRedirectUrl(String url) {
return encodeRedirectURL(url);
}
@Override
public String encodeRedirectURL(String url) {
return addNonce(super.encodeRedirectURL(url));
}
@Override
@Deprecated
public String encodeUrl(String url) {
return encodeURL(url);
}
@Override
public String encodeURL(String url) {
return addNonce(super.encodeURL(url));
}
/*
* Return the specified URL with the nonce added to the query string.
*/
private String addNonce(String url) {
if (url == null) {
return nonce;
}
String path = url;
String query = "";
String anchor = "";
int pound = path.indexOf('#');
if (pound >= 0) {
anchor = path.substring(pound);
path = path.substring(0, pound);
}
int question = path.indexOf('?');
if (question >= 0) {
query = path.substring(question);
path = path.substring(0, question);
}
StringBuilder sb = new StringBuilder(path);
if (query.length() > 0) {
sb.append(query);
sb.append('&');
} else {
sb.append('?');
}
sb.append(MyConstants.CSRF_NONCE_REQUEST_PARAM);
sb.append('=');
sb.append(nonce);
sb.append(anchor);
return sb.toString();
}
}
protected static class LruCache<T> implements Serializable {
private static final long serialVersionUID = 1L;
// Although the internal implementation uses a Map, this cache
// implementation is only concerned with the keys.
private final Map<T, T> cache;
public LruCache(final int cacheSize) {
cache = new LinkedHashMap<T, T>() {
private static final long serialVersionUID = 1L;
@Override
protected boolean removeEldestEntry(Map.Entry<T, T> eldest) {
if (size() > cacheSize) {
return true;
}
return false;
}
};
}
public void add(T key) {
synchronized (cache) {
cache.put(key, null);
}
}
public boolean contains(T key) {
synchronized (cache) {
return cache.containsKey(key);
}
}
}
}
我的web.xml配置
<filter>
<filter-name>CSRF</filter-name>
<filter-class>filters.myCatalina.MyCsrfPreventionFilter</filter-class>
<init-param>
<param-name>entryPoints</param-name>
<param-value>/index.jsp,/,index.jsp</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CSRF</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
和在jsp entryPoint中
<INPUT type="hidden" name="CSRF_NONCE" value="<%=response.encodeUrl(null)%>">
这只是一个示例,但是可以工作,如果您使用的是tomcat-catalina依赖性,则应在org.apache.catalina.filters.Constants类中使用“ org.apache.catalina.filters.CSRF_NONCE”,而不是“ CSRF_NONCE”