Comunidad de diseño web y desarrollo en internet online

Certificados de Seguridad y SSL bien explicados

Hoy tuve que ayudar a mi equipo a correr un certificado de seguridad SSL. En esta tarea, me dí cuenta que la información es nula y que solo los valientes lo lograrán. En serio, es putamente vicioso, incluso la info de php.net esta mal.

Lo primero: No te asustes, relajate y lee este artículo. Es fácil, sólo que todo el mundo lo hace ver imposible.

¿Que es un certificado de seguridad?


Cuando transfieres info de un server a otro, ejemplo un gateway de pagos, existen cierto tipo de ataques como el ataque "Hombre en el medio" que emplean las URLs de envío para infectar o robar nuestra información. La información en la web viaja "desnuda" y visible a todo el mundo todo el tiempo. Hay que cifrarla para que solo el servidor y el usuario final lo puedan ver.

Un certificado de seguridad hace imposible este tipo de ataques. Consta de dos pequeñas partes:
  • Certificado en el Servidor de envío
  • Certificado en el otro Servidor de recepción

Este certificado o ".cert" o ".crt" no es más que un archivo cifrado que contiene la clave privada o privatekey.

Entonces tenemos que instalar el certificado en nuestro server (Se supone que el server de recepción nos ha dado el certificado), generalmente es sencillo, otras no. Si son decentes, vienen con un pequeño manual paso a paso y no es demasiado problema hacerlos.

ProTip: Uno de los certificados más conocidos es VeriSign.

Private Key y Public Key


Ok, tenemos el f@!#%ng certificado instalado (Que muchas veces lo instala nuestro Server/Hosting). Pero para usarlo debemos entender cómo lo usaremos.

El certificado tiene como dijimos el privatekey, el cual es una cadena codificada con algún algoritmo. Yo usaré el más famoso, el PKCS#12 con un hash RSA de 1024. No te preocupes si son demasiadas siglas, lee el artículo de la wikipedia o sigue leyendo este.

El tema será leer este certificado para obtener la privatekey. Pero como era de esperarse, usará un password (Para nuestro ejemplo: 1234. NADIE debe poner algo así de idiota, recuerden es seguridad de verdad).

¿Pero que es la Public Key? La public key es el certificado que usaremos para enviar la información encriptada. La private queda en el server, la pública es la que vuela por internet. Bastante obvio si se lo ponen a pensar (Lástima nadie lo explica así en NINGÚN lado).


Por cierto una pequeña diferencia para no asustarse, la private es siempre igual, la public es dinámica y varia en cada inicio de sesión.

Configurar el Servidor


Bien para empezar con algo de coding, tendremos que configurar nuestro server (Si están en un hosting, pidan que hagan esto por ustedes).

cURL


Debemos tener la librería cURL, una librería muy cool que permite enviar HTTP-Headers desde PHP.

Para habilitarla en el server solo hagan en el php.ini lo siguiente:
  • Busquen la línea "extension=php_curl.dll"
  • Quiten el ;( punto y coma) de delante
  • Reinicien el servicio


openSSL


Esta librería, muy poco documentada a mi gusto, es genial para mantener sesiones seguras SSL mediante certificados de seguridad.

Para instalar deben seguir estos pasos:
  • Descarguen OpenSSL
  • Si están en Windows Server seguramente tengan que instalar la libreria del C++
  • Sigan los pasos de instalación desde la descarga
  • Busquen en el php.ini "extension=php_openssl.dll"
  • Quiten el ;( punto y coma) de delante
  • Reinicien el servicio


Cómo usar OpenSSL


Ya podemos empezar con el código PHP. Ahora armaremos nuestro código base que lo que intentaré es abrir el certificado, obtener la privatekey, generar la publickey, encriptar el texto y desencriptarlo.

Lo primero debemos hacer es abrir el certificado como si fuera un archivo más, como un simple .txt sí.

Código :

$file = 'nombre_certificado.p12';
// puede ser .crt o .cert también
$fd = fopen($file, 'r');
$p12buf = fread($fd, filesize($file));
fclose($fd);

Ya tenemos nuestra info, ahora extraeremos la privatekey:

Código :

$p12cert = array();
$pass = "1234";
// En este array almacenaremos la info del privatekey
openssl_pkcs12_read($p12buf, $p12cert, $pass);

La función openssl_pkcs12_read nos permite extraer del buffer de lectura la información pasándole el pass para autentificarlo.

Por cierto, si usan otro tipo de certificado que no sea PKCS#12, tiene varias funciones para extraer la info, básicamente siempre es la misma cosa. En la guía de OpenSSL de PHP.net pueden consultarlas.

Ahora vamos a validar un poco la sentencia, la función nos devuelve un booleano, así que podemos hacer:

Código :

if ( openssl_pkcs12_read($p12buf, $p12cert, $pass) )
{
   //Código Creación PrivateKey
}
else
{
    // Código Error
}

Como habrán notado una de los parámetros es nuestro array vacío, que ahora contiene la info del key. Así que con hacer:

Código :

$p12cert["pkey"];

Tendremos el resultado de nuestro key, que se verá algo así:

Código :

-----BEGIN CERTIFICATE-----PORQUERIA ENCRIPTADA-----END CERTIFICATE-----

Por eso vamos a almacenar el privatekey:

Código :

$privatekey = $p12cert["pkey"];

Vamos a crear el keypair, que es básicamente lo que explique antes, que por cierto, se llama "asymmetric key algorithms".

Código :

$res=openssl_pkey_new();

Ahora que tenemos el key_pair, vamos a generar un string valido para nuestro key:

Código :

openssl_pkey_export($res, $p12cert["pkey"]);

Como verán no tiene mucha ciencia, solo ejecutamos la función empleando el key_pair y validando con nuestra privatekey.

Ahora sí, vamos a obtener nuestro publickey:

Código :

$publickey=openssl_pkey_get_details($res);
$publickey=$publickey["key"];

La primer función openssl_pkey_get_details obtiene la información para nuestra public key (Similar a como hicimos para la private). Y luego la pasamos a una variable desde el array (Por practicidad). Noten como hemos vuelto a invocar al key_pair ($res).

Estamos listos, vamos a crear un texto y a encriptarlo


Código :

$texto_a_convertir = htmlentities('"Hola Mundo & Amo OpenSSL aunque sea malvado");
openssl_public_encrypt($texto_a_convertir, $crypt, $publickey);

¿Nada difícil eh? Esto es porque solo tenemos que emplear una variable de texto primero (Aconsejo usar htmlentities para la misma) y luego emplear la función openssl_public_encrypt, pasando que valor queremos convertir, en que variable almacenar la conversión y con que publickey hacerlo. Todas cosas que ya teníamos.

Ahora desencriptemos la información !

Código :

$PK12=openssl_get_privatekey($p12cert["pkey"]);
openssl_private_decrypt($crypt,$decrypt,$PK12);

Bien en esta vez, primero debemos obtener la privatekey en formato key (La tenemos en String), para eso usaremos openssl_get_privatekey y luego descriptaremos muy similar a como encriptamos con la función openssl_private_decrypt, donde pasaremos que valor desencriptar, en donde almacenar y con que privatekey hacerlo.

Y eso es todo! Han logrado su primera conexión mega-segura!

Código Final


Les dejo el código final, un poco tocado para poner echos y demás para que sea algo visual:

Código :

<?php
$p12cert = array();
$file = 'certificado.p12';
$pass = "1234";
$fd = fopen($file, 'r');
$p12buf = fread($fd, filesize($file));
fclose($fd);
echo "<h1>Mi Primer Test</h1>";
if ( openssl_pkcs12_read($p12buf, $p12cert, $pass) )
{
   echo "Funciona";
}
else
{
    echo "No funciona";
}
$privatekey = $p12cert["pkey"];
$res=openssl_pkey_new();
openssl_pkey_export($res, $p12cert["pkey"]);
$publickey=openssl_pkey_get_details($res);
$publickey=$publickey["key"];

echo "<h2>Private Key:</h2>$privatekey<br><h2>Public Key:</h2>$publickey<BR>";

$cleartext = htmlentities('<center><b>Texto HTML</b></center>');

echo "<h2>Original:</h2>$cleartext<BR><BR>";

openssl_public_encrypt($cleartext, $crypttext, $publickey);

echo "<h2>Encriptada:</h2>$crypttext<BR><BR>";

$PK2=openssl_get_privatekey($p12cert["pkey"]);

$Crypted=openssl_private_decrypt($crypttext,$Decrypted,$PK2);
if (!$Crypted) {
   $MSG.="<p class='error'>Imposible desencriptar ($CCID).</p>";
}else{
   echo "<h2>Desencriptada:</h2>" . $Decrypted;
}
?>


Espero les sea de utilidad ^^

¿Sabes SQL? ¿No-SQL? Aprende MySQL, PostgreSQL, MongoDB, Redis y más con el Curso Profesional de Bases de Datos que empieza el martes, en vivo.

Publica tu comentario

o puedes...

¿Estás registrado en Cristalab y quieres
publicar tu URL y avatar?

¿No estás registrado aún pero quieres hacerlo antes de publicar tu comentario?

Registrate