2015-08-10 8 views
9

Sto lavorando a un progetto che ha host e client e dove gli host possono inviare comandi ai client (tramite socket).Quali problemi di sicurezza derivano dal chiamare i metodi con la riflessione?

Sono determinato che l'utilizzo di JSON per comunicare le opere migliori.

Ad esempio:

{ 
    "method" : "toasty", 
    "params" : ["hello world", true] 
} 

In questo esempio, quando questa stringa JSON viene inviato al client, verrà elaborato e un metodo appropriato all'interno del client verrà eseguito come tale:

public abstract class ClientProcessor { 

    public abstract void toasty(String s, boolean bool); 
    public abstract void shutdown(int timer); 

    private Method[] methods = getClass().getDeclaredMethods(); 

    public void process(String data) { 
     try { 
      JSONObject json = new JSONObject(data); 
      String methodName = (String) json.get("method"); 

      if (methodName.equals("process")) 
       return; 

      for (int i = 0; i < methods.length; i++) 
       if (methods[i].getName().equals(methodName)) { 
        JSONArray arr = json.getJSONArray("params"); 

        int length = arr.length(); 
        Object[] args = new Object[length]; 
        for (int i2 = 0; i2 < length; i2++) 
         args[i2] = arr.get(i2); 

        methods[i].invoke(this, args); 
        return; 
       } 
     } catch (Exception e) {} 
    } 
} 

E utilizzando il ClientProcessor:

public class Client extends ClientProcessor { 
    @Override 
    public void toasty(String s, boolean bool) { 
     //make toast here 
    } 

    @Override 
    public void shutdown(int timer) { 
     //shutdown system within timer 
    } 

    public void processJSON(String json) { 
     process(json); 
    } 
} 

il JSON viene inviato dal server al client , ma il server potrebbe essere modificato per inviare JSON diversi.

Le mie domande sono:

  • È questo un modo sicuro di eseguire metodi di elaborazione JSON?
  • C'è un modo migliore per farlo? Sto pensando che l'uso della riflessione sia terribilmente lento.

risposta

4

C'è un 100 e 1 modi è possibile elaborare un messaggio JSON in modo che si verifica qualche elaborazione, ma saranno tutti si riducono a:

  • messaggio parse
  • mappa messaggio a metodo
  • metodo Invoke
  • comportamento di invio

Sebbene sia possibile utilizzare una chiamata riflessa (in termini di prestazioni sarebbe buona per la maggior parte dei casi) invocare un metodo, che, imho, sarebbe un po 'troppo aperto: un client dannoso potrebbe, ad esempio, danneggiare il sistema emettendo le chiamate wait.

Reflection ti apre anche a dover mappare correttamente i parametri, che è più complicato del codice che hai mostrato nella tua domanda.

Quindi non utilizzare Reflection.

Vuoi che si potrebbe fare è definire un semplice interface, le implementazioni dei quali sarebbe capire come elaborare i parametri ed avere il processore (più comunemente nota come controller) invocare che, qualcosa di simile:

public interface ServiceCall 
{ 
    public JsonObject invoke(JsonArray params) throws ServiceCallException; 
} 

public class ServiceProcessor 
{ 
    private static final Map<String, ServiceCall> SERVICE_CALLS = new HashMap<>(); 

    static 
    { 
    SERVICE_CALLS.put("toasty", new ToastCall()); 
    } 

    public String process(String messageStr) 
    { 
    try 
    { 
     JsonObject message = Json.createReader(new StringReader(messageStr)).readObject(); 

     if (message.containsKey("method")) 
     { 
     String method = message.getString("method"); 

     ServiceCall serviceCall = SERVICE_CALLS.get(method); 

     if (serviceCall != null) 
     { 
      return serviceCall.invoke(message.getJsonArray("params")).toString(); 
     } 
     else 
     { 
      return fail("Unknown method: " + method); 
     } 
     } 
     else 
     { 
     return fail("Invalid message: no method specified"); 
     } 
    } 
    catch (Exception e) 
    { 
     return fail(e.message); 
    } 
    } 

    private String fail(String message) 
    { 
    return Json.createObjectBuilder() 
     .add("status", "failed") 
     .add("message", message) 
     .build() 
     .toString(); 
    }  

    private static class ToastCall implements ServiceCall 
    { 
    public JsonObject invoke(JsonArray params) throws ServiceCallException 
    { 
     //make toast here 
    } 
    } 
} 
+0

Combina questo approccio con la generazione del codice e otterrai una soluzione rapida, sicura e conveniente (+1) –

+0

@DmitryZaitsev yeah, ci sono alcune API che posso pensare (Spring e J2EE) che essenzialmente fanno ciò che ho mostrato (normalmente con annotazioni in questi giorni), quale sarebbe la mia scelta piuttosto che rotolare il mio –

+0

Stai parlando di 'Object.wait()'? Sto usando '.getDeclaredMethods();' che restituirà solo 'toasty',' shutdown' e 'process'. Nel metodo 'process', ignoro le richieste di metodo da elaborare (per evitare uno stackoverflow). Preferisco di gran lunga la tua idea. –

-3

Credo che si sta tentando di convertire la stringa JSON per oggetto Java e viceversa ... se questo è il requisito allora questo non sarebbe l'approccio giusto ...

provare qualsiasi API open source come Gson ... è l'API di Google per conversare da Java a JSON e viceversa.

Si prega di verificare ... https://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/gson/Gson.html

fatemi sapere se avete ulteriori domande ...

+0

Ho dato una buona occhiata alla serializzazione, ma questo richiede ancora che io usi la reflection per chiamare l'oggetto analizzato. –

+0

ciò che si sta cercando di fare nel processo di metodo() .. non vedo alcuna necessità di utilizzare riflessione qui ... –

+0

Sono fiducioso per un metodo senza riflessione, quindi si prega di suggerire uno se avete idee. Ricorda che 'process()' sta prendendo in un JSON, e da quello, ha bisogno di eseguire un metodo. –

0

nomi dei metodi Mappa a int costanti e basta passare (caso) su queste costanti per richiamare il metodo appropriato .

"toasty" : 1 
"shutdown": 2 

switch() 
case 1: toasty() 
case 2: shutdown() 
+0

Anche il mio primo pensiero, ma che dire degli argomenti/parametri? Avrò bisogno di scriverli manualmente (controllando la firma del metodo per sapere quali tipi di cast in). E controllando la firma del metodo, sto usando la riflessione ancora una volta. –

+0

Penso che Enum potrebbe essere usato, potresti esplorare in quella linea. Ti farò sapere se sono in grado di capire come farlo. – Roshith

Problemi correlati