How to handle parser exceptions during unmarshalling JSON data?

I use jersey in my web application. The data sent to the server is in JSON format, which, in turn, is not tied to the server, and the received object is used for further processing. A security audit revealed some vulnerabilities for this approach.

My rest code:

@POST
@Path("/registerManga")
@Produces(MediaType.APPLICATION_JSON)
public Response registerManga(MangaBean mBean){
    System.out.println(mBean);
    return Response.status(200).build();
}

MangaBean:

public class MangaBean {
    public String title;
    public String author;

    @Override
    public String toString() {
        return "MangaBean [title=" + title + ", author=" + author + "]";
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getAuthor() {
        return author;
    }
    public void setAuthor(String author) {
        this.author = author;
    }


}

Data is sent in the following format:

["title":"Bleach","author":"kubo tite"]

The above data is not successfully bound to the object, and I get this as a result:

MangaBean [title=Bleach, author=kubo tite]

But if the data is changed to:

["title":"<script>alert("123");</script>","author":"kubo tite"]

An internal server 500 error occurs and is displayed to the user:

javax.servlet.ServletException: org.codehaus.jackson.JsonParseException: Unexpected character ('1' (code 49)): was expecting comma to separate OBJECT entries
 at [Source: org.apache.catalina.connector.CoyoteInputStream@19bd1ca; line: 1, column: 28]
    com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:420)
    com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:537)
    com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:699)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:717)

An unexpected appearance ""causes errors in the parser. Since unmarshalling is done behind the scenes, and I have no control over it, I cannot handle the exception.

, stacktrace. .

+5
6

JSON:

@Provider
class JSONParseExceptionMapper implements ExceptionMapper< JsonParseException > {
    @Override
    public Response toResponse(final JsonParseException jpe) {
        // Create and return an appropriate response here
        return Response.status(Status.BAD_REQUEST)
                .entity("Invalid data supplied for request").build();
    }
}
+14

( ), , ResourceConfig.

, JacksonFeature ( Jersey 2.x) , , .

. JSONParseExceptionMapper "your.package.here", .

@ApplicationPath("whatever")
public class MyAppResourceConfig extends ResourceConfig
{
    public MyAppResourceConfig()
    {
        packages("your.package.here");
        register(JacksonFeature.class);
    }
}

JsonMappingExceptionMapper.

+1

In addition to @Perception's answer, the missing part is that exceptions are swallowed and not reported. You must pass a listener check:

private static final String[] severity = new String[] {"Warning", "Error", "Fatal Error"};
void beforeUnmarshal(Unmarshaller u, Object parent) throws JAXBException {
    u.setEventHandler((evt) -> {
        throw new WebApplicationException(severity[evt.getSeverity()]+": Error while parsing request body: " + evt.getMessage(), evt.getLinkedException(), 400);
    });
}

Just release this code in your JAXB bean and all your settings.

+1
source

Adding an example of a full perception response class

package com.shashi.service;

import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;

import org.apache.log4j.Logger;

import org.codehaus.jackson.JsonParseException;
import com.sun.jersey.api.client.ClientResponse.Status;
import com.talklingo.service.v1.UserManagementService;
@Provider
public class JSONParseExceptionMapper implements ExceptionMapper< JsonParseException > {

 private static Logger logger = Logger
   .getLogger(JSONParseExceptionMapper.class);

   public Response toResponse(final JsonParseException jpe) {
         // Create and return an appropriate response here

         return Response.status(Status.BAD_REQUEST)
                 .entity("Invalid data supplied for request").build();

     }
}
0
source

Another option might be in ResourceConfig to register the JsonParseExceptionMapper class.

Register (JsonParseExceptionMapper.class);

0
source

Add the exception handling class to the same package (or optional package) mentioned in the web.xml file

0
source

All Articles