2013-02-13 13 views
5

Sto usando Jersey nella mia applicazione Web. I dati inviati al server sono in formato JSON, che a sua volta è unmarshalled sul server-end e l'oggetto ottenuto viene utilizzato in ulteriore elaborazione. L'audit di sicurezza ha sollevato alcune vulnerabilità per questo approccio.Come gestire le eccezioni del parser durante lo smantellamento dei dati JSON?

My Code Riposo:

@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; 
    } 


} 

I dati vengono inviati in questo formato:

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

I dati sopra riportati deserializzati con successo in un oggetto e mi ottenere questo come output:

MangaBean [title=Bleach, author=kubo tite] 

Ma se i dati viene modificato in:

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

si verifica un errore del server interno 500 e viene visualizzato all'utente:

javax.servlet.ServletException: org.codehaus.jackson.JsonParseException: Unexpected character ('1' (code 49)): was expecting comma to separate OBJECT entries 
at [Source: [email protected]; 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) 

L'imprevisto di "" sta provocando errori nella parser. Dato che l'unmarshalling è fatto dietro le quinte e non ho il controllo su di esso, non sono in grado di gestire l'eccezione che viene sollevata.

La mia domanda è come posso gestire questa eccezione e restituire una risposta corretta all'utente invece di uno stacktrace. Per favore consiglio

risposta

14

Pubblicare un mapper un'eccezione per gestire le JSON eccezioni di analisi:

@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(); 
    } 
} 
+0

Non capisco veramente come utilizzare la sintassi @Provider. Posso usarlo per gestire il seguente scenario: L'API indisciplinata restituisce [] quando una mappa è vuota anziché {}. Sembra che da quanto sopra, ho potuto mappare questa eccezione e gestirlo? – deepwinter

+1

Non riesco a far funzionare tutto questo in Jersey 2.13. Ugh. –

+0

Stiamo usando CXF, ma questo ha funzionato comunque. Grazie! – fool4jesus

0

Aggiunta di esempio completo di classe della percezione risposta

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

Questo non viene chiamato, cos'altro devo fare? –

1

Se questo mapper eccezione non viene chiamato (come il commento di John Ding indicato), assicurarsi di averlo registrato con ResourceConfig.

Inoltre, prendere nota che quando si utilizza la funzione Jackson (con Jersey 2.x) include un mapper di eccezione per questo, ma se si registra il proprio avrà la precedenza.

Ecco un esempio di registrazione per pacchetto. Quindi metti JSONParseExceptionMapper in "your.package.here" e verrà prelevato.

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

Per la domanda iniziale, è necessario gestire JsonMappingExceptionMapper pure.

0

L'altra opzione potrebbe essere in ResourceConfig, registrare la classe JsonParseExceptionMapper.

register (JsonParseExceptionMapper.class);

0

aggiungere la classe di gestione delle eccezioni nel pacchetto stesso (o il pacchetto sub) menzionato nel file web.xml

1

Oltre alla risposta @ di percezione, la parte mancante è che le eccezioni vengono ingerite e non segnalati.Dovresti passare un ascoltatore di convalida:

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); 
    }); 
} 

Basta rilasciare questo codice nel bean JAXB e tutto il tuo set.