La parte cliente de OpenWAF Verify es código abierto con licencia Apache 2.0: github.com/openwaf-dev/verify (enlace externo). Es el código que se ejecuta en el navegador de tus visitantes, el protocolo con el que habla con el borde y las librerías con las que tu servidor comprueba los tokens.
Puedes leer qué hacen el widget Verify y el reto de navegador en el navegador del visitante, compararlo con lo que sirve tu sitio y usar las librerías en lugar de escribir tus propias llamadas a siteverify.
Qué es abierto
- Widget de navegador (
challengejs/). El scriptwidget.js: la caja, sus estados, la APIowafVerifyy el campo ocultoowaf-verify-response. - Worker de prueba de trabajo (
challengejs/). El Web Worker que resuelve los acertijos SHA-256 y la alternativa que calcula en la página cuando no hay worker. - Página intermedia (
challengejs/). La plantilla HTML y el CSS de la página del reto de navegador. - Protocolo (
spec/). Cómo pide el navegador un reto, envía su solución y recibe un token, y la API de siteverify. - Librerías de siteverify. Go (
siteverify/, módulogithub.com/openwaf-dev/verify), Node.js y TypeScript (node/,@openwaf/verify) y PHP (php/, paquete de Composeropenwaf/verify). - Componentes. React (
react/,@openwaf/verify-react) y Vue 3 (vue/,@openwaf/verify-vue). - Ejemplos (
examples/). Aplicaciones pequeñas que funcionan: muestran el widget y comprueban el token.
Qué no es abierto y por qué
Algunas partes siguen cerradas:
- La puntuación de riesgo. Cómo convierte el borde las señales del servidor en una puntuación.
- La regla de coherencia del navegador. Cómo comprueba el borde que un navegador se comporta como el navegador que dice ser.
- Las comprobaciones de automatización en la página. El módulo de comprobaciones de sí o no sobre herramientas de automatización, y cómo se codifica su respuesta en cada reto.
- Reputación y listas de amenazas. Las listas detrás de las listas de amenazas y la reputación.
- El interior del borde. El proxy y cómo funcionan sus nodos.
Estas partes deciden con cuánto cuidado mira el borde una petición. Si sus reglas exactas fueran públicas, la automatización podría ajustarse para pasarlas, y cada una dejaría de servir el mismo día en que se publicara.
Lo que leen no es secreto. Los datos que trata cada parte están en Datos tratados y en la puntuación de riesgo.
El widget servido no es idéntico byte a byte
El widget que sirve tu borde es este código abierto más un módulo de extensión cerrado: las comprobaciones de automatización en la página.
- El módulo hace unas pocas comprobaciones de sí o no en la página.
- Su única salida es un número entero opaco que se añade a la petición con la solución.
- No lee ninguna superficie de huella digital: ni canvas, ni WebGL, ni audio, ni fuentes, ni client hints de alta entropía.
Por ese módulo, una compilación del repositorio no es idéntica byte a byte al paquete de /__waf/challenge/v1/widget.js. Todo lo demás de ese paquete es el código de challengejs/.
Compruébalo tú mismo
No tienes que fiarte de lo que decimos. Abre una página que use Verify, como la demo en vivo, con las herramientas para desarrolladores del navegador:
- Red. Todas las peticiones del widget van al propio host de la página, bajo
/__waf/. Nada va a otro dominio. - Cookies. El widget no pone ninguna cookie. La página del reto de navegador pone solo
__waf_pass, después de resolver el reto. - Content Security Policy. El widget funciona con
Content-Security-Policy: default-src 'self', sin infracciones en la consola. La demo funciona con esa política. - Código. Lee los
widget.jsyworker.jsservidos y compáralos conchallengejs/en el repositorio.
Usar las librerías
Las librerías llaman a siteverify por ti. Siguen la referencia de siteverify y se comportan igual en todos los lenguajes. De momento se instalan desde el repositorio de GitHub: Go y Composer desde la etiqueta v0.1.0, y npm desde los tarballs adjuntos a la versión (enlace externo). Los paquetes de npm y Packagist llegarán pronto.
go get github.com/openwaf-dev/verify/siteverify@v0.1.0c, err := siteverify.New(os.Getenv("OWAF_VERIFY_SECRET"))
if err != nil {
log.Fatal(err)
}
res, err := c.Verify(r.Context(), r.FormValue("owaf-verify-response"), siteverify.Params{
RemoteIP: clientIP,
ExpectedAction: "signup",
})
if err != nil || !res.Success {
http.Error(w, "verification failed", http.StatusForbidden)
return
}
// crear la cuentanpm install https://github.com/openwaf-dev/verify/releases/download/v0.1.0/openwaf-verify-0.1.0.tgzimport { SiteverifyClient } from "@openwaf/verify";
const client = new SiteverifyClient({ secret: process.env.OWAF_VERIFY_SECRET! });
const result = await client.verify(token, { remoteIp, expectedAction: "signup" });
if (!result.success) {
// rechazar el formulario
}composer config repositories.openwaf-verify vcs https://github.com/openwaf-dev/verify
composer require openwaf/verify:^0.1<?php
$client = new OpenWAF\Verify\Siteverify\Client((string) getenv('OWAF_VERIFY_SECRET'));
$result = $client->verify(
$_POST['owaf-verify-response'] ?? '',
remoteIp: $clientIp,
expectedAction: 'signup',
);
if (!$result->success) {
http_response_code(403);
exit('Verification failed');
}
// crear la cuentanpm install https://github.com/openwaf-dev/verify/releases/download/v0.1.0/openwaf-verify-react-0.1.0.tgzimport { Verify } from "@openwaf/verify-react";
<form action="/signup" method="post">
<input name="email" type="email" required />
<Verify siteKey="owk_YOUR_SITE_KEY" action="signup" onSuccess={(token) => setToken(token)} />
<button type="submit">Sign up</button>
</form>npm install https://github.com/openwaf-dev/verify/releases/download/v0.1.0/openwaf-verify-vue-0.1.0.tgz<script setup>
import { Verify } from "@openwaf/verify-vue";
</script>
<template>
<form action="/signup" method="post">
<input name="email" type="email" required />
<Verify site-key="owk_YOUR_SITE_KEY" action="signup" @success="onToken" />
<button type="submit">Sign up</button>
</form>
</template>Los componentes de React y Vue muestran el mismo widget, así que la página tiene que servirse a través de OpenWAF.
Qué hacen las librerías de servidor:
- Valores por defecto. Llaman a
https://dash.openwaf.dev/v1/challenge/siteverifycon un tiempo de espera de 10 segundos. Puedes apuntarlas ahttps://<tu host>/__waf/challenge/siteverify. - Sin petición cuando no puede salir bien. Un token vacío devuelve
missing-input-responsey un token de más de 2048 bytes devuelveinvalid-input-response, sin llamar a siteverify. - Nombre de host y acción. Si indicas el nombre de host o la acción que esperas y el token no coincide, la respuesta es un fallo con
hostname-mismatchoaction-mismatch. Estos dos códigos los pone la librería, no siteverify. - Respuestas y errores. Toda respuesta de siteverify, incluidas
400,405y429(con suRetry-After), vuelve como resultado. Un tiempo de espera agotado, un fallo de red, otro estado HTTP o un cuerpo que no es JSON es un error: errores centinela en Go,SiteverifyErroren Node ySiteverifyExceptionen PHP, con los códigostimeout,network,httpybad-response. - Sin reintentos automáticos. Para reintentar después de un tiempo de espera agotado, envía otra vez la misma clave de idempotencia: la segunda llamada recibe la primera respuesta en lugar de
timeout-or-duplicate. - El secreto no sale en los errores. Nunca aparece en mensajes de error, logs ni objetos impresos.
Pruébalas con las claves de prueba: ows_test_pass, ows_test_fail y ows_test_spent funcionan sin widget.
Licencia
Todo el repositorio tiene la licencia Apache 2.0 (enlace externo). Puedes usarlo, cambiarlo y redistribuirlo, también en productos comerciales.
Contribuir
Abre incidencias y pull requests en github.com/openwaf-dev/verify (enlace externo). Revisamos cada cambio. Los cambios en el código de navegador se publican con el borde, así que un cambio aceptado llega a los sitios con la siguiente versión del borde.
Informar de una vulnerabilidad
No abras una incidencia pública. Escribe a support@openwaf.dev (security@openwaf.dev llega al mismo equipo) y sigue el SECURITY.md (enlace externo) del repositorio.