user10227658
user10227658

Reputation:

How to create filter in Spring RESTful for Prevent XSS?

i use from Spring 4.2.6.RELEASE and backend is rest services. and now I can not have a filter for Prevent XSS

my filter is:

@Component
@Order(1)
public class XSSFilter implements Filter {

  @Override
  public void init(FilterConfig filterConfig) throws ServletException {
  }

  @Override
  public void destroy() {
  }

  @Override
  public void doFilter(
        ServletRequest request, 
        ServletResponse response, 
        FilterChain chain) throws IOException, ServletException {

      chain.doFilter(new XSSRequestWrapper((HttpServletRequest) request), response);
   }

}

and XSSRequestWrapper is :

public class XSSRequestWrapper extends HttpServletRequestWrapper {

  public XSSRequestWrapper(HttpServletRequest servletRequest) {
    super(servletRequest);
  }

  @Override
  public String[] getParameterValues(String parameter) {
    String[] values = super.getParameterValues(parameter);

    if (values == null) {
        return null;
    }

    int count = values.length;
    String[] encodedValues = new String[count];
    for (int i = 0; i < count; i++) {
        encodedValues[i] = stripXSS(values[i]);
    }

    return encodedValues;
  }

  @Override
  public String getParameter(String parameter) {
    String value = super.getParameter(parameter);

    return stripXSS(value);
  }

  @Override
  public String getHeader(String name) {
    String value = super.getHeader(name);
    return stripXSS(value);
  }

  private String stripXSS(String value) {

    return StringEscapeUtils.escapeHtml(value);
  }
}

and in WebConfig extends WebMvcConfigurerAdapter Class:

// -----------------------------------------------------
// Prevent XSS
// -----------------------------------------------------

@Bean
public FilterRegistrationBean xssPreventFilter() {
    FilterRegistrationBean registrationBean = new FilterRegistrationBean();

    registrationBean.setFilter(new XSSFilter());
    registrationBean.addUrlPatterns("/*");

    return registrationBean;
}

My Rest Class is:

@RestController
@RequestMapping("/personService")
public class PersonController extends BaseController<PersonDto, PersonCriteria> {

  @RequestMapping( value= "/test" )
  private void getTest2(@RequestParam String name) {

      System.out.println(name);

      System.out.println( StringEscapeUtils.escapeHtml(name) );

  }

}

But it does not work, without any Error or Exception. How can I do this and create my own filter? I use only Java Config and no XML. in my Controller I was forced again use StringEscapeUtils.escapeHtml(name) and this is bad.

Upvotes: 5

Views: 23494

Answers (2)

hardMaster
hardMaster

Reputation: 21

A simple XSS filter implementation. Create two java classes named as XSSFilter and XSSRequestWrapper respectively and use the below implementation respectively:

package com.example.config;

import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

@Component
@Order(1)
public class XSSFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {}

    @Override
    public void destroy() {}

    @Override
    public void doFilter(
        ServletRequest request,
        ServletResponse response,
        FilterChain chain) throws IOException, ServletException {
        chain.doFilter(new XSSRequestWrapper((HttpServletRequest) request), response);
    }
}
package com.example.config;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.util.regex.Pattern;

public class XSSRequestWrapper extends HttpServletRequestWrapper {

    private static Pattern[] patterns = new Pattern[] {
        Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE),
            Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
            Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
            Pattern.compile("</script>", Pattern.CASE_INSENSITIVE),
            Pattern.compile("<script(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
            Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
            Pattern.compile("expression\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL),
            Pattern.compile("javascript:", Pattern.CASE_INSENSITIVE),
            Pattern.compile("vbscript:", Pattern.CASE_INSENSITIVE),
            Pattern.compile("onload(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL)
    };

    public XSSRequestWrapper(HttpServletRequest servletRequest) {
        super(servletRequest);
    }

    @Override
    public String[] getParameterValues(String parameter) {
        String[] values = super.getParameterValues(parameter);
        if (values == null) {
            return null;
        }
        int count = values.length;
        String[] encodedValues = new String[count];
        for (int i = 0; i < count; i++) {
            encodedValues[i] = stripXSS(values[i]);
        }

        return encodedValues;
    }

    @Override
    public String getParameter(String parameter) {
        String value = super.getParameter(parameter);
        return stripXSS(value);
    }

    @Override
    public String getHeader(String name) {
        String value = super.getHeader(name);
        return stripXSS(value);
    }

    private String stripXSS(String value) {
        if (value != null) {
            value = value.replaceAll("\0", "");
            for (Pattern scriptPatter: patterns) {
                value = scriptPatter.matcher(value).replaceAll("");
            }
        }
        return value;
    }
}

The below lines can be added to the main class of the application:

@Bean("xssPreventFilter")
public FilterRegistrationBean < XSSFilter > xssFilterFilter() {
    FilterRegistrationBean < XSSFilter > registrationBean = new FilterRegistrationBean < XSSFilter > ();
    registrationBean.setFilter(new XSSFilter());
    registrationBean.addUrlPatterns("/*");
    return registrationBean;
}

Upvotes: 0

Mehdi Tahmasebi
Mehdi Tahmasebi

Reputation: 1084

I’ve created a fully executable sample project based on your codes.

Everything goes fine, you can download full source from my github https://github.com/mehditahmasebi/spring/tree/master/spring-xss-filter and for running command “mvnw spring-boot:run” and in browser type: http://localhost:8080/personService/test?name=foobar, so you can see result in XSSRequestWrapper.stripXSS.

I hope this source code will help you.


Some explanation :

Project structure :

  • POM.xml
  • WebConfig.java for Spring web config
  • SpringBootApplication.java for starting up application
  • your classes (PersonController.java, XSSFilter.java and XSSRequestWrapper.java)

dive into them, but I was only copy important lines :

pom.xml

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>commons-lang</groupId>
        <artifactId>commons-lang</artifactId>
        <version>2.6</version>
    </dependency>
</dependencies>

WebConfig.java (at the bottom lines you can see your bean) :

@Configuration
@EnableWebMvc
@EnableWebSecurity
public class WebConfig extends WebSecurityConfigurerAdapter implements WebMvcConfigurer {

    @Override
    protected void configure(HttpSecurity http) throws Exception {      
        http
            .authorizeRequests()
                .anyRequest().permitAll()
            .and().csrf().disable();
    }

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
        .allowCredentials(true)
        .allowedHeaders("*")
        .allowedMethods("GET, POST, PATCH, PUT, DELETE, OPTIONS")
        .allowedOrigins("*");
    }

    @Bean
    public FilterRegistrationBean xssPreventFilter() {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();

        registrationBean.setFilter(new XSSFilter());
        registrationBean.addUrlPatterns("/*");

        return registrationBean;
    }
}

SpringBootApplication.java (for starting up project) :

@SpringBootApplication
public class SpringbootApplication extends SpringBootServletInitializer {

    /**
     * tomcat deployment needed
     */
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(SpringbootApplication.class);
    }

    public static void main(String[] args) {
        SpringApplication.run(SpringbootApplication.class, args);
        System.out.println("Spring boot application started!");

    }
}

The other java source files is exactly as you are , but with 2 changes :

first, I've added a sysout line to see trace of your code without debugging:

private String stripXSS(String value) {
    if(value != null)
        System.out.println("escapeHTML work successfully and escapeHTML value is : " + StringEscapeUtils.escapeHtml(value));
    return StringEscapeUtils.escapeHtml(value);
}

and the second change is, I commented escapeHtml from PersonController as you said is not a good idea:

  @RequestMapping( value= "/test" )
  private void getTest2(@RequestParam String name) {

      System.out.println(name);

//      System.out.println( StringEscapeUtils.escapeHtml(name) );

  }

You can find all the source at my github https://github.com/mehditahmasebi/spring/tree/master/spring-xss-filter

Upvotes: 17

Related Questions