Reputation: 721
I need to add a check to see if the domain matches the referrer and completely new to csrf concepts and servlets. I would like to know if there is a way for me to validate if the referrer exists
If the referrer header is not https://[samedomain]/abc/sso?module=console, then fail. Note that the check should be very strict here. Cannot just compare using endswith “/abc/sso?module=console” since it could be bypass with https://attacker.com/abc/sso?module=console or https://[samedomain].attacker.com/abc/sso?module=console If not fail, proceed
I am looking for the right validation with regards to code like may be need to compare the port and the server name too. I am not looking for something overly complicated i have come this far ,
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
}
Any help would be appreciated
Upvotes: 0
Views: 2728
Reputation: 17455
This was actually a bit harder than I thought so I thought I'd share what I came up with. The code could be optimized - there are too many if
statements but it looks like you are coming from a different language so I tried to make it fairly straight forward. Additionally, there are probably some error conditions I missed but it should be close.
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
}
}
Upvotes: 3