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.
Por torrealbaruben el 06 de Octubre de 2010
¿Qué otro tipo de certificado seguridad existente?
Por eveevans el 06 de Octubre de 2010
Por [email protected] el 06 de Octubre de 2010
Por daz_angie el 06 de Octubre de 2010
La verdad es que no es nada complicado, pero el chiste de un certificado de seguridad es que tengas la validación de una organización, y no nada más que te lo inventes tú.
Hay que tener cuidado con eso.
Por Hernán el 06 de Octubre de 2010
[email protected] :
¿Comunidad de diseñadores?
[email protected] :
Ejecuta el código que yo hice usando un algoritmo encriptado basado en PKCS#12 y dime si el echo de la llave pública te aparece aunque sea una vez igual la cadena. Verás como la private SIEMPRE es igual, y la pública se modifica. Ya sabes, la seguridad SI es importante cuando manejas certificados.
[email protected] :
Esto es EXACTAMENTE eso, un certificado digital con openSSL, y no, no es "más sencilla". Tienes que poder operar con esto... lo que pasa es que debes estar pensando en certificados simples de aplicar como los de VeriSign, el ejemplo que use para todo esto, es para aplicar certificados bancarios de alto nivel de seguridad.
Como comentario final... ¿Por que mierda alguien sabria tu clave privada? Se supone es secreta y jamás debes de exponerla. Si la expones, es porque alguien SI tiene acceso al servidor y por ende, a tu código, no sería jodido leer la ecuación o simplemente robarla.
Por Hernán el 06 de Octubre de 2010
torrealbaruben :
Algoritmos Usuales:
Saludos, Hernán . -
Por M@U el 06 de Octubre de 2010
Por Hernán el 06 de Octubre de 2010
M@U :
Yo no puse el título. El titulo original era "Certificados & SLL". El que editó el bbcode del artículo y lo paso a portada fue el que lo cambio.
Saludos, Hernán . -
Por Ivan el 07 de Octubre de 2010
Por Hernán el 07 de Octubre de 2010
Ivan-blog :
Dime cual es el error. Caso contrario, solo quedas como un idiota.
Por CLAnonimo el 07 de Octubre de 2010
Realmente no tienes ni idea
Por eldervaz el 08 de Octubre de 2010
Ivan-blog :
Estoy totalmente deacuerdo , cuando desarrollo mis app y tengo que pasar mi clave de la tarjeta de crédito hago esto:
www.dominio.com/compra.php?claveTarjetaDeCredito=123456789
o cuando hago un login uso:
www.dominio.com/login.php?user=vivaYO&pass=123456
Por Miguel Altamirano M. el 23 de Noviembre de 2010
Es posible usar éstas técnicas de cifrado en una Aplicación VB Net ?.
He visto que en éste IDE existe una clase llamada RSA, pero no sé si sirva especialmente para algo similar.
Esto es acerca de la facturación electrónica.
Por Samuel Noriega el 20 de Junio de 2011
Por samSSL el 13 de Agosto de 2011
saludos
Por feliperfec el 02 de Septiembre de 2011
Por pulque el 20 de Septiembre de 2011
Un saludo
Por Antonio el 13 de Noviembre de 2011
Por superDiego el 24 de Noviembre de 2011
Por Eliud el 20 de Julio de 2012
Por ronal el 22 de Febrero de 2013
Por yes el 28 de Febrero de 2013
Por Daniel el 19 de Marzo de 2013
Por anonimo el 02 de Mayo de 2013
Por Daniel Urquijo el 27 de Julio de 2013
A los que se enfrascan en discuciones ofensivas por favor, sugiero aporten sus explicaciones y ya miraremos quien lo hizo mejor.
Por Diegoni el 19 de Marzo de 2015
Por Cloud el 15 de Julio de 2015
Mi navegador no entra en las HttpS y es a causa de la ausencia de certificados.
Necesito un instalador que los INSTALE todos actualizados de forma automatica ( como cuando instalamos un programa) en donde corresponda.
Para que el navegador deje de dar ESTE absurdo error y vuelva a funcionar perfecto, como siempre.
Gracias.
Por diegotham el 16 de Octubre de 2015
Por jorands00 el 20 de Octubre de 2015
Ingresa Aquí y registrate
http://acugd.com/GanaDinero
Por Dental implants abro el 18 de Agosto de 2016
http://www.vita-centre.co.uk