透過 Servlet Filter 攔截請求,驗證 Referer 標頭是否為本站域名,阻擋跨站請求偽造(CSRF)與惡意跨域提交。
public class ArgsIsValidFilter implements Filter {
private static Log log = LogFactory.getLog(ArgsIsValidFilter.class);
private static final String[] IGNORE_URIS = {"/back/", "/Info.jsp", "/pzxx.jsp"};
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String serverName = request.getServerName().toLowerCase();
String currentURI = request.getRequestURI();
Enumeration refs = request.getHeaders("Referer");
String referer = "";
while (refs.hasMoreElements()) referer = (String) refs.nextElement();
boolean valid = true;
if (referer.isEmpty()) {
valid = false;
log.info("Referer 為空,疑似跨域請求");
} else {
referer = referer.toLowerCase();
int prefixLen = referer.startsWith("https://") ? 8 : 7; // 去除 http(s)://
String host = referer.substring(prefixLen, prefixLen + serverName.length());
if (!host.equals(serverName)) {
valid = false;
log.info("域名不符,跨域請求: " + referer);
}
}
// 白名單跳過檢查
for (String ignore : IGNORE_URIS) {
if (currentURI.contains(ignore)) { valid = true; break; }
}
if (!valid) {
response.sendRedirect("/index.html"); // 導向首頁或錯誤頁
} else {
chain.doFilter(req, res);
}
}
public void init(FilterConfig cfg) {}
public void destroy() {}
}
<filter>
<filter-name>ArgsIsValidFilter</filter-name>
<filter-class>com.hety.uitl.ArgsIsValidFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ArgsIsValidFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Referer 域名與 ServerName,不符即攔截。Referer 可被偽造、某些隱私模式/防火牆會移除,無法 100% 防禦。SameSite Cookie、CORS 標頭等多層防禦。