Servlets HttpServletRequest,用于Referer标头的csrf检查

Servlets HttpServletRequest,用于Referer标头的csrf检查,servlets,httprequest,csrf,Servlets,Httprequest,Csrf,我需要添加一个检查,看看该域是否与推荐者匹配,以及是否完全不熟悉csrf概念和servlet。我想知道是否有一种方法可以让我验证推荐人是否存在 如果referer头不是,则失败。注意,这里的检查应该非常严格。无法仅使用endswith“/abc/sso?module=console”进行比较,因为它可能会被或绕过 如果没有失败,请继续 我正在寻找关于代码的正确验证,比如可能需要比较端口和服务器名称。我不是在寻找过于复杂的东西 我已经走了这么远 String refererHeader =

我需要添加一个检查,看看该域是否与推荐者匹配,以及是否完全不熟悉csrf概念和servlet。我想知道是否有一种方法可以让我验证推荐人是否存在

如果referer头不是,则失败。注意,这里的检查应该非常严格。无法仅使用endswith“/abc/sso?module=console”进行比较,因为它可能会被或绕过 如果没有失败,请继续

我正在寻找关于代码的正确验证,比如可能需要比较端口和服务器名称。我不是在寻找过于复杂的东西 我已经走了这么远

    String refererHeader = request.getHeader("referer");
    final String PATH = '/abc/sso?module=console',
    String host = request.getServerName();
    int port = request.getServerPort();

    String portstr="";
    if(port!=80 || port!= 443){
      portstr=":"+port;
    }

    if (refererHeader == null) {
        response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
        return;
    }

    if (refererHeader != null &&  host!== null) {
     //check if port is not the default ports, in that case construct the url 

     //append with PATH and compare if the referrer header and this matches 

    }

任何帮助都将不胜感激

这实际上比我想象的要困难一些,所以我想我会分享我的想法。代码可以优化-有太多的
if
语句,但看起来您来自不同的语言,所以我尝试将其简单化。此外,可能有一些错误条件我错过了,但它应该是接近

import java.io.IOException;
import java.net.URL;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebFilter
public class RefererFilter implements Filter {
    private static final String PATH = "/abc/sso?module=console";
    // the domains that you will accept a referrer from
    private static final List<String> acceptableDomains = Arrays.asList("google.com", "mydomain.com");

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // unused in this application
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        String refererHeader = request.getHeader("referer");
        // no need to continue if the header is missing
        if (refererHeader == null) {
            response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
            return;
        }

        // parse the given referrer
        URL refererURL = new URL(refererHeader);
        // split the host name by the '.' character (but quote that as it is a regex special char)
        String[] hostParts = refererURL.getHost().split(Pattern.quote("."));

        if (hostParts.length == 1) { // then we have something like "localhost"
            if (!acceptableDomains.contains(hostParts[0])) {
                response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                return;
            }
        } else if (hostParts.length >= 2) { // handle domain.tld, www.domain.tld, and net1.net2.domain.tld
            if (!acceptableDomains.contains(hostParts[hostParts.length - 2] + "." + hostParts[hostParts.length - 1])) {
                response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                return;
            }
        }
        // if we've gotten this far then the domain is ok, how about the path and query?
        if( !(refererURL.getPath() + "?" + refererURL.getQuery()).equals(PATH) ) {
            response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
            return;
        }
        // all tests pass - continue filter chain
        filterChain.doFilter(request, response);
    }

    @Override
    public void destroy() {
        // unused in this implementation
    }
}
import java.io.IOException;
导入java.net.URL;
导入java.util.array;
导入java.util.List;
导入java.util.regex.Pattern;
导入javax.servlet.Filter;
导入javax.servlet.FilterChain;
导入javax.servlet.FilterConfig;
导入javax.servlet.ServletException;
导入javax.servlet.ServletRequest;
导入javax.servlet.ServletResponse;
导入javax.servlet.annotation.WebFilter;
导入javax.servlet.http.HttpServletRequest;
导入javax.servlet.http.HttpServletResponse;
@网络过滤器
公共类RefererFilter实现过滤器{
私有静态最终字符串路径=“/abc/sso?模块=控制台”;
//您将从中接受推荐人的域
私有静态最终列表acceptableDomains=Arrays.asList(“google.com”、“mydomain.com”);
@凌驾
public void init(FilterConfig FilterConfig)抛出ServletException{
//未在本应用程序中使用
}
@凌驾
public void doFilter(ServletRequest ServletRequest、ServletResponse ServletResponse、FilterChain FilterChain)抛出IOException、ServletException{
HttpServletRequest=(HttpServletRequest)servletRequest;
HttpServletResponse=(HttpServletResponse)servletResponse;
字符串refererHeader=request.getHeader(“referer”);
//如果缺少标头,则无需继续
if(refererHeader==null){
response.setStatus(HttpServletResponse.SC_BAD_请求);
返回;
}
//解析给定的引用者
URL refereUrl=新URL(refererHeader);
//按“.”字符分割主机名(但引用该字符,因为它是正则表达式特殊字符)
String[]hostParts=refererURL.getHost().split(Pattern.quote(“.”);
如果(hostParts.length==1){//那么我们有类似于“localhost”的东西
如果(!acceptableDomains.contains(主机部件[0])){
response.setStatus(HttpServletResponse.SC_BAD_请求);
返回;
}
}else如果(hostParts.length>=2){//handle domain.tld、www.domain.tld和net1.net2.domain.tld
if(!acceptableDomains.contains(hostParts[hostParts.length-2]+“+hostParts[hostParts.length-1])){
response.setStatus(HttpServletResponse.SC_BAD_请求);
返回;
}
}
//如果我们已经做到了这一步,那么域就可以了,那么路径和查询呢?
如果(!(refereUrl.getPath()+“?”+refereUrl.getQuery()).equals(路径)){
response.setStatus(HttpServletResponse.SC_BAD_请求);
返回;
}
//所有测试均通过-继续过滤链
filterChain.doFilter(请求、响应);
}
@凌驾
公共空间销毁(){
//此实现中未使用
}
}

这实际上比我想象的要难一些,所以我想我会分享我的想法。代码可以优化-有太多的
if
语句,但看起来您来自不同的语言,所以我尝试将其简单化。此外,可能有一些错误条件我错过了,但它应该是接近

import java.io.IOException;
import java.net.URL;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebFilter
public class RefererFilter implements Filter {
    private static final String PATH = "/abc/sso?module=console";
    // the domains that you will accept a referrer from
    private static final List<String> acceptableDomains = Arrays.asList("google.com", "mydomain.com");

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // unused in this application
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        String refererHeader = request.getHeader("referer");
        // no need to continue if the header is missing
        if (refererHeader == null) {
            response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
            return;
        }

        // parse the given referrer
        URL refererURL = new URL(refererHeader);
        // split the host name by the '.' character (but quote that as it is a regex special char)
        String[] hostParts = refererURL.getHost().split(Pattern.quote("."));

        if (hostParts.length == 1) { // then we have something like "localhost"
            if (!acceptableDomains.contains(hostParts[0])) {
                response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                return;
            }
        } else if (hostParts.length >= 2) { // handle domain.tld, www.domain.tld, and net1.net2.domain.tld
            if (!acceptableDomains.contains(hostParts[hostParts.length - 2] + "." + hostParts[hostParts.length - 1])) {
                response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                return;
            }
        }
        // if we've gotten this far then the domain is ok, how about the path and query?
        if( !(refererURL.getPath() + "?" + refererURL.getQuery()).equals(PATH) ) {
            response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
            return;
        }
        // all tests pass - continue filter chain
        filterChain.doFilter(request, response);
    }

    @Override
    public void destroy() {
        // unused in this implementation
    }
}
import java.io.IOException;
导入java.net.URL;
导入java.util.array;
导入java.util.List;
导入java.util.regex.Pattern;
导入javax.servlet.Filter;
导入javax.servlet.FilterChain;
导入javax.servlet.FilterConfig;
导入javax.servlet.ServletException;
导入javax.servlet.ServletRequest;
导入javax.servlet.ServletResponse;
导入javax.servlet.annotation.WebFilter;
导入javax.servlet.http.HttpServletRequest;
导入javax.servlet.http.HttpServletResponse;
@网络过滤器
公共类RefererFilter实现过滤器{
私有静态最终字符串路径=“/abc/sso?模块=控制台”;
//您将从中接受推荐人的域
私有静态最终列表acceptableDomains=Arrays.asList(“google.com”、“mydomain.com”);
@凌驾
public void init(FilterConfig FilterConfig)抛出ServletException{
//未在本应用程序中使用
}
@凌驾
public void doFilter(ServletRequest ServletRequest、ServletResponse ServletResponse、FilterChain FilterChain)抛出IOException、ServletException{
HttpServletRequest=(HttpServletRequest)servletRequest;
HttpServletResponse=(HttpServletResponse)servletResponse;
字符串refererHeader=request.getHeader(“referer”);
//如果缺少标头,则无需继续
if(refererHeader==null){
response.setStatus(HttpServletResponse.SC_BAD_请求);
返回;
}
//解析给定的引用者
URL refereUrl=新URL(refererHeader);
//按“.”字符分割主机名(但引用该字符,因为它是正则表达式特殊字符)
String[]hostParts=refererURL.getHost().split(Pattern.quote(“.”);
if(hostParts.length)==