2015-09-27 28 views
6

Sto cercando di ottenere il risultato di una query Eloquent e di produrre i risultati come risposta JSON. La mia applicazione utilizza Slim e Twig per generare risposte HTML, tuttavia non sono sicuro se dovrei utilizzare Twig per generare anche JSON.È appropriato utilizzare Twig per generare risposte JSON pure?

So che posso utilizzare la funzione nativa di PHP echo json_encode(...), ma ciò crea una potenziale vulnerabilità XSS se il mio database contiene entità HTML. Si suppone che Twig sia incaricato di evadere la mia uscita in modo appropriato.

Sono a conoscenza di this question, tuttavia non sembra fornire una risposta pertinente. Sono anche consapevole del filtro json_encode, ma quando faccio questo:

/api/users-json.twig

{ 
    "rows" : {{rows | json_encode}} 
} 

/API/utenti regolatore:

// Simulate database query results 
$result = [ 
    "rows" => [ 
     [ 
      "user_name" => "alex", 
      "message" => "grawr!"  
     ], 
     [ 
      "user_name" => "h4xx0r", 
      "message" => "<script>alert('hello, I can execute JS on your website!');</script>"  
     ]     
    ] 
]; 

$app->response->headers->set('Content-Type', 'application/json; charset=utf-8'); 
$app->render("api/users-json.twig", $result); 

La risposta è la seguente:

{ 
    "rows" : [{&quot;user_name&quot;:&quot;alex&quot;,&quot;message&quot;:&quot;grawr!&quot;},{&quot;user_name&quot;:&quot;h4xx0r&quot;,&quot;message&quot;:&quot;&lt;script&gt;alert(&#039;hello, I can execute JS on your website!&#039;);&lt;\/script&gt;&quot;}] 
} 

Quale non è interpretabile lato client senza ulteriori elaborazioni. Secondo il mio browser, il tipo di contenuto è impostato correttamente su application/json.

posso, ovviamente, fare: /api/users-json.twig

{ 
    "rows" : {{rows | json_encode | raw}} 
} 

che mi dà la risposta:

{ 
    "rows" : [{"user_name":"alex","message":"grawr!"},{"user_name":"h4xx0r","message":"<script>alert('hello, I can execute JS on your website!');<\/script>"}] 
} 

Ma se dovessi rendere h4xx0r di messaggio nel codice lato client, sono aperto a un attacco XSS.

L'output che credo sarebbe "corretto" sarebbe:

{ 
    "rows" : [{"user_name":"alex","message":"grawr!"},{"user_name":"h4xx0r","message":"&lt;script&gt;alert(&#039;hello, I can execute JS on your website!&#039;);&lt;\/script&gt;"}] 
} 

nota che "messaggio" di h4xx0r ora è sfuggito, ma la struttura della risposta nel suo complesso è conservato come JSON valido.

È possibile, naturalmente, eseguire il ciclo di ogni riga e manualmente htmlspecialchars ogni valore, quindi echo json_encode oppure passarlo a Twig. Ma sembra che dovrebbe essere la responsabilità di Twig!

Edit: Sembrerebbe che PHP di filter_var_array, combinata con json_encode, è una ragionevole alternativa all'utilizzo di Twig:

$app->response->headers->set('Content-Type', 'application/json; charset=utf-8'); 
echo json_encode(filter_var_array($result, FILTER_SANITIZE_SPECIAL_CHARS)); 

produce:

{"rows":[{"user_name":"alex","message":"grawr!"},{"user_name":"h4xx0r","message":"&#60;script&#62;alert(&#39;hello, I can execute JS on your website!&#39;);&#60;\/script&#62;"}]} 

ma non sono ancora sicuro se questo è qualcosa che "dovrebbe" essere fatto con Twig.

C'è un modo per farlo con Slim e Twig? Oppure, sono sulla strada sbagliata e dovrebbe essere la responsabilità del mio codice lato client (JS) per uscire correttamente dal contenuto prima del rendering?

+0

Non credo che prevenire XSS atrack sia responsabilità di Twig. Per impedirlo, devi filtrare il tuo input, non l'output. –

+0

@gustavo Questo non è corretto. Certo, dovresti sempre ** filtrare ** i tuoi input quando possibile, ma ** l'escaping ** è qualcosa che dovrebbe essere fatto in uscita. L'input di escape è un [antipattern] (http://security.stackexchange.com/a/42521/74909). – alexw

+0

Uhh, stai chiedendo retoricamente? – alexw

risposta

0

Twig esegue il rendering di qualsiasi variabile data come codificata in html. Tuttavia, siccome vuoi che json codifichi il risultato, hai bisogno di scorrere i dati da solo mentre Twig non approfondisce l'array per te.