Introducción

Actualización marzo del 2019: coinhive ha dejado de funcionar o dejará de funcionar al momento de escribir este post; por lo tanto este captcha ya no es válido.

Nota: si quieres usar reCAPTCHA en PHP mira mi otro post. Sé que este post es sobre una alternativa a reCAPTCHA pero como puedes ver, ya no funciona.

Sordid details following…

Un captcha funciona principalmente para detener a los bots y dejar pasar a los humanos. Veamos cómo trabajar con el captcha de coinhive en PHP.

El captcha de coinhive es un captcha como el recaptcha de Google, pero éste funciona minando criptomonedas. Así, no medimos si se trata de una persona o de un bot, sino del poder computacional.

Gracias a esto, a los “spammers” no les funcionará programar bots, pues aunque el captcha no ofrece retos para los bots, hace que la computadora tenga que trabajar. De esta forma los bots tendrán que esperar bastante tiempo antes de hacer lo que iban a hacer.

Cómo implementar captcha de coinhive en PHP

Esto es muy sencillo. Lo que tenemos que hacer es poner el captcha dentro de un formulario. Cuando el captcha detecta que has resuelto los hashes correspondientes, inyecta un nuevo campo al formulario, el cual tiene un token.

Del lado del servidor comprobamos el token con la API de coinhive, y si ambos coinciden entonces significa que el captcha ha sido resuelto correctamente.

Lado del cliente

Comencemos programando el lado del cliente para trabajar con el captcha de coinhive en PHP.

Pongamos de ejemplo este formulario en donde simplemente pedimos un nombre:

<form method="post" action="comprobar.php">
<input type="text" name="nombre" placeholder="Escribe tu nombre">
<input type="submit" value="Enviar">
</form>

Ahora, para integrar el captcha ponemos dentro de él la carga del script y el siguiente div:

<script src="https://authedmine.com/lib/captcha.min.js" async></script>
 <div
            data-disable-elements="[type='submit']"
            data-whitelabel="true"
            class="coinhive-captcha"
            data-hashes="1024"
            data-key="clave">
        <div>
            Esto se muestra mientras el captcha carga
        </div>
    </div>

Expliquemos los atributos:

  • data-disable-elements: un selector css. Todos los elementos que cumplan esa regla serán deshabilitados hasta que los hashes sean completados. Es opcional y sólo ayuda visualmente
  • data-whitelabel: ocultar el logotipo y otras cosas de coinhive
  • class: bueno, esto es una clase. Pero no debemos removerla, me parece que el script toma esa clase como guía para saber en dónde inyectar el captcha
  • data-hashes: cuántos hashes se deben calcular antes de que el captcha sea resuelto. Debe ser un múltiplo de 256. Este valor lo ponemos aquí y también del lado del servidor
  • data-key: nuestra clave pública que obtenemos en el escritorio de coinhive

La lista completa así como la guía la podemos ver en: https://coinhive.com/documentation/captcha

Es importante notar que si el usuario tiene un bloqueador de publicidad el script no se cargará, y por lo tanto no será posible resolver el captcha.

De tal manera que nuestro formulario completo lucirá así (por favor ignorar los estilos por ahora, pues el objetivo del post no es ese):

<form method="post" action="comprobar.php">
	<input type="text" name="nombre" placeholder="Escribe tu nombre">
	<br>
	<br>
 
	<script src="https://authedmine.com/lib/captcha.min.js" async></script>
	<div
	    data-disable-elements="[type='submit']"
	    data-whitelabel="true"
	    class="coinhive-captcha"
	    data-hashes="1024"
	    data-key="clave">
	    <div>
	        Esto se muestra mientras el captcha carga
	    </div>
	</div>
 
	<br>
	<input type="submit" value="Enviar">
 
</form>

Veamos ahora el lado del servidor.

Lado del servidor

Sigamos ahora con el lado del servidor para trabajar con el captcha de coinhive en PHP.

En el lado del servidor recibiremos el nombre y el token. Como lo dije, se enviará por el método post y podremos acceder a él a través de $_POST["coinhive-captcha-token"].

El código de ejemplo queda así:

<?php
$datos = [
    'secret' => 'clave_privada', # clave privada. Obtener de coinhive
    'token' => isset($_POST["coinhive-captcha-token"]) ? $_POST["coinhive-captcha-token"] : "", # el valor que recibimos del formulario. Poner modo por defecto si no lo mandan
    'hashes' => 1024, # el mismo número que pusimos en el formulario
];
 
$contexto = stream_context_create([
    'http' => [
        'header' => "Content-type: application/x-www-form-urlencoded\r\n", #Encabezados, dejar así
        'method' => 'POST', # El método
        'content' => http_build_query($datos) # Formamos la cadena de datos a enviar
    ]
]);
 
$url = 'https://api.coinhive.com/token/verify'; #Aquí se envían las peticiones
$respuesta = json_decode(file_get_contents($url, false, $contexto)); # Hacemos la petición POST
 
/*
    La API devuelve un JSON. Lo decodificamos con json_decode y vemos si 
    no es NULL y si tiene una propiedad llamada success con el valor
    true. En caso de que sí, adelante, el usuario ha
    resuelto el captcha.
    Si no (ya sea porque no se esperó, envió el formulario antes o 
    no resolvió los hashes esperados) entonces no lo dejamos pasar
*/
if($respuesta && $respuesta->success){
    echo "Ok, pasa " . $_POST["nombre"]; #Ejemplo de lo que hacemos si todo va bien
}else{
    echo "¡Alto ahí rufián!"
}
?>

Lo que hacemos es hacer una petición post con stream_context_create. Le pasamos nuestra clave privada (no la pública, ya que la pública va en el formulario), los hashes que pusimos del lado del cliente para evitar trampas y también el token que debió ser generado por el captcha.

De ahí coinhive se encarga de realizar la validación y dependiendo de ello nosotros realizamos acciones.

Obviamente este es un ejemplo básico, no hay validaciones ni estilos, pero muestra lo más importante de cómo trabajar con este servicio que algunos llaman malware aunque no lo es ;)

Si el post ha sido de tu agrado te invito a que me sigas para saber cuando haya escrito un nuevo post, haya actualizado algún sistema o publicado un nuevo software. Facebook | X | Instagram | Telegram | También estoy a tus órdenes para cualquier contratación en mi página de contacto