Seguridad y manejo de datos
Beaconry maneja dos cosas sensibles: las credenciales de API que conectan tu sitio con diez plataformas publicitarias y la PII de los visitantes que hace que las conversiones coincidan. Esta página documenta exactamente cómo se protegen ambas, de principio a fin. Cada credencial se cifra en reposo, dos de los diez canales nunca dejan que tu sitio sostenga un token OAuth, cada evento pasa por la puerta de consentimiento y la PII de los visitantes se hashea con SHA-256 antes de salir de tu servidor.
La versión corta
- Credenciales en reposo: cada secreto de API, token de acceso, bearer OAuth y la clave de licencia se almacenan cifrados con AES-256-GCM en la base de datos, derivados de tu auth salt de WordPress.
- Google Ads y Microsoft Ads: tu sitio nunca sostiene los tokens OAuth. Viven en el broker de Beaconry; el plugin solo sostiene un bearer firmado que autoriza las cargas en tu nombre.
- Consentimiento: sin consentimiento de analítica en la cookie
nl_prefdel visitante, ningún evento sale del navegador y no ocurre ningún envío del lado del servidor. La puerta se aplica de forma centralizada, una sola vez. - PII: el correo, el teléfono, el nombre, la dirección y el resto se normalizan y se hashean con SHA-256 según la spec de matching de cada canal. Los valores en bruto nunca van por el cable.
- Borrado: una herramienta de derecho al olvido integrada calcula los hashes exactos que necesita cada proveedor y registra la solicitud en un audit log, sin almacenar nunca el texto plano.
Cifrado de credenciales en reposo (AES-256-GCM)
Cada valor que pudiera autenticarse ante un tercero se cifra antes de tocar la base de datos. Eso cubre el secreto de API de GA4, el token CAPI de Meta, el token de acceso de TikTok, el token de acceso de LinkedIn, los tokens de acceso de Pinterest / Snapchat / Reddit, los cuatro secretos OAuth 1.0a de X Ads, ambos bearers de ad-broker y la clave de licencia de Polar.
El cifrado es AES-256-GCM, cifrado autenticado. GCM te da confidencialidad e integridad en una sola pasada: un texto cifrado que ha sido manipulado falla la verificación del tag de autenticación al descifrar y se rechaza, en lugar de descifrarse silenciosamente a basura. Cada valor recibe un IV aleatorio fresco de 12 bytes, y el tag GCM de 16 bytes se almacena junto al texto cifrado.
La clave de cifrado se deriva de wp_salt('auth'), el auth salt por instalación que cada sitio WordPress ya genera en wp-config.php. Eso significa que la clave nunca se envía con el plugin y nunca es la misma entre dos sitios: un volcado de base de datos de una instalación no se puede descifrar sin los salts de esa instalación. Los valores almacenados llevan un prefijo encv2: para que el formato sea autodescriptivo.
| Propiedad | Valor |
|---|---|
| Algoritmo | AES-256-GCM (autenticado) |
| Fuente de la clave | wp_salt('auth'), por instalación |
| IV | 12 bytes, aleatorio fresco por valor |
| Tag de autenticación | 16 bytes, almacenado con el texto cifrado |
| Forma almacenada | encv2: + base64(IV + tag + texto cifrado) |
Los blobs CBC heredados migran al leerse
Las instalaciones anteriores al cambio a GCM almacenaban los secretos como AES-256-CBC (un IV de 16 bytes, prefijo enc:, sin tag de autenticación). CBC sin MAC es vulnerable a manipulación al estilo padding-oracle, por lo que Beaconry lo abandonó. No tienes que hacer nada con los valores antiguos: la ruta de descifrado detecta el prefijo y lee cualquiera de los dos formatos, y la próxima vez que ese campo se guarde se vuelve a cifrar como GCM. Así, los blobs CBC desaparecen de la base de datos de forma gradual a medida que tocas cada ajuste, sin migración manual y sin reconexión.
Lo que no se almacena en absoluto
La protección más fuerte no es cifrar un secreto, es nunca sostenerlo. Dos canales están construidos así (ver la siguiente sección), y la PII de los visitantes nunca es persistida por la pipeline de envío en primer lugar: se hashea en tránsito y se reenvía, no se escribe en una tabla de Beaconry. El log operativo registra los resultados de los eventos (salud, fallos de envío, solicitudes rechazadas), nunca PII de eventos en bruto.
El modelo de confianza con broker OAuth (Google Ads + Microsoft Ads)
Google Ads y Microsoft Ads necesitan un cliente OAuth confidencial: un client secret, un developer token y un refresh token de larga duración. Enviar esos a miles de instalaciones de clientes sería inviable, cada copia sería un lugar desde el que el secreto podría filtrarse. Así que Beaconry no los envía. Viven en un único broker de cliente confidencial que Beaconry opera en oauth.beaconry.app.
Tu sitio se conecta una vez mediante una redirección OAuth estándar. Al final de ella, el broker no entrega a tu sitio los tokens de Google o Microsoft. Acuña un site id opaco aleatorio, almacena el refresh token contra ese id en su propio almacén key-value y devuelve en su lugar un bearer firmado y corto a tu plugin. Cada carga de conversiones posterior desde tu sitio envía ese bearer; el broker lo verifica, busca el refresh token, acuña un token de acceso fresco, adjunta el developer token y publica en la plataforma publicitaria en tu nombre. Tu wp-config.php y tu base de datos sostienen cero secretos de Google o Microsoft, solo el bearer (a su vez cifrado en reposo como cualquier otra credencial).
Qué es el bearer y qué no es
El bearer es un JWT firmado con HMAC-SHA256 (HS256) usando una clave de firma que existe únicamente dentro del broker. Su payload es deliberadamente diminuto: un site id opaco (sid), el host del sitio, una marca de tiempo issued-at y una expiración (los bearers llevan un claim de expiración de unos cinco años; un bearer expirado se rechaza). No es un token de Google, no lleva ningún scope de Google o Microsoft, y es inútil contra cualquier endpoint que no sea la propia ruta de carga del broker. La firma significa que un cliente no puede falsificarlo ni alterarlo; el broker rechaza cualquier cosa cuyo HMAC no verifique.
Endurecimiento que limita el alcance del daño si un bearer se filtra
- Los tokens nunca viajan en una URL. Para el flujo de ad-broker, el bearer se obtiene mediante un POST de servidor a servidor al endpoint
/redeemdel broker (el state OAuth de un solo uso se intercambia por el bearer en un cuerpo JSON, luego la clave del state se elimina), de modo que el bearer nunca se coloca en una URL de redirección donde pudiera acabar en un historial del navegador, un log de proxy o una cabecera referrer. - Pin de cuenta perezoso en el primer uso. La primera carga de conversiones que hace un bearer lo fija a ese id de cuenta de Ads. Cada carga posterior debe coincidir con el pin o el broker devuelve 403. Si un bearer se filtrara alguna vez, un atacante no podría apuntarlo a una cuenta de Ads diferente que él controle para inyectar o extraer conversiones. El pin se borra al desconectar, de modo que una reconexión limpia inicia una ventana de pin fresca.
- Revocación de un solo sentido. Desconectar desde la pestaña Tracking le indica al broker que revoque y borre el refresh token almacenado y limpie el pin, luego borra el bearer localmente. No hay camino de vuelta a los tokens desde el lado del plugin.
Los otros ocho canales (GA4, Meta, TikTok, LinkedIn, Pinterest, Snapchat, Reddit, X Ads) se autentican con un token que pegas directamente, que luego se cifra en reposo como se describe arriba. No usan el broker porque sus APIs aceptan un token de larga duración o una firma por llamada que es seguro sostener cifrada en tu propio servidor. El token de 60 días de LinkedIn además muestra un contador de días restantes para que te vuelvas a autenticar antes de que caduque.
La puerta de consentimiento
Beaconry no enviará nada sin consentimiento. El banner de consentimiento incluido (nl-data-gate) escribe una cookie nl_pref que registra la elección del visitante en las categorías funcional, analítica y marketing. Dos comprobaciones la leen:
- Puerta de analítica en el endpoint REST. Cada evento del navegador hace POST a tu propio endpoint del mismo origen. Antes de que ocurra cualquier otra cosa, el endpoint lee
nl_prefy descarta el evento en silencio salvo que el flaganalyticsesté activado. Sin consentimiento, sin evento, y punto. Esto no es un banner cosmético sobre un rastreador que dispara de todos modos, los datos físicamente no salen del navegador hasta que el visitante da su consentimiento. - Puerta de marketing en la cookie de matching first-party. La función opcional de matching entre eventos (que recuerda las claves de matching hasheadas de un visitante entre, por ejemplo, el envío de un formulario y un checkout posterior para elevar la calidad del matching) solo escribe su cookie first-party cuando el flag separado
marketingestá activado. El consentimiento de analítica por sí solo no la activa.
Los llamadores del lado del servidor (un envío de formulario, una compra de WooCommerce) no vuelven a preguntar en su propia capa, porque el visitante ya actuó en un contexto donde aplica el consentimiento. El consentimiento se aplica una vez, de forma centralizada, en el dispatcher, la misma puerta que cubre los eventos de commerce y personalizados. El efecto neto es un solo lugar sobre el que razonar, no una dispersión de comprobaciones por canal que pueden desincronizarse.
Si ejecutas tu propia plataforma de gestión de consentimiento, apúntala a la misma cookie nl_pref y Beaconry respetará la decisión de tu CMP sin un segundo banner.
Cómo se hashea la PII de los visitantes
Cuando un evento lleva datos de usuario (un lead de formulario, una compra con dirección de facturación), Beaconry los hashea por canal antes de la transmisión. Los campos de advertiser-match que reconoce son correo, teléfono, nombre, apellido, ciudad, provincia, código postal, país, género, fecha de nacimiento y un id de cliente externo.
El hashing es SHA-256 sobre un valor normalizado. La normalización importa tanto como el hash: el mismo valor lógico tiene que producir el mismo digest sin importar de qué fuente venga, o las audiencias nunca coinciden. Así que antes de hashear, Beaconry:
- pasa el valor a minúsculas y lo recorta (la regla base que especifican las plataformas),
- reduce un número de teléfono a dígitos E.164 (sin espacios, sin el signo más inicial) para que un
+49 170 1234567y un0170 1234567puedan reconciliarse, - canonicaliza país, provincia y código postal, de modo que una provincia alemana dada como
Niedersachsen,NIoniresuelva a una sola entrada de audiencia en Meta, TikTok, Pinterest y Snap, - reduce el género a una sola
f/my la fecha de nacimiento aYYYYMMDDantes del hash.
Cada canal recibe entonces los campos hasheados con los nombres de clave y la forma exactos que espera su CAPI (los em / ph / fn / ... de Meta, el sha256_email_address de GA4, los matchers de user-id hasheados de LinkedIn, etc.). Los valores en bruto, sin hashear, nunca se envían a ninguna plataforma y nunca los almacena Beaconry. Un campo que marques como Don't map en la pestaña Forms queda excluido del hashing por completo, aunque su nombre todavía parezca PII, consulta la documentación de Forms para el marcador de skip por campo.
Endurecimiento del endpoint
El endpoint del mismo origen que recibe los eventos del navegador es la única superficie alcanzable desde fuera, así que está blindado en consecuencia. Siempre responde 204 No Content independientemente del resultado, de modo que un sondeo no pueda distinguir un evento descartado de uno aceptado. Además de la puerta de consentimiento, impone:
- Un nonce rotatorio. Cada evento debe llevar un nonce de WordPress válido (rotación de 12 horas) que la página emitió. Un POST pelado desde la internet abierta sin el nonce se descarta. Esto es lo que impide que un extraño escriba scripts de conversiones falsas para quemar tu cuota de plataforma publicitaria o envenenar tus informes de GA4. Las páginas abiertas durante mucho tiempo o cacheadas obtienen un nonce fresco automáticamente para que el tracking legítimo nunca falle.
- Un filtro de bots. El tráfico obvio de crawlers, previews y scanners se descarta antes de que pueda tocar una sola plataforma publicitaria, lo que mantiene limpias la cuota y los datos. Es filtrable para configuraciones inusuales.
- Un límite de tasa por IP. Un tope suave (600 eventos por minuto por defecto, filtrable) atrapa ráfagas abusivas muy por encima del ritmo de cualquier visitante real. La clave del bucket es un hash de la IP, de modo que no se persiste ninguna IP en bruto.
- IP de cliente resistente al spoofing. Las cabeceras de proxy como
X-Forwarded-ForyCF-Connecting-IPsolo se confían cuando la conexión directa proviene realmente de un rango edge de Cloudflare. Un atacante con conexión directa no puede falsificar una cabecera para esquivar el límite de tasa, porque su valor spoofeado se descarta en favor de la dirección de conexión real. - Sin caching. El endpoint marca sus respuestas como no-store para que un CDN o un caché de página completa nunca pueda servir un nonce obsoleto ni tragarse un evento.
Herramienta de derecho al olvido conforme al RGPD
Cuando un visitante envía una solicitud de "borra mis datos", la parte incómoda no es tu propia base de datos (Beaconry no almacena PII de visitantes allí), son las diez plataformas publicitarias a las que reenviaste datos hasheados, cada una con su propia UI de borrado que toma entrada hasheada. La herramienta de Beaconry, en la pestaña Advanced, cierra esa brecha.
Introduces el correo y / o el teléfono del visitante. La herramienta calcula los hashes SHA-256 usando exactamente la misma normalización que usan los dispatchers en el momento de la carga, de modo que el hash que pegas en la UI de privacidad de un proveedor coincida con el hash que ese proveedor almacenó. Luego renderiza una tarjeta de workflow por destino (solo para los canales que realmente has configurado) para que no tengas que buscar entre diez docs de proveedores y encontrar cada formulario de borrado.
De forma crucial, la solicitud se registra en un audit log para tu propio registro de cumplimiento, pero el log almacena solo los hashes y el id de usuario de WordPress del admin que la ejecutó, nunca el correo o el teléfono en texto plano. El resultado en texto plano se muestra una vez, en un transient de un solo uso que se consume y se elimina en la siguiente carga de página. Así, ejecutar una solicitud de borrado no crea por sí misma un nuevo lugar donde la PII en bruto del visitante quede dando vueltas.
Controles para usuarios avanzados
Vale la pena conocer dos interruptores para configuraciones endurecidas o impulsadas por cumplimiento, ambos definidos en wp-config.php:
- Credenciales completamente fuera de la base de datos. Cualquier credencial de canal puede suministrarse como una constante de
wp-config.phpen lugar de a través de la UI. Cuando la constante está definida y no vacía, gana sobre el valor almacenado en el momento de la lectura, y el campo se renderiza bloqueado en el admin. Esto mantiene los secretos en tu infraestructura como código o en la configuración de tu servidor, en lugar de en la tabla de opciones de WordPress, útil cuando la base de datos se respalda o replica de forma más amplia que el código. - Desactivar la persistencia de PII. La cookie de matching entre eventos puede apagarse si tu política de privacidad no permite persistir las claves de matching de los visitantes, ni siquiera cifradas y ni siquiera con consentimiento. El tracking de conversiones del lado del servidor sigue funcionando sin ella, cambias una porción de calidad de matching por cero persistencia de PII.
Una nota sobre el propio sitio de marketing de Beaconry: no incluye ningún pixel de tracking, ninguna analítica y ningún banner de cookies. Vender herramientas de privacidad del lado del servidor y luego soltar un pixel de terceros sobre tus visitantes sería una contradicción, así que no lo hacemos.