Search code examples
javarestapigrails

How to prevent XSS attacks or untrusted data in Rest API JSON using Java?


I had developed a Rest API application and have handled Authentication and Authorization using custom JWT. I want to further make the application secure from XSS attacks or validation for untrusted data which could be handled for each and every field of JSON request.

Can I get some help in this regard so that efficient data processing will happen at the entry-level of the request without touching internal business validation?


Solution

  • Need to override the HttpServletRequest in a Servlet Filter(if you are using Servlet).

    1. Extends HttpServletRequestWrapper that stores JSON body(intention is to sanitize JSON body).

    2. Strip/ escape the eligible JSON value

    Extented "HttpServletRequestWrapper" :

    public class SanitizationRequestWrapper extends HttpServletRequestWrapper {
        
            public byte[] getBody() {
                return body;
            }
        
            public void setBody(byte[] body) {
                this.body = body;
            }
        
            private byte[] body;
        
            public SanitizationRequestWrapper(HttpServletRequest request) throws IOException {
                super(request);
                try {
                    body = IOUtils.toByteArray(super.getInputStream());
                }catch (NullPointerException e){
        
                }
            }
        
            @Override
            public ServletInputStream getInputStream() throws IOException {
                return new ServletInputStreamImpl(new ByteArrayInputStream(body));
            }
        
            @Override
            public BufferedReader getReader() throws IOException {
                String enc = getCharacterEncoding();
                if (enc == null) enc = "UTF-8";
                return new BufferedReader(new InputStreamReader(getInputStream(), enc));
            }
        
            private class ServletInputStreamImpl extends ServletInputStream {
        
                private InputStream is;
        
                public ServletInputStreamImpl(InputStream is) {
                    this.is = is;
                }
        
                public int read() throws IOException {
                    return is.read();
                }
        
                public boolean markSupported() {
                    return false;
                }
        
                public synchronized void mark(int i) {
                    throw new RuntimeException(new IOException("mark/reset not supported"));
                }
        
                public synchronized void reset() throws IOException {
                    throw new IOException("mark/reset not supported");
                }
            }
        }
        
    

    Servlet filter which sanitize request body:

        public class XSSSanitizeFilters implements Filter {
                @Override
            public void destroy() {
            }
        
            @Override
            public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException {
                HttpServletRequest request = (HttpServletRequest) arg0;
                HttpServletResponse response = (HttpServletResponse) arg1;
                SanitizationRequestWrapper sanitizeRequest = new SanitizationRequestWrapper(request);
                    if (null != sanitizeRequest.getBody()) {
                        try {
                            sanitizeJson(sanitizeRequest);
                        } catch (ParseException e) {
                            LOG.error("Unable to Sanitize the provided JSON .");
                        }
                        arg2.doFilter(sanitizeRequest, arg1);
        
                    } else {
                        arg2.doFilter(arg0, arg1);
                    }       
            }
        
            public void init(FilterConfig filterConfig) throws ServletException {
        
            }
        
            private void sanitizeJson(SanitizationRequestWrapper sanitizeRequest ) throws IOException, ParseException {
                    JSONParser parser= new JSONParser();
                    Object obj = parser.parse(sanitizeRequest.getReader());
                     ObjectMapper oMapper = new ObjectMapper();
                    Map <String, Object> map = oMapper.convertValue(obj, Map.class);
                    sanitizeRequest.setBody((new JSONObject(map)).toString().getBytes());
            }