Injecció SQL

De Viquipèdia
Dreceres ràpides: navegació, cerca

Injecció SQL és un mètode d'infiltració de codi intrús que utilitza un error del programari present en una aplicació en el nivell de validació de les entrades per a poder realitzar consultes a una base de dades.[1]

L'origen de la vulnerabilitat radica en la incorrecta comprovació i/o filtrat de les variables utilitzades en un programa que conté, o bé genera, codi SQL. És, de fet, un error d'una classe més general de vulnerabilitats que pot ocórrer en qualsevol llenguatge de programació o script que estigui incrustat dintre d'un altre.

Es coneix com a Injecció SQL al tipus de vulnerabilitat, al mètode d'infiltració, al fet d'incrustar codi SQL intrús a la porció de codi incrustat.

Descripció[modifica | modifica el codi]

Es diu que existeix o s'ha produït una injecció SQL quan, d'alguna manera, s'insereix o "injecta" codi SQL invasor dins del codi SQL programat per a alterar el funcionament normal del programa i fer que s'executi la porció de codi "invasor" incrustat, en la base de dades.[2]

Aquest tipus d'intrusió normalment és de caràcter maliciós, nociu o espia, per tant és un problema de seguretat informàtica, i ha de pensar pel programador de l'aplicació per a poder-lo prevenir. Un programa elaborat amb oblit, displicència o amb ignorància d'aquest procediment, pot resultar vulnerable, i la seguretat del sistema (base de dades) pot quedar eventualment compromesa.

La intrusió té lloc durant l'execució del programa vulnerable, ja sigui, en computadores d'escriptori o bé en llocs Web, en aquest últim cas òbviament executant-se en el servidor que els conté.

La vulnerabilitat es pot produir automàticament quan un programa "arma descuidadament" una sentència SQL en temps de execució, o bé durant la fase de desenvolupament, quan el programador explicita la sentència SQL a executar en forma desprotegida. En qualsevol cas, sempre que el programador necessiti i faci ús de paràmetres a ingressar per part de l'usuari, a efectes de consultar una base de dades, ja que, justament, dins dels paràmetres és on es pot incorporar el codi SQL intrús.

En executar-se la consulta en la base de dades, el codi SQL injectat també s'executarà i podria fer moltes coses, com inserir registres, modificar o eliminar dades, autoritzar accessos i, fins i tot, executar un altre tipus de codi maliciós a la computadora.[3]

Per exemple, assumint que el següent codi està en una aplicació web i que existeix un paràmetre "nomUsuari" que conté el nom de l'usuari a consultar, una injecció SQL es podria provocar de la següent manera:[4]

El codi SQL original i vulnerable és:

consulta := "SELECT * FROM usuaris WHERE nom = '" + nomUsuari + "';"

Si l'operador escriu un nom, per exemple "Alícia", res anormal passarà, l'aplicació generaria una sentència SQL similar a la següent, que és perfectament correcta, on se seleccionarien tots els registres amb el nom "Alícia" en la base de dades:

SELECT * FROM usuaris WHERE nom = 'Alícia';

Però si un operador malintencionat escriu com nom d'usuari a consultar:

"Alícia'; DROP TABLE usuaris; SELECT * FROM dades WHERE nom LIKE '%"

(sense les cometes), es generaria la següent consulta SQL, (el color verd és el que vol el programador, el blau és la dada, i el vermell, el codi SQL injectat):

SELECT * FROM usuaris WHERE nom = 'Alícia';
DROP TABLE usuaris;
SELECT * FROM dades WHERE nom LIKE '%';

En la base de dades s'executaria la consulta en l'ordre donat, se seleccionarien tots els registres amb el nom 'Alícia', s'esborraria la taula 'usuaris' i finalment se seleccionaria tota la taula "dades", que no hauria d'estar disponible per als usuaris web comuns.

En resum, qualsevol dada de la base de dades pot ser tret disponible per a ser llegit o modificat per un usuari malintencionat.

Cal notar per què es diu "Injecció" SQL. Si s'observa el codi maliciós, de color vermell, es notarà que està inserit en mig del codi bo, el verd. Així, el codi vermell ha sigut "injectat" dins del verd.

La injecció SQL és fàcil d'evitar, per part del programador, en la majoria dels llenguatges de programació que permeten desenvolupar aplicacions web. En la següent secció es tracten resumidament aquest tema.

Algunes formes d'evitar la Injecció SQL[modifica | modifica el codi]

Ruby on Rails[modifica | modifica el codi]

En el framework Ruby on Rails (RoR), les consultes són verificades automàticament per qualsevol dels mètodes de cerca inclosos. Per exemple:

 Project.find(:all, :conditions => ["name = ?", params[:name]])
 # o bien
 Project.find(:all, :conditions => {:name => params[:name]})

L'única forma de que un usuari malintencionat pugui utilitzar una injecció de SQL en RoR és que mitjançant el codi es transformi la variable a tipus string i s'utilitzi com argument de la cerca directament. Per exemple:

 # NO S'HAURIA DE FER AIXÒ
 Project.find(:all, :conditions => "name = '#{params[:name]}'")

Perl[modifica | modifica el codi]

En llenguatge Perl DBI, el mètode DBI::quote filtra els caràcters especials (assumint que la variable $sql conté una referència a un objecte DBI):

 $query = $sql->prepare 
   ( 
         "SELECT * FROM usuaris WHERE nom = " 
  . 
         $sql->quote($nom_usuari) 
    );

O també es pot utilitzar la característica placeholder (amb cometes automàtiques) com aquest exemple:

 $query = $sql->prepare("SELECT * FROM usuaris WHERE nom = ?"); 
 $query->execute($nombre_usuari);

PHP[modifica | modifica el codi]

En el llenguatge PHP, hi ha diferents funcions que poden servir d'ajuda per a utilitzar amb diferents sistemes de gestió de bases de dades. Per a MySQL, la funció a utilitzar és mysqli_real_escape_string[5] o mysql_real_escape_string.[6][7] Amb l'extensió mysql es programaria el següent:

 $query_result = mysql_query("SELECT * FROM usuaris WHERE nom = \"". mysql_real_escape_string($nom_usuari). "\"");

I amb l'extensió mysqli es programaria el següent:

 $con = mysqli_connect($host_db, $usuario_db, $clave_db,$nombre_db);
 $query_result = mysqli_query($con, "SELECT * FROM usuaris WHERE nom = \"". mysql_real_escape_string($con, $nom_usuari). "\"");

Java[modifica | modifica el codi]

En llenguatge Java, es pot utilitzar la classe PreparedStatement

En comptes de:

 Connection con = (acquire Connection) 
 Statement stmt = con.createStatement(); 
 ResultSet rset = stmt.executeQuery("SELECT * FROM usuaris WHERE nom = '" + nomUsuari + "';");

es pot utilitzar parametrització o escapament de variables, com s'indica en els següents apartats.

Parametrizació de sentències SQL[modifica | modifica el codi]

 Connection con = (acquire Connection) 
 PreparedStatement pstmt = con.prepareStatement("SELECT * FROM usuaris WHERE nom = ?"); 
 pstmt.setString(1, nomUsuari); 
 ResultSet rset = pstmt.executeQuery();

Escapament de les variables a inserir en la sentència SQL[modifica | modifica el codi]

Escapar el text contingut en la variable reemplaçant els caràcters especials en SQL per el seu equivalent textual, de tal forma que SQL interpreti tot el contingut de la variable como si fos text.

 Connection con = (acquire Connection) 
 Statement stmt = con.createStatement(); 
 ResultSet rset = stmt.executeQuery("SELECT * FROM usuaris WHERE nom = '" + nomUsuari.replace("\\", "\\\\").replace("'", "\\'") + "';");

També es pot utilitzar el métode escapeSQL de la classe StringEscapeUtils procedent de la llibreria de Apache Commons Lang

 Connection con = (acquire Connection) 
 Statement stmt = con.createStatement(); 
 ResultSet rset = stmt.executeQuery("SELECT * FROM usuaris WHERE nom = '" + StringEscapeUtils.escapeSQL(nomUsuari) + "';");

En C#[modifica | modifica el codi]

En el llenguatge C#, de la plataforma .NET (o la seva alternativa lliure Mono), té ADO.NET SqlCommand (per a Microsoft SQL Server) o OracleCommand (per a servidors de bases de dades Oracle). L'exemple següent mostra com prevenir els atacs d'injecció de codi utilitzant l'objecte SqlCommand. El codi per a ADO.NET es programa de manera similar, encara que pot variar lleument segons la implementació específica de cada proveïdor.

En comptes de:

 using( SqlConnection con = (acquire connection) ) { 
     con. Open(); 
     using( SqlCommand cmd = new SqlCommand("SELECT * FROM usuaris WHERE nom = '" + nomUsuari + "'", con) ) { 
        using( SqlDataReader rdr = cmd.ExecuteReader() ){ 
            ... 
        } 
     }       
 }

es podria utilitzar lo següent:

 using( SqlConnection con = (acquire connection) ) { 
     con. Open(); 
     using( SqlCommand cmd = new SqlCommand("SELECT * FROM usuaris WHERE nom = @nomUsuari", con) ) { 
 
        cmd.Parameters.AddWithValue("@nomUsuari", nomUsuari); 
 
        using( SqlDataReader rdr = cmd.ExecuteReader() ){ 
            ... 
        } 
     }       
 }

Vegeu també[modifica | modifica el codi]

Referències[modifica | modifica el codi]

  1. «Injecció de codi SQL» (en castellà). Juan Martínez Llinás, 21 abril 2009. [Consulta: 20 maig 2012].
  2. «Injecció de codi SQL en MS SQL Server 2005» (en castellà). HackTimes, 16/01/2010. [Consulta: 20 maig 2012].
  3. «Què és la Injecció SQL?» (en anglès). Robert Auger. [Consulta: 20 maig 2012].
  4. «Atacs d'injecció SQL Estàs fora de perill?]» (en anglès). Mitchell Harper, 17 Juny 2002. [Consulta: 20 maig 2012].
  5. «Manual PHP: mysqli_real_escape_string» (en anglès). PHP, 6 setembre 2012. [Consulta: 7 setembre 2013].
  6. «Manual PHP: mysql_real_escape_string» (en anglès). PHP, 18 maig 2012. [Consulta: 20 maig 2012].
  7. «Tècniques d'atac en servidors web amb scripts via injecció SQL» (en anglès). memonix@roses-labs.com, 26/01/2007. [Consulta: 20 maig 2012].

Enllaços externs[modifica | modifica el codi]