4

How do you protect, sanitize applications that take raw JSON bodies and typically output JSON responses and don't use Spring Boot. I only saw one good example that might work and used JsonComponent. If we don't use jsoncomponent, how to filter out a request to remove bad cross site scripting tags from a the entire JSON request body? Also, it would be OK to detect XSS tags in the request body and throw an error.

Also looking for a global solution that might protect all input/output of JSON requests and add that code in one area. We could use JSR bean validation but we would have to hit all of the define properties and variables.

Is it possible to also look at the JSON payload for data which could include script tags.

Berlin Brown
  • 11,504
  • 37
  • 135
  • 203
  • 1
    Hi, what about HtmlUtils.htmlEscape(yourDangerousString) https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/util/HtmlUtils.html#htmlEscape-java.lang.String- That method does some filtering, if you are interested in blocking then you check if(yourDangerousString.equals(HtmlUtils.htmlEscape(yourDangerousString))return ResponseEntity.status(HttpStatus.BAD_REQUEST); – Melardev Mar 19 '18 at 22:45
  • Do you have more code? How do you use it? Was looking for a global solution that might protect an entire website. – Berlin Brown Mar 20 '18 at 12:33
  • 1
    My first hit on google looking for examples is https://www.programcreek.com/java-api-examples/?api=org.springframework.web.util.HtmlUtils , there is not too much to say, you place one of such calls in your filter and that should be it, do you really need me to write a working demo for you? just let me know if you want me to do it if you can't do it yourself – Melardev Mar 20 '18 at 13:48

2 Answers2

4

Ok finally I did it, I post my solution as response instead of comment, it is functional but no very robust, if you want me to improve it with exception handlers etc let me know

The AntiXssDemoApplication.java is

package com.melardev.stackoverflow.demos.antixssdemo;

import com.melardev.stackoverflow.demos.antixssdemo.filters.AntiXssFilter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

import javax.servlet.Filter;

@SpringBootApplication
@ServletComponentScan
public class AntiXssDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(AntiXssDemoApplication.class, args);
    }

}

the AntiXssFilter

package com.melardev.stackoverflow.demos.antixssdemo.filters;

import org.springframework.web.util.HtmlUtils;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

@WebFilter(urlPatterns = "/*")
public class AntiXssFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("Filter initialized");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        String userInput = servletRequest.getParameter("param");
        if (userInput != null && !userInput.equalsIgnoreCase(HtmlUtils.htmlEscape(userInput)))
            throw new RuntimeException();
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {
        System.out.println("destroy");
    }
}

The Controller

package com.melardev.stackoverflow.demos.antixssdemo.controllers;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/")
public class HomeController {
    @RequestMapping("/xss-reflected")
    @ResponseBody
    public String xssDemo(@RequestParam("param") String userInput) {
        return userInput;
    }
}

The demo:

  1. open browser at localhost:8080/xss-reflected?param=Look at this reflected content, works!!
  2. open browser at localhost:8080/xss-reflected?param=<h1>Look at this reflected content, works!!</h1>

At step 2, I have used the html tag h2. You should see a Runtime exception thrown from Filter, what happened is: The Filter intercepts all urls(because of urlPatterns=/**), for each interception doFilter is called, if the user supplied Html content, then HtmlUtils.htmlEscape will return the filtered string, in other words, the returned string is different from the original one, this means the user supplied Html in his json input, which is not what we expect, so we throw the exception, if the returned string is the same as the string returned by htmlEscape(userInput) this means the user has not supplied any Html content, in that case we let the request pipeline to flow as usual with filterChain.doFilter(servletRequest, servletResponse); I am not using a live XSS demo because chrome will most likely protect you since it is a very basic reflected XSS detected by anyone ...

The Spring Boot skeleton project was downloaded from https://start.spring.io/ with Web as the only starter dependency.

Edit: Improved code

fgb
  • 18,439
  • 2
  • 38
  • 52
Melardev
  • 1,101
  • 10
  • 22
  • Will this work for JSON payloads as a raw request body? – Berlin Brown Mar 20 '18 at 21:48
  • @BerlinBrown why not? you can request.getInputStream(), then store it to a String, then you call HtmlUtils.htmlEscape(), to convert stream to String you can use Apache Commons as follows: String requestBody = IOUtils.toString(request.getInputStream(), encoding); then you htmlEscape(requestBody) – Melardev Mar 20 '18 at 21:56
  • Html characters can appear as valid data in other contexts. Quote characters in particular are required within JSON input which will be rejected by this method. – fgb Mar 21 '18 at 13:16
  • Exactly, my demo in the current state is not suitable for all situations, my demo is too restrictive. But you can easily add some code on top and not throw an exception but just encode the user input. which is what most developers do – Melardev Mar 21 '18 at 17:03
  • how to prevent a file(multipart). any suggestion – Vipul Pandey Sep 07 '21 at 09:13
3

First of all , concept to protect against vulnerabilities has nothing to do with SpringBoot and XSS is one of those vulnerabilities.

This vulnerability is protected by implementing a org.springframework.web.filter.OncePerRequestFilter and depending on which top framework you use & what kind of app you have - filter registration & chaining process has to be implemented.

Idea is to simply sanitize every incoming JSON body & call next filter in chain with sanitized request body.

If you have a Spring based project, you should first try to use Spring Security dependencies and enable default security features. refer this question

For xss protection , offered by spring security they have this disclaimer -

Note this is not comprehensive XSS protection!

In my case, I wrote a custom XSS protection filter implementing - org.springframework.web.filter.OncePerRequestFilter

In this filter- I have used this API ,

<dependency>
            <groupId>org.owasp.esapi</groupId>
            <artifactId>esapi</artifactId>
</dependency>

In my code , I have listed down possible attack patterns but I guess there might be better way to do it.

Refer these two on SO to know more as what I am talking about - XSS filter to remove all scripts & How to Modify QueryParam and PathParam in Jersey 2

Answer by Melardev is explaining the only case for @RequestParam & you have to extend that approach to handle the case when its a JSON body. I have handled the case of a json body but can't share my code due to company copy right .

Sabir Khan
  • 9,826
  • 7
  • 45
  • 98