Evita que se salten el paywall en tu JavaScript publicado

Una barrera de paywall en el bundle es una función con nombre que devuelve un booleano, e invertirla es un parche de una línea. Qué cambian la ofuscación y una semilla por build a la hora de encontrarla y de mantener el parche funcionando.

Una comprobación de paywall o de derechos de acceso que se ejecuta en el navegador solo es cara de encontrar y cara de parchear si tú haces que lo sea. La salida minificada no la hace ni lo uno ni lo otro.

Por qué una barrera de paywall es un parche de una línea

En una salida sin procesar o minificada, una barrera de paywall suele ser una función con nombre que devuelve un booleano. Cualquiera que lea el bundle puede buscar la palabra que le da nombre: isSubscribed, hasAccess, checkEntitlement. Una vez encontrada, el ataque más barato es un parche de una línea que invierte el valor de retorno.

Ese parche funciona en la copia del archivo de cada usuario, y sigue funcionando en tu siguiente versión si el archivo no ha cambiado de forma. El trabajo de encontrar la barrera se paga una vez y se reutiliza en cada build posterior.

Cómo queda el archivo publicado después de un build

Un build por defecto renombra los identificadores y codifica los literales de cadena, así que la función que antes se llamaba isSubscribed ya no lleva ese nombre y las cadenas que la rodean ya no son texto legible. Buscar el nombre o el mensaje en el archivo publicado no encuentra nada que parchear.

La propiedad que más importa aquí es el polimorfismo por build. La semilla es nueva en cada build salvo que la fijes, así que un parche escrito contra una versión no encaja con la siguiente. Un atacante que averigua dónde está la barrera vuelve a pagar ese coste cada vez que publicas.

Sube la protección de la barrera

El preset por defecto ya renombra y codifica con un objetivo de complexity bajo. Para subir un escalón todo el bundle:

$ npx afterpack@latest dist/ --preset=hard

Para subir solo la función de la barrera sin tocar el resto del bundle, márcala con una directiva:

/* @afterpack preset=hard */
function checkEntitlement(token: string): boolean {
  return validateSubscription(token);
}
/* @afterpack end */

Las directivas tienen efecto en los builds Pro.

Comprueba que la barrera salió protegida

Abre el Protection Map después de un build y busca la función de la barrera. Debería estar coloreada con más intensidad que el código que la rodea, reflejando el objetivo de complexity más alto que estableciste para esa región. Si se ve igual que el resto del bundle, lee los diagnósticos del build: ahí se informa de una directiva que se leyó pero no tuvo efecto.

Dónde termina una barrera en el cliente

La rotación por build es la parte duradera de todo esto. Una semilla nueva en cada versión significa que el trabajo de localizar y parchear la barrera nunca se arrastra, así que un parche, script o userscript escrito contra un build deja de aplicarse al siguiente. Un lector estático que analice un único build aún puede recuperar un cálculo equivalente, ya que la barrera tiene que ejecutarse correctamente en el navegador, así que combina la comprobación en el cliente con una llamada de derechos de acceso en el servidor para todo lo que controle ingresos.

Siguiente