Spring: How to add XSS protection to #RequestBody in a RESTful service? - java

I am trying to add custom XSS protection by creating a RequestWrapper extending HttpServletRequestWrapper in an XSS filter. The below code provides XSS protection to:
1. Request Params
2. Payload.
public class XssRequestWrapper extends HttpServletRequestWrapper {
XssRequestWrapper(HttpServletRequest request) {
super(request);
}
#Override
public String getQueryString() {
/*
Custom XSS logic
*/
}
#Override
public String getParameterMap() {
/*
Custom XSS logic
*/
}
#Override
public String getParameterValues() {
/*
Custom XSS logic
*/
}
}
But when I configure my REST Api with #RequestBody Annotation in my controller, the overridden getParameterValues is not invoked. Instead, getInputStream is invoked, which results in the addition of the following:
#Override
public ServletInputStream getInputStream() throws IOException {
/*
Custom XSS logic
*/
}
Is there any better/ideal way to provide XSS protection to data passed via #RequestBody annotation?
Edit:
Solution: https://www.baeldung.com/spring-reading-httpservletrequest-multiple-times
Since I was using ContentCachingRequestWrapper in one of my previous filters, I was unable to use the same and hence went forward with the above solution.
By Caching the request, I was able to read it multiple times and perform XSS check over the cached content.

I am a bit confused of what you are trying to achieve with the code.
First thing first - there are three types of Cross-site Scripting (XSS) vulnerabilities:
DOM based - runs in the browser often due a flaw in JavaScript. No server calls are needed for the vulnerability to be exploited.
Reflected XSS - the payload gets reflected in the HTML body by the web server.
Persistent XSS - the payload lands in the DB and is embedded in the HTML body by the web server.
So there are no ways you can address the DOM based XSS with a request wrapper because there is no need for a request to be made.
You might try to address the points 2 and 3, but handling with the request values is a uncommon thing to be done. XSS vulnerabilities are context sensitive, and if you try to encode or escape without knowing the context in which the value is to be used later - you might and will fail.
Please look over the XSS prevention cheat sheet from OWASP to learn how to prevent XSS flaws in the code.

Related

Server side custom headers with embedded jetty and jersey

We have a legacy application that uses embedded Jetty and provides functionality through clients making HTTP calls. Most of the information/parameters needed by the server is sent by the client through HTTP headers. We are now prototyping the use of REST API calls using Jersey where the same parameters are provided as JSON inputs. One of the requirements is to maintain backward compatibility and not disturb the existing functionality.
While we were able to use Jersey and pass in parameters, we are looking for help with the following:
We want to avoid changing the current jetty handlers in the application, so we would like to convert the json input from the REST API input into headers and pass them on to the handlers, so that the current functionality can kick in from that point.
I have tried the other (very helpful) posts on using the wrapper/filter mechanisms to add custom headers, even one using the ContainterRequestFilter. Following are my references:
Adding an HTTP header to the request in a servlet filter
How to add servlet filter with embedded jetty
How to add a header to http request using a filter in jax-rs
However for security reasons, the legacy application has this line of code (recommended in Jetty docs) which uses the base request instead of the wrapped request:
Request base_request = request instanceof Request ? (Request)request : HttpConnection.getCurrentConnection().getHttpChannel().getRequest();
Response base_response = response instanceof Response ? (Response)response : HttpConnection.getCurrentConnection().getHttpChannel().getResponse();
This effectively does not use the HttpServletRequestWrapper object that I send in. Since this line of code looks for the org.eclipse.jetty.server.Request object, I tried creating a wrapper around this object, like so, but this did not work because this instance seems to have most of the content as null, plus it would not provide the rest of the methods that the Request object would provide.
class MyRequestWrapper extends Request
{
public MyRequestWrapper(HttpServletRequest request)
{
super( ((Request)request).getHttpChannel(), ((Request)request).getHttpInput());
}
#Override
public String getHeader(String name)
{
if(name.equalsIgnoreCase("X-My-Test"))
{
return "MyName";
}
return super.getHeader(name);
}
}
What is the best way to send the JSON inputs in as headers from the REST handling method to the existing Jetty handlers, without creating security concerns? I guess I could tweak that check for the base request a bit, but I am not sure of the best way to do it.
Wrapped requests are only valid for the same ServletContext and Filter chain that the wrapped request was created in and only applies to the rest of the executing Filter chain from the point in time it was created.
A wrapped request will never apply to a standard Jetty Handler, as that's not participating in a ServletContext or Filter chain.
It is also impossible to wrap the core Jetty Request object due to the needs of the context-less environment it executes within. You cannot change this behavior.
If you are wrapping requests and whatnot just to provide a custom request header, then stop doing ALL of the wrapping and nonsense you are dealing with right now.
Note: The minute you stop wrapping HttpServletRequest, HttpServletResponse, or the Servlet streams is the minute you will have the ability to use features introduced for Servlet 3.0 and newer, such as AsyncContext and Async I/O. The technique of wrapping these components is discouraged in modern usage because it limits your options for better performing webapps.
You have 2 choices, both modify the Request headers in-place.
Modify the Request headers before dispatch.
Modify the Request headers during dispatch via a low level Jetty Handler.
If you choose to modify the headers before dispatch, there are 2 places you can do this.
As a HttpConfiguration.Customizer
During one of the pre-dispatch HttpChannel.Listener events
If you choose to modify the headers during dispatch, then create a Jetty Handler that modifies the Request headers, and put it somewhere early in your server handler hierarchy.
The code that modifies the Request headers will all do the same thing, here's the Handler version as an example.
package jetty.demo;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.handler.HandlerWrapper;
public class ModifyRequestHeadersHandler extends AbstractHandler
{
#Override
public void handle(String target, Request baseRequest,
HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
// As fully fleshed out field
final HttpField X_MY_TEST = new HttpField("X-My-Test", "MyName");
baseRequest.getHttpFields().put(X_MY_TEST);
// As predefined header and custom value
baseRequest.getHttpFields().put(HttpHeader.X_POWERED_BY,
"ModifiedRequestHeadersHandler");
// As string header and string value
baseRequest.getHttpFields().put("X-Foo-Test", "MyFooName");
}
}

Using only one servlet

I'am making a web page with a login system and backoffice page. The problem is, both use the method "doPost" (the login use to autenticate and the backoffice use to insert data in db). How can I use only one servlet for both? I'am asking this because both use doPost, so I made two servlet's.
In case you want to use a single servlet, you should implement Front Controller Pattern. For this, you will parse the request URL and decide which action should be performed:
public class MySingleServlet extends Servlet {
#Override
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
String url = request.getPathInfo();
//returns the action to handle
Action action = ActionFactory.getAction(url);
action.process(request, response);
}
}
This involves an Action interface/abstract class and an ActionFactory that will parse the URL and return the right implementation to handle the actions to do.
Another more naive and harder-to-maintain implementation is by sending an action parameter. This may be a problem because an attacker may use a proxy and change the action parameter before sending the request to the URL. If this is a recognized valid action, and the attacker knows what to send, then you're in trouble.
Note that there are MVC frameworks that already implement Front Controller Pattern like Spring MVC and JSF, so there's no need to reinvent the wheel unless it is for learning purposes (otherwise, you should use a library that already implements this).
You could add an extra parameter (e.g. action) in your post method
retrieved from a hidden form field, if you are using forms, or
added with a simple &action='value' to your request if using xml http request
and based on its value perform the appropriate actions:
if (action.equals("auth"))
{
// authenticate
}
else if (action.equals("backoffice"))
{
// db update
}
You can get pathInfo from request object based on that you route the request.

Alternative of URL parameter for deciding which method to call

Right now based on the site name in the URL parameter, we decide the appropriate actions to take(method calls etc) in the Java (Standard Jsp/Servlet web applications). For example, the request would be something like www.oursite.com?site=Ohio
Wondering what would be the alternative of doing this without having to provide URL parameter.
You could use POST instead of GET.
GET appends request parameters to the end of the URL.
POST sends encoded data using a form.
http://www.tutorialspoint.com/jsp/jsp_form_processing.htm
Why not just code it into the path?
www.oursite.com/Ohio
If you're just using straight servlet api, you can just do something of this nature:
String path = request.getPathInfo();
String site = path.split("/")[0];
That being said, most web frameworks have some support for helping with this.
For example, in spring mvc:
#RequestMapping(value="/{site}/blah/blah", method=RequestMethod.GET)
public ModelAndView blahBlah(HttpServletRequest req,
HttpServletResponse resp,
#PathVariable("site") String site) {
// do stuff here
}
Of course you could do this at the controller level too if all your methods need that sort of mapping:
#Controller
#RequestMapping(value="/{site}")
public class MyController {
#RequestMapping(value="/blah/blah", method=RequestMethod.GET)
public ModelAndView blahBlah(HttpServletRequest req,
HttpServletResponse resp,
#PathVariable("site") String site) {
// do stuff here
}
}
I believe this is cleaner than a query param, though it still shows up in your URL. There's other, more complex methods like using apache's reverse proxying and virtual host capabilities to switch based on site names. You could do something at login, and store the site in session. It all depends on your requirements.
You could use an alternate URL, like ohio.oursite.com. This process could be automated by having your server respond to *.oursite.com. I would probably set up a filter that looked at what the subdomain was and compared that with a predefined list of allowed sites. If it didn't exist, you could redirect back to the main (www) site. If it did, you could set a request attribute that you could use in a similar way that you currently use the request parameter now.

How to intercept custom HTTP header value and store it in Wicket's WebSession?

I need to grab a certain custom HTTP header value from every request and put it in WebSession so that it will be available on any WebPage later on. (I believe the Wicket way to do this is to have a custom class extending WebSession that has appropriate accessors.)
My question is, what kind of Filter (or other mechanism) I need to be able to both intercept the header and access the WebSession for storing the value?
I tried to do this with a normal Java EE Filter, using
CustomSession session = (CustomSession) AuthenticatedWebSession.get();
But (perhaps not surprisingly), that yields:
java.lang.IllegalStateException:
you can only locate or create sessions in the context of a request cycle
Should I perhaps extend WicketFilter and do it there (can I access the session at that point?), or is something even more complicated required?
Of course, please point it out if I'm doing something completely wrong; I'm new to Wicket.
I'd guess you need to implement a custom WebRequestCycle:
public class CustomRequestCycle extends WebRequestCycle{
public CustomRequestCycle(WebApplication application,
WebRequest request,
Response response){
super(application, request, response);
String headerValue = request.getHttpServletRequest().getHeader("foo");
((MyCustomSession)Session.get()).setFoo(headerValue);
}
}
And in your WebApplication class you register the custom RequestCycle like this:
public class MyApp extends WebApplication{
#Override
public RequestCycle newRequestCycle(Request request, Response response){
return new CustomRequestCycle(this, (WebRequest) request, response);
}
}
Reference:
Request cycle and request cycle
processor

Is a GWT app running on Google App Engine protected from CSRF

I'm developing a GWT app running on the Google App Engine and wondering if I need to worry about Cross-site request forgery or is that automatically taken care of for me?
For every RPC request that requires authentication, I have the following code:
public class BookServiceImpl extends RemoteServiceServlet implements
BookService {
public void deleteInventory(Key<Inventory> inventoryKey) throws NotLoggedInException, InvalidStateException, NotFoundException {
DAO dao = new DAO();
// This will throw NotLoggedInException if user is not logged in
User user = dao.getCurrentUser();
// Do deletion here
}
}
public final class DAO extends DAOBase {
public User getCurrentUser() throws NotLoggedInException {
currentUser = UserServiceFactory.getUserService().getCurrentUser();
if(currentUser == null) {
throw new NotLoggedInException();
}
return currentUser;
}
I couldn't find any documentation on how the UserService checks authentication. Is it enough to rely on the code above or do I need to to more? I'm a beginner at this, but from what I understand to avoid CSRF attacks some of the strategies are:
adding an authentication token in
the request payload instead of just
checking a cookie
checking the HTTP
Referer header
I can see that I have cookies set from Google with what look like SID values, but I can't tell from the serialized Java objects in the payloads if tokens are being passed or not. I also don't know if the Referer header is being used or not.
So, am I worrying about a non-issue? If not, what is the best strategy here? This is a common enough problem, that there must be standard solutions out there...
If you were to put the same code in a regular servlet, you'd surely be vulnerable to XSRF. But since you are using GWTs RemoteServiceServlet - the answer depends on the version of GWT you are using.
Starting with the yet-to-be-release GWT 2.1, the RPC mechanism adds request headers and validates the presence of these headers in RemoteServiceServlet. This has its limitations - in particular, older versions of flash allow you to send the request headers from a different domain, but it does make things more difficult for a potential attacker.
If you want to adequately protect yourself from XSRF, refer to Lombardi's Development blog. The blog discusses two techniques. The first is a simple change that ports 2.1 changes to older versions of GWT. The second approach requires duplicating the session identifier as a request parameter, and is the recommended way to protect against XSRF.
References
GWT RPC - Does it do enough to protect against CSRF?
Lombardi development blog on GWT RPC and XSRF
Security for GWT Applications

Categories