Tech Blog

Injection - come prevenire con Liferay

Un viaggio all'interno delle vulnerabilità, e come sanarle

Simone Cinti
Software Architect
5 minuti di lettura
liferay, security, xss, sql, injection, attack e vulnerability
Questo articolo è disponibile anche in English 🇬🇧

Un attacco di tipo Injection consiste nell'invio di codice o comandi malevoli che possono essere poi interpretati ed eseguiti dall'applicazione.

L'attacco di tipo Injection è attualmente primo nella classifica OWASP Top Ten, ed è composto da diverse categorie a seconda del linguaggio o del tipo di comando.

Taken together, injection attacks are a huge percentage of the serious application security risk. Many organizations have poorly thought through security controls in place to prevent injection attacks. OWASP, about the injection attacks

In questo articolo focalizzeremo la nostra attenzione su due particolari tipologie di Injection:

  • SQL Injection (SQLi) – quando avviene una injection di query o comandi SQL
  • Cross-Site Scripting (XSS) – quando avviene una injection di script interpretabili dal browser

mostrando come le soluzioni offerte dal Portale Liferay possono aiutarti nel prevenire gli attacchi di tipo injection, tenendo alto il livello di sicurezza.

Liferay Portal Security

Liferay segue le OWASP Top 10 e le CWE/SANS Top 25 per garantire il più alto livello di protezione possibile contro diversi tipi di attacchi.

Di seguito alcune tipologie di attacchi inclusi in entrambe le OWASP Top Ten e le CWE/SANS Top 25 e contro i quali Liferay ti garantisce il più alto livello di protezione possibile:

Liferay si prende cura della sicurezza del portale, sia nelle edizioni community (CE) che nelle edizioni enterprise (DXP), mantenendo sempre aggiornati gli elenchi delle vulnerabilità note, ed il proprio security statement.

SQL Injection (SQLi)

SQL Injection consiste nell'invio di comandi (o query) SQL sfruttando la mancata validazione degli input dell'utente lato client.

A seconda dei privilegi dell'utente sul database preso di mira, l'attaccante potrebbe effettuare:

  • insert, update o delete di righe su tabelle già esistenti
  • ottenere dati sensibili dalle tabelle (comando select)
  • drop delle tabelle
  • eseguire comandi di amministrazione, come ad esempio lo shutdown del database ottenendo così un attacco di tipo DoS

Uno dei benefici nell'utilizzo di Liferay è nel fatto che il livello di persistenza generato dal Service Builder è ideato in modo tale da prevenire attacchi di tipo SQL Injection (maggiori dettagli).

Quando la soluzione offerta dal Service Builder non dovesse essere sufficiente, Liferay ti aiuta a mantenere alto il livello di sicurezza contro gli attacchi di tipo SQL Injection anche nella definizione dei Custom Finder. Tuttavia, occorre prestare attenzione nell'implementazione dei custom Finder e seguire le istruzioni fornite dalla documentazione ufficiale di Liferay.

In particolare:

  • ogni query personalizzata deve essere contenuta nell'element <custom-sql> all'interno di custom-sql/default.xml e la query sql deve essere inclusa in un <![CDATA[...]]>, e non deve mai terminare con il punto-e-virgola;

  • i parametri delle query devono essere aggiunti utilizzando QueryPos che effettua sempre output escaping. La validazione dei parametri da sorgenti non affidabili è obbligatoria così come per i nomi delle colonne della clausola order-by provenienti dalla request.

La validazione dei dati provienienti dai parametri della request HTTP è la chiave per prevenire gli attacchi di tipo SQL injection.

Nell'esempio seguente mostreremo per quale motivo i nomi delle colonne nelle clausole order-by non devono mai provenire direttamente dalla request senza essere prima validati, e come un attacco di tipo injection nelle clausole order-by può ridurre in modo significativo il numero totale dei tentativi necessari a scoprire il valore di una determinata colonna.

Supponiamo di aver esteso il model aggiungendo una nuova entità Vendor, introducendo una vulnerabilità nell'implementazione del finder:

sql = StringUtil.replace(sql, "[$ORDER_BY$]",	" ORDER BY " + orderBy);  // unsafe

la versione sicura prevede l'utilizzo di BasePersistenceImpl.appendOrderByComparator():

StringBundler sb = new StringBundler();
if (orderByComparator != null) {
  appendOrderByComparator(sb, "Vendor.", orderByComparator);
}
sql = StringUtil.replace(sql,
	"[$ORDER_BY$]", sb.toString());

con questa vulnerabilità, ad esempio, l'attaccante potrebbe sfruttare il parametro orderByCol del SearchContainer sulla pagina di ricerca dei vendors, per iniettare il seguente comando sql tramite la submit della form:

_portletName_INSTANCE_instanceId_orderByCol=

(CASE WHEN (
    SELECT substring(CONVERT(userId, CHAR),1,1)
    FROM user_
    WHERE emailAddress = 'test@liferay.com'
  ) = '2'
THEN name ELSE vendorId END)

In questo modo, l'attaccante può scoprire l'i-esima cifra dello userId avente test@liferay.com come indirizzo e-mail, semplicemente verificando il tipo di ordinamento nella pagina dei risultati. Ogni tentativo di injection modificherà l'ordine dei risultati, a seconda se l'attaccante ha indovinato o meno la cifra corrispondente. Supponendo di avere degli userId composti da 5 cifre decimali, l'attaccante può riuscire facilmente ad indovinare lo userId in (5 * 9) - 1 = 44 tentativi nel caso peggiore, mentre un attacco a forza bruta potrebbe richiedere 9 * 10^4 tentativi. Lo stesso tipo di attacco può anche essere utilizzato per indovinare lo screen-name o la password dell'utente, anche se richiederebbe un numero assai maggiore di tentativi.

Consigli utili per proteggerti dagli attacchi di tipo SQL Injection

  • Il ServiceBuilder di Liferay ti aiuta a tenere alto il livello di sicurezza, ma occorre prestare attenzione nell'implementazione dei Custom Finder: utilizzare sempre OrderByComparator ed effettuare la validazione dei nomi delle colonne nella clausole order-by.

  • Tieni a mente che la vulnerabilità agli attacchi di tipo SQL Injection è principamente un problema di validazione dell'input: al fine di prevenire questi attacchi evitare la concatezione di stringhe, specialmente se provenienti da sorgenti non affidabili come la HTTP request, senza alcun tipo di validazione preventiva.

  • Utilizzare i parametri delle query il più possibile, in quanto l'output escaping neutralizza l'injection.

Cross-Site Scripting (XSS)

Cross-site scripting (XSS) è conosciuto anche come “Improper neutralization of input during web page generation” ed èuno degli attacchi più comuni in accordo alle OWASP Top 10 ed alle CWE/SANS Top 25.

Secondo una recente riclassificazione a cura di OWASP, gli attacchi XSS possono essere suddivisi in due principali categorie:

  • Server XSS: quando dati non affidabili in input dall'utente vengono restituiti nella risposta del server

  • Client XSS: quando dati non affidabili in input dall'utente vengono inclusi nel DOM o interpretati dal browser mediante funzioni JavaScript vulnerabili

Un'altra classificazione possibile degli attacchi XSS è relativa alla persistenza:

  • Stored (Persistent or Type-I): quando dati non affidabili in input dall'utente vengono resi persistenti nel sistema di archiviazione del server, come ad esempio il database

  • Reflected (Non-Persistent or Type-II): quando dati non affidabili in input dall'utente vengono restituiti nella risposta del server senza essere memorizzati in modo permanente

Tipologie di XSS
Tipologie di XSS

Liferay Portal è costruito per prevenire attacchi di tipo XSS

Quando sviluppi una nuova portlet dovresti sempre utilizzare le taglib di frontend Liferay. Gli elementi delle taglib (come ad esempio <aui: >, <liferay-ui: >, <clay: > ) sono sicuri in quanto effettuano sempre output escaping quando necessario nel modo corretto, quindi neutralizzeranno ogni tipologia di attacco XSS.

Utilizzare HtmlUtil di Liferay è la via più sicura per effettuare output escaping.

Ora mostriamo qualche esempio di attacco Server XSS...

Attacco Reflected Server XSS - esempio

  1. 💻 CLIENT: l'attaccante include il codice malevolo tramite i parametri o il body della request HTTP
firstName=<script>alert('XSS!')</script>
  1. 🌍 SERVER: la response generata dinamicamente può includere dei dati non affidabili (nella pagina jsp non si effettua output escaping HTML):
<p> Hello, <%= firstName %> </p>
  1. 💻 CLIENT: il browser mostra la pagina di risposta ottenuta dal server, eseguendo codice malevolo
<p>
  Hello,
  <script>
    alert("XSS!");
  </script>
</p>

Stored Server XSS Attack - example

  1. 💻 CLIENT: l'attaccante include il codice malevolo tramite i parametri o il body della request HTTP
firstName=';alert(document.cookie);'
  1. 🌍 SERVER: l'entità del model è aggiornata nello strato di persistenza senza alcuna validazione, e può contenere dei dati non affidabili:
...
customer.setFirstName(firstName);
_customerService.updateCustomer(customer);
  1. 🌍 SERVER: la response generata dinamicamente include dei dati non affidabili provenienti dallo strato di persistenza, espondendo l'applicazione ad una vulnerabilità XSS in quanto non viene effettuato output escaping JS:
<aui:script>
 var firstName = '<%= c.getFirstName() %>';
...
</aui:script>
  1. 💻 CLIENT: il browser mostra la pagina di risposta ottenuta dal server eseguendo il codice malevolo, che è anche salvato nello strato di persistenza, anche dopo aver effettuato il refresh della pagina.
<script>
 var firstName = '';alert(document.cookie);'';
...
<script>

Gli attacchi di tipo XSS possono essere neutralizzati effettuando output escaping:

  • ogni volta che, nella generazione dinamica delle pagine, imposti il valore di un attributo o un contenuto in un elemento HTML la cui provenienza non è verificata nè affidabile (esempio parametri della request HTTP);

  • quando nelle pagine jsp si utilizza l'output diretto del contenuto delle variabili Java <%= ... %> all'interno degli <script>;

  • quando si realizzano delle taglib personalizzate.

Ecco alcuni esempi di utilizzo corretto di HtmlUtil:

<p> Hello, <%= HtmlUtil.escape(firstName) %> </p>
<div title="<%= HtmlUtil.escapeAttribute(title) %>">...</div>
<a href="<%= HtmlUtil.escapeHREF(detailsURL) %>">...</a>
<aui:script>
 var firstName = '<%= HtmlUtil.escapeJS(c.getFirstName())%>';
...
</aui:script>

Consigli utili per proteggersi dagli attacchi di tipo XSS

  • i dati provenienti da fonti non affidabili devono essere validati e sanitizzati prima di essere persistiti o processati per la risposta in output. Enum o costanti possono essere utilizzati per effettuare eventuali mapping per valori di tipo stringa;

  • utilizzare le taglib di frontend Liferay, e HtmlUtil per l'output escaping. L'escaping dell'output in fase di generazione dinamica della risposta neutralizzerà l'injection così come l'eventuale presenza di <script> o codice JavaScript malevolo, evitando che possano essere eseguiti dal browser;

  • fare attenzione al codice JavaScript personalizzato che interviene direttamente sul DOM. Codice JavaScript non sicuro può rivelarsi vulnerabile agli attacchi di tipo Client XSS.

Conclusione

L'Injection è uno degli attacchi più diffusi nelle applicazioni web. Le strategie di difesa contro questa tipologia di attacchi consistono nella:

  • prevenzione mediante validazione dei dati provenienti da sorgenti non affidabili prima che questi possano essere persistiti o processati per la risposta in output;

  • neutralizzazione tramite escaping o sanitizzazione dell'output.

Liferay garantisce il più alto livello di sicurezza possibile sia nelle versioni community (CE) che nelle versioni enterprise (DXP), ed aiuta lo sviluppatore nel tenere alto il livello di sicurezza anche nello sviluppo di nuove componenti.

scritto da
Simone Cinti
Software Architect
Software Architect in SMC, si occupa della progettazione e sviluppo di soluzioni basate su Liferay Portal.

Potrebbero interessarti anche…