HttpServletRequest, csrf check for referrer header - servlets

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

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
}
}

Related

What does the EndpointsServlet class do in Google's Endpoints?

First, I am a beginner in java servlets, maven projects and apis.
I am doing the following tutorial on getting started with google endpoints, which is a tutorial implementing the following maven project source code on github. On the web.xml, there is only one named Servlet, the EndpointsServlet like so:
<!-- wrap the backend with Endpoints Framework v2. -->
<servlet>
<servlet-name>EndpointsServlet</servlet-name>
<servlet-class>com.google.api.server.spi.EndpointsServlet</servlet-class>
<init-param>
<param-name>services</param-name>
<param-value>com.example.echo.Echo</param-value>
</init-param>
</servlet>
What I dont understand is why are there no other servlets on the project? There are only 3 java classes in the main directory and none of them are servlet files. I am assuming that this project is a sample api with server side logic (such as routing and responding to requests) like any other servlet project which means there should be more than this servlet.
The comment on the web.xml is an obvious clue as to what it does but I dont really know what wrapping the backend with endpoints framework means. Also, I actually got the EndpointsServlet.java file and it says the servlet is a "handler for proxy-less API serving. This servlet understands and replies in JSON-REST. Again, I dont really understand this comment nor what the servlet does even reading it. Servlet code below:
package com.google.api.server.spi;
import com.google.api.server.spi.SystemService.EndpointNode;
import com.google.api.server.spi.config.ApiConfigException;
import com.google.api.server.spi.config.model.ApiClassConfig.MethodConfigMap;
import com.google.api.server.spi.config.model.ApiConfig;
import com.google.api.server.spi.config.model.ApiMethodConfig;
import com.google.api.server.spi.dispatcher.PathDispatcher;
import com.google.api.server.spi.handlers.ApiProxyHandler;
import com.google.api.server.spi.handlers.CorsHandler;
import com.google.api.server.spi.handlers.EndpointsMethodHandler;
import com.google.api.server.spi.handlers.ExplorerHandler;
import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.util.Enumeration;
import java.util.List;
import java.util.Map.Entry;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* A handler for proxy-less API serving. This servlet understands and replies in JSON-REST.
*/
public class EndpointsServlet extends HttpServlet {
private static final String EXPLORER_PATH = "explorer";
private ServletInitializationParameters initParameters;
private SystemService systemService;
private PathDispatcher<EndpointsContext> dispatcher;
private CorsHandler corsHandler;
#Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
ClassLoader classLoader = getClass().getClassLoader();
this.initParameters = ServletInitializationParameters.fromServletConfig(config, classLoader);
this.systemService = createSystemService(classLoader, initParameters);
this.dispatcher = createDispatcher();
this.corsHandler = new CorsHandler();
}
#Override
public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
String method = getRequestMethod(request);
if ("OPTIONS".equals(method)) {
corsHandler.handle(request, response);
} else {
String path = Strings.stripSlash(
request.getRequestURI().substring(request.getServletPath().length()));
EndpointsContext context = new EndpointsContext(method, path, request, response,
initParameters.isPrettyPrintEnabled());
if (!dispatcher.dispatch(method, path, context)) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
response.getWriter().append("Not Found");
}
}
}
private String getRequestMethod(HttpServletRequest request) {
Enumeration headerNames = request.getHeaderNames();
String methodOverride = null;
while (headerNames.hasMoreElements()) {
String headerName = (String) headerNames.nextElement();
if (headerName.toLowerCase().equals("x-http-method-override")) {
methodOverride = request.getHeader(headerName);
break;
}
}
return methodOverride != null ? methodOverride.toUpperCase() : request.getMethod();
}
private PathDispatcher<EndpointsContext> createDispatcher() {
PathDispatcher.Builder<EndpointsContext> builder = PathDispatcher.builder();
List<EndpointNode> endpoints = systemService.getEndpoints();
// We're building an ImmutableList here, because it will eventually be used for JSON-RPC.
ImmutableList.Builder<EndpointsMethodHandler> handlersBuilder = ImmutableList.builder();
for (EndpointNode endpoint : endpoints) {
ApiConfig apiConfig = endpoint.getConfig();
MethodConfigMap methods = apiConfig.getApiClassConfig().getMethods();
for (Entry<EndpointMethod, ApiMethodConfig> methodEntry : methods.entrySet()) {
if (!methodEntry.getValue().isIgnored()) {
handlersBuilder.add(
new EndpointsMethodHandler(initParameters, getServletContext(), methodEntry.getKey(),
apiConfig, methodEntry.getValue(), systemService));
}
}
}
ImmutableList<EndpointsMethodHandler> handlers = handlersBuilder.build();
for (EndpointsMethodHandler handler : handlers) {
builder.add(handler.getRestMethod(), Strings.stripTrailingSlash(handler.getRestPath()),
handler.getRestHandler());
}
ExplorerHandler explorerHandler = new ExplorerHandler();
builder.add("GET", EXPLORER_PATH, explorerHandler);
builder.add("GET", EXPLORER_PATH + "/", explorerHandler);
builder.add("GET", "static/proxy.html", new ApiProxyHandler());
return builder.build();
}
private SystemService createSystemService(ClassLoader classLoader,
ServletInitializationParameters initParameters) throws ServletException {
try {
SystemService.Builder builder = SystemService.builder()
.withDefaults(classLoader)
.setStandardConfigLoader(classLoader)
.setIllegalArgumentIsBackendError(initParameters.isIllegalArgumentBackendError())
.setDiscoveryServiceEnabled(true);
for (Class<?> serviceClass : initParameters.getServiceClasses()) {
builder.addService(serviceClass, createService(serviceClass));
}
return builder.build();
} catch (ApiConfigException | ClassNotFoundException e) {
throw new ServletException(e);
}
}
/**
* Creates a new instance of the specified service class.
*
* #param serviceClass the class of the service to create
*/
protected <T> T createService(Class<T> serviceClass) {
try {
return serviceClass.newInstance();
} catch (InstantiationException e) {
throw new RuntimeException(
String.format("Cannot instantiate service class: %s", serviceClass.getName()), e);
} catch (IllegalAccessException e) {
throw new RuntimeException(
String.format("Cannot access service class: %s", serviceClass.getName()), e);
}
}
}
EndpointsServlet handles all API calls with a certain path prefix. It takes a RESTful API call and translates it into POJO(s) and dispatches it to a Java method you've written, and then serializes the return value of that method to JSON. It does this based on how you annotate your code.

Servlet Filter login redirection infinite loop [duplicate]

This question already has an answer here:
Servlet filter runs in infinite redirect loop when user is not logged in
(1 answer)
Closed 7 years ago.
I am experimentig with servlet filters. I have created two JSP pages - Home and Login.
I want to create the following flow:
When accessing the Home page without credentials in the session -> redirect to Login page.
When entering the correct credentials (compare them against hardcoded constants) redirect to the Home page.
When entering incorrect credential - redirect to Login page again.
Here is my code so far, I have an issue with an infinite loop when entering the home page directly, because of the null checks. Can you please give me directions on the right approach in this situation.
package bg.filter.test;
import java.io.IOException;
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 ("/pages/*")
public class LoginFilter implements Filter {
private static final String name = "admin";
private static final String pass = "123";
#Override
public void destroy() {
// TODO Auto-generated method stub
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
String name = request.getParameter("username");
String pass = request.getParameter("password");
if (name != null && pass != null) {
if (LoginFilter.name.equals(name) && LoginFilter.pass.equals(pass)) {
((HttpServletRequest) request).getSession().setAttribute("username", name);
((HttpServletRequest) request).getSession().setAttribute("password", pass);
((HttpServletResponse) response).sendRedirect("/FilterLoginTest/pages/Home.jsp");
} else {
((HttpServletResponse) response).sendRedirect("/FilterLoginTest/pages/Login.jsp");
}
} else {
name = (String)((HttpServletRequest) request).getSession().getAttribute("username");
if(name == null) {
((HttpServletResponse) response).sendRedirect("/FilterLoginTest/pages/Login.jsp");
}
}
chain.doFilter(request, response);
}
#Override
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
}
I wonder why do you want to implement it like that ,
Take a look at JAAS
JAAS for human beings
Also if you need to implement this filter , it's a common behavior after login to put the user object for example in the session and just the filter will test it against null,
if it's about authorization you will check the url for example against a predefined list of roles to pass the request or redirect to unauthorized page

AEM Servlet response writter removing links

In AEM, I'm trying to write a JSON object that contains a string object via a get servlet, like this:
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.getWriter().write(jsonObject.toString());
Response being of type SlingHttpServletResponse
When the servlet is accessed in a browser the is stripped with a warning coming out of the aem log:
03.08.2015 16:55:27.359 *WARN* [127.0.0.1 [1438617327343] GET /bin/integration.json HTTP/1.1] com.day.cq.rewriter.linkchecker.impl.LinkCheckerImpl Ignoring malformed URI: java.net.URISyntaxException: Illegal character in path at index 0: \
Link checker is bypassed for a lot of patterns including the link above.
For example the string object inside the json:
pageIntro:'this link doesn't work'
becomes:
pageIntro:'this link</a> doesn't work'
Any help would be much appreciated.
Cheers,
Alex
By doing a quick fiddle around AEM 6.0 , I am not able to reproduce this issue .
Following is what I did in the servlet. Attaching the snippet below. Is there anything else you are doing to achieve this ?
import java.io.IOException;
import javax.servlet.ServletException;
import org.apache.felix.scr.annotations.sling.SlingServlet;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.apache.sling.commons.json.JSONException;
import org.apache.sling.commons.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
#SlingServlet( label = "Stack Overflow - Sabya Test Servlet",
description = "Used for quick fiddle",
paths="/bin/sabya-servlet.json",
metatype = true
)
public class SabyaTestServlet extends SlingAllMethodsServlet {
private static final long serialVersionUID = 1335893917596088016L;
private static final Logger log = LoggerFactory
.getLogger(SabyaTestServlet.class);
#Override
protected void doGet(SlingHttpServletRequest request,
SlingHttpServletResponse response) throws ServletException,
IOException {
log.trace("Sabya Test Servlet : doGet() starts .. ");
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("pageIntro", "this <a href='http://www.domain.com/my-section/page.html'>link</a> doesn't work");
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.getWriter().write(jsonObject.toString());
} catch (JSONException e) {
log.error("Something ridiculous has happened !! {}" , e);
}
log.trace("Sabya Test Servlet : doGet() ends .. ");
}
}
Request URL : http://localhost:4502/bin/sabya-servlet.json
Response :
{
pageIntro: "this <a href='http://www.domain.com/my-section/page.html'>link</a> doesn't work"
}
Note : I believe you are using org.apache.sling.commons.json.JSONObject .

Processing an InputStream to OutputStream on the fly through a HttpServlet

I'm trying to process a large text file through a HttpServlet (tomcat).
As this file can be large and the process should be very fast, I don't want to upload the file on the server and I've used the method HttpRequest.getInputStream to process the input on the fly. For example, I want to transform the input to upper-case with the code below:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
#SuppressWarnings("serial")
public class EchoServlet extends HttpServlet
{
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
OutputStream out=null;
InputStream in=req.getInputStream();
if(in==null) throw new IOException("input is null");
try
{
resp.setContentType("text/plain");
out=resp.getOutputStream();
int c;
while((c=in.read())!=-1)
{
out.write((char)Character.toUpperCase(c));
}
}
catch(IOException err)
{
//ignore
}
finally
{
if(out!=null) out.flush();
if(out!=null) out.close();
in.close();
}
}
}
I invoked my servlet with CURL:
curl -s -d #big.file.txt "http://localhost:8080/test/toupper"
1) processing the input on the fly through a servlet, is it a good/common practice ?
2) my code seems to remove the carriage return ('\n') . Why ?
Thanks
1) processing the input on the fly through a servlet, is it a good/common practice ?
Depends on the functional requirement. I would personally have used a servlet which accepts HTTP multipart/form-data requests instead of raw request bodies. This way it's reuseable on normal HTML forms.
2) my code seems to remove the carriage return ('\n') . Why ?
The given code example doesn't do that. Maybe you've oversimplified it and you was originally using BufferedReader#readLine() while not using PrintWriter#println(). The readLine() indeed eats CRLFs.
There are more issues/inefficiencies in the given code snippet as well, but I can't give a decent answer on that as you seem not to actually be running the code as you posted in the question.

Handle http post request

I have the following scenario to implement:
I have an ASP.NET Web site. On a click of a button in my site the user is redirected to a 3rd party site. When the user does some actions in this 3rd party site, the site starts sending http post requests to my site with a special message every 1 minute.
Now, the problem is that I should handle and process these requests, but I do not know how to do it. Please note that the requests that are sent from the 3rd party site DO NOT open my site by the http post requests. These requests are some kind of background requests, i.e. they do not open a page directly, so they should be handled using another approach.
I have the solution in Java. It is called Servlet. By the help of the servlet I can do the thing that I want in Java. However, I need the same functionality in ASP.NET? Does anybody have a solution for this?
Thanks a lot!
P.S. Just for your reference, here is the Java code for the servlet:
package payment;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import beans.action.PaymentBean;
public class EPayRequestCatcher extends javax.servlet.http.HttpServlet
implements javax.servlet.Servlet{
static final long serialVersionUID = 1L;
public EPayRequestCatcher() {
super();
}
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException{
doPost(request, response);
}
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException{
String encoded = request.getParameter("encoded");
PaymentUtil util = new PaymentUtil();
if (encoded != null) {
String decoded = util.getDecodedB64Data(encoded);
int invStart = decoded.indexOf("=") + 1;
int invEnd = decoded.indexOf(":", invStart);
String invoice = decoded.substring(invStart, invEnd);
System.out.println("" + invoice);
String checksum = request.getParameter("checksum");
PaymentBean bean = new PaymentBean();
String responseStatus = bean.getEpayRequest(encoded, checksum);
if (!responseStatus.equals("")) {
String responseData = "INVOICE=" + invoice + ":STATUS=" + responseStatus + "\n";
System.out.println(responseData);
response.getWriter().append(responseData);
}
}
else {
return;
}
}
}
TheVisitor,
if I understood well, an external website will POST some data to your ASP.NET website; you'll (probably) define a page to receive that post and don't know how to handle it, right?
Well, you can try something like:
protected void Page_Load(object sender, EventArgs e)
{
string encoded = Request["encoded"];
string checksum = Request["checksum"];
// do stuff
Response.Write("some response");
}
This could be enough, depending on you requirements.
HTH

Resources