4
votes

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.

2
Hi, what about HtmlUtils.htmlEscape(yourDangerousString) docs.spring.io/spring/docs/current/javadoc-api/org/… 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
Do you have more code? How do you use it? Was looking for a global solution that might protect an entire website.Berlin Brown
My first hit on google looking for examples is programcreek.com/java-api-examples/… , 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 yourselfMelardev

2 Answers

3
votes

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 .

4
votes

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