domingo, 7 de julio de 2013

Funciones de Encriptacion en PHP



Encriptación en PHP

Para proteger la información de tus aplicaciones, muchas veces es necesario encriptar la información. Existen muchos algoritmos disponibles de encriptación y si quieres puedes crear uno propio, el único problema es que es bastante dificil crear un algoritmo de encriptación que sea seguro.


¿Que es encriptación?


En pocas palabras, encriptación es el mecanismo mediante el cual transformo una cadena en otra. Por ejemplo, si tengo la cadena "Copstone" al encriptarla podría producir un valor como "3SOg2XbS5Jk=" que obviamente es completamente diferente a la original. De esta forma, si alguien llegara a obtener la cadena encriptada "3SOg2XbS5Jk=" no sabría que significa "Copstone" y así puedo decir que mi información está segura.

La mayoría de métodos de encriptación utilizan una cadena secreta que permite proteger aún más la información. Esta cadena secreta se utiliza para generar la cadena encriptada de esta forma podemos obtener para una misma cadena diferentes valores encriptados:

 

Ten en cuenta, que mientras más segura la clave secreta más segura será la clave. Es por esta razón que se recomienda utilizar claves secretas complicadas como por ejemplo: jas%23jhqd#”!$qdjas8123 3!”asdhsoias/(_d%$3.

Importante!! La clave secreta es lo que le da seguridad a tu encriptación así que la clave secreta debes protegerla a toda costa. Nunca se la des a nadie, guardala en un lugar seguro, no la mandes por la red ni por correo. Por ejemplo, lo más absurdo sería hacer una petición web en la que mando una cadena encriptada y la clave secreta para que se pueda desencriptar al otro lado. La clave secreta no debería viajar por la web, deberías entregar la clave secreta de forma personal o por teléfono o algún medio que no deje una huella que alguien más pueda capturar.


Existen dos tipos de encriptación: Encriptación de dos sentidos y encriptación de un sentido.

Encriptación de dos sentidos


La encriptación de dos sentidos, es un tipo de encriptación en el que se puede encriptar y desencriptar una cadena. Es decir, una cadena como "Copstone" se puede convertir en "2IYa0gFAiGI=" si utilizamos la clave secreta "casa" y también se puede realizar el proceso inverso, es decir si tenemos la cadena "2IYa0gFAiGI=" y la palabra secreta "casa" podemos obtener la palabra "Copstone".

Esta forma de encriptación, a pesar de ser bastante segura, sigue siendo vulnerable debido a que siempre existe una forma de regresar a la cadena original. Me explico:

Supongamos que en tu servidor guardas las contraseñas de tus usuarios. Como eres precavido, las claves las guardas encriptadas. Además en tu servidor en un lugar seguro tienes escrita tu clave secreta. Ahora supongamos que alguien se mete a tu servidor y obtiene estos dos datos: la contraseña encriptada "2IYa0gFAiGI=" y la clave secreta "casa". Con estos dos datos se puede saber que la contraseña es "Copstone", lo único que hay que hacer es adivinar el algoritmo utilizado para encriptar (en realidad hay varios pero no tantos como para que esto sea dificil).
  


Encriptación de un sentido

La encriptación de un sentido o encriptación asimétrica, es un tipo de encriptación en el que solo se puede encriptar una cadena y el proceso inverso es casi imposible. Es decir, una cadena como "Copstone" se puede convertir en "6298ed5652f7dff6fd72af530f036f31" usando "casa" como clave secreta y no hay forma de regresar a la cadena original.

Esta forma de encriptación es la mas segura por el mismo hecho de que no se puede regresar a la cadena original. Me explico:

Supongamos que en tu servidor guardas las contraseñas de tus usuarios. Como eres precavido, las claves las guardas encriptadas. Además en tu servidor en un lugar seguro tienes escrita tu clave secreta. Ahora supongamos que alguien se mete a tu servidor y obtiene estos dos datos: la contraseña encriptada "6298ed5652f7dff6fd72af530f036f31" y la clave secreta "casa". Como no hay forma de regresar a la cadena original utilizando estos dos valores, es practicamente imposible que se obtenga la contraseña. La única forma de adivinar la clave sería probar una cadena que al aplicarle el algoritmo de encriptación con la palabra secreta "casa" se obtenga la contraseña encriptada. Como te puedes dar cuenta esto es casi lo mismo que adivinar la clave desde cero.

La pregunta es: ¿Si no puedo regresar a la cadena original como sabes el valo de la cadena original? La respuesta es sencilla. No puedes saberlo.

La idea de este tipo de encriptación es comparar las dos claves encriptadas para ser iguales. Por ejemplo, si una persona tiene la palabra "Copstone" que al aplicarle la encriptación con la palabra "casa" obtiene el valor "6298ed5652f7dff6fd72af530f036f31", lo que tenemos que hacer es obtener la palabra "Copstone" y encriptarla usando la palabra "casa" y comparar este resultado con el valor recibido.

Combinando ambas

En realidad, la mejor seguridad se obtiene de la combinación de ambas encriptaciones pero dependiendo de la sensibilidad de la información que manejes debes escoger si utilizas una o la otra o tal vez ambas.

Si quieres combinar ambas puedes realizar la combinación que desees. Por ejemplo podrías aplicar primero la de un sentido y luego la de dos sentidos o al revés. También podrías emplear la de un sentido para la clave secreta o para ambas. En realidad las podrías combinar como quieras.

Implementación

Ahora que ya sabes de que trata la encriptación te voy a mostrar como puedes implementarla en PHP.


Encriptación de dos sentidos

Existen muchos algoritmos para encriptar de dos sentidos, y una gran variedad de librerías para hacerlo. Sin embargo, la más fácil de utilizar y más común es la librería MCrypt. Para poder utilizar esta librería tienes que asegurarte de que esté instalada junto con tu instalación de PHP. La forma más simple de saber si está instalada es simplemente colocando el código y si no aparece ningún error entonces tu instalación cuenta con MCrypt. Otra forma de saber si está instalada es crear una página web con el siguiente contenido:

1
<?php phpinfo(); ?>
  
Cuando cargues esta página, si mcrypt está instalado, deberías encontrar en algún lado de la página algo como esto:


Si usaste el instalador de PHP para Windows, lo más probable es de que esté instalada, si no lo está puedes conseguir la DLL libmcrypt.dll  en http://files.edin.dk/php/win32/mcrypt/. Simplemente copia esta DLL en la carpeta ext de tu instalación de php y en alguna de las rutas que estén dentro de tu PATH y listo. Para mayor información de como instalar visita http://www.php.net/manual/en/book.mcrypt.php.

Si trabajas con Ubuntu, probablemente necesites instalarla. Para instalarla basta con ejecutar el comando sudo apt-get install php5-mcrypt en un terminal y luego reiniciar tu servidor apache con el comando sudo /etc/init.d/apache2 restart.

Voy a implementar dos funciones que me permiten encriptar y desencriptar cadenas. Ambas funciones reciben la cadena que se quiere encriptar o desencriptar y la clave secreta a utilizar. Estas funciones devuelven la cadena encriptada o desencriptada.


Para encriptar utilizaremos la función mcrypt_encrypt y para desencriptar la función mcrypt_decrypt. Ambas funciones reciben los siguiente parámetros:
 
 




El problema con el texto encriptado es que tiene muchos caracteres raros, inclusive podría ser que tenga caracteres que, al no tener una representación visual, no se estén mostrando. También podría ser que tenga espacios en blanco al inicio o al final. Debido a todas estas razones, no es posible almacenar este valor de forma correcta en una base de datos o inclusive pasarlo por un web service sin que exista la posibilidad de que se pierda un pedazo de esta cadena.

Es por esta razón que recomiendo convertir la cadena encriptada en base 64 para que solo esté compuesta por caracteres con representación visual. Para convertir a base 64 usaremos base64_encode y base64_decode. El código quedaría algo así:




Como puedes ver, ahora la cadena es un poco más larga pero completamente legible. Este es el valor que deberías pasar por la red o almacenar en una base de datos.

Importante!! En este ejemplo uso como clave secreta la palabra "casa" pero deberías usar una cadena bastante más larga y que combine caracteres con números y signos así como mayúsculas y minúsculas para hacerlo más seguro. Podrías usar algo como esto: p&(oa@)+=uaq*23711!@#12psd@#239. Asegúrate de que la cadena no sea muy larga o el algoritmo no funcionará.

Encriptación de un sentido

Ahora que ya hemos visto como realizar la encriptación de dos sentidos te voy a mostrar como realizar la de un solo sentido.
Para encriptar en un solo sentido no necesitas instalar nada ya que PHP a partir de su versión 5.0 viene incluido con esta funcionalidad.
Para encriptar en un solo sentido podemos utilizar la función hash_hmac que recibe los siguientes parámetros:
 

Encriptando en otros lenguajes
En teoría, si utilizas un algoritmo estándar como por ejemplo Rijndael o md5, no importa el lenguaje que utilices para encriptar la información ya que todos deberían producir el mismo resultado si utilizas la misma clave y el mismo vector de inicialización.
 
Manejo de sesiones en PHP
Las sesiones en PHP son una forma de mantener ciertos datos de un visitante entre los diversos accesos una web. De esta forma se pueden crear aplicaciones donde se le muestra al usuarios datos personalizados de acuerdo a las preferencias o acciones del usuario. 

Las sesiones se manejan internamente por un identificador llamado SID (Session ID) el cual esta asociado a una única sesión y que ayuda a identificar el contenido de la sesión actual. Esta variable se propaga automaticamente a traves de Cookies o mediante URL.


Manejo de sesiones en PHP

Todas la variables de sesión son accesibles mediante arrays en la variable global $_SESSION. Adicionalmente ofrece una serie de funciones que permiten manejar detalladamente las sesiones de manera sencilla:


·         session_start inicializa una sesión y crea el identificador de sesión.
·         session_id devuelve el identificador de la sesión actual.
·         session_regenerate_id genera un nuevo identificador para la sesión actual.
·         session_unset limpia todas las variables de sesión registradas.
·         session_destroy elimina todas las variables de sesión registradas.


Crear variables de Sesión

Si deseamos crear variables de sesión para que se puedan utilizar a través de diferentes páginas inicializamos el manejo de sesiones con al función session_start y luego guardamos el dato deseado como variable de sesión utilizando la variable global $_SESSION.