Filtraciones de CDP en Puppeteer: cómo los sistemas antifraude detectan la automatización a través de Chrome DevTools Protocol


Markus_automation
Expert in data parsing and automation
Entre las herramientas de automatización de navegadores, Puppeteer ha ocupado desde hace mucho tiempo un lugar especial. A diferencia del pesado ecosistema de Selenium, ofrecía a los desarrolladores un control nativo y de alto rendimiento sobre Chromium de forma nativa dentro del entorno Node.js.
Puppeteer se convirtió en un estándar de la industria gracias a su enorme ecosistema de complementos listos para usar y su profunda integración con el motor V8. Puede tomar Puppeteer, conectar puppeteer-extra-plugin-stealth, adquirir proxies de alta calidad, falsificar cuidadosamente las huellas digitales de Canvas y WebGL y, para muchas tareas, eso será suficiente.
Sin embargo, en sitios web bien protegidos, este tipo de scraper puede encontrarse con dificultades. Los sistemas de protección como Cloudflare, Akamai o DataDome pueden empezar a bloquear sus sesiones. ¿Por qué ocurre esto?
El problema no radica en la lógica de su código ni en la calidad de sus proxies. La razón está incrustada en la base misma que hace que Puppeteer sea tan potente y conveniente: el Protocolo Chrome DevTools (CDP). Este protocolo de control de bajo nivel deja tras de sí huellas digitales específicas que los algoritmos modernos contra el fraude pueden detectar y utilizar para identificar bots.
Analicemos cómo se producen estas filtraciones y por qué las técnicas de falsificación superficial para las configuraciones estándar de Puppeteer ya no funcionan.
Contenidos
Mantén tu anonimato en línea con Octo Browser. Tu huella digital real no se puede rastrear.
¿Te gustaría probar Octo Browser con descuento?
Usa el código promocional OCTOSCRAPER para obtener un 30% de descuento en cualquier suscripción. Esta oferta solo es válida para nuevos usuarios.
¿Qué es CDP y por qué deja rastros digitales?
El protocolo Chrome DevTools proporciona acceso de bajo nivel a la arquitectura del navegador. Fue diseñado originalmente para la depuración, inspección y creación de perfiles, no para el raspado web oculto.
El protocolo opera a través de conexiones WebSocket que interactúan directamente con el motor V8. Cuando tu script envía un comando, como un clic o la navegación por una página, el navegador abre un socket local para la comunicación bidireccional. Este proceso genera inevitablemente registros internos, afecta la asignación de memoria y deja artefactos dentro del entorno del navegador aislado. Los sistemas de seguridad pueden analizar estos microcambios y patrones de sincronización para detectar comportamientos automatizados. Como resultado, la mera existencia de la conexión puede revelar la automatización del navegador.
Cómo difieren las fugas de CDP de la huella digital tradicional
Es importante entender que las fugas de CDP y las fugas de la huella digital del navegador representan dos vectores de detección fundamentalmente diferentes.
La generación de huellas digitales tradicional (Canvas, WebGL, fuentes) identifica características únicas del hardware y el comportamiento de renderizado. Las inconsistencias en la huella digital o los errores de suplantación permiten a los sistemas antibot detectar la manipulación y clasificar al usuario como sospechoso.
Las fugas de CDP revelan indicadores de comportamiento y estructurales de la ejecución del código. Exponen el hecho de que el navegador está siendo controlado de forma remota.
Puedes tener una huella digital WebGL perfectamente única, pero los indicadores de automatización pueden invalidar instantáneamente esa ventaja. Las comprobaciones de la huella digital del navegador requieren recursos y tiempo de procesamiento considerables, mientras que comprobar las variables de entorno o las pilas de llamadas es casi gratuito. Esta es precisamente la razón por la que los sistemas antifraude favorecen la detección basada en CDP. Les permite filtrar bots durante las comprobaciones básicas a nivel de protocolo, conservando los recursos del servidor que de otro modo se gastarían en análisis de comportamiento profundos más costosos.
Anatomía de las fugas del protocolo Chrome DevTools
Marcadores de contexto de ejecución
Una de las principales debilidades de Puppeteer radica en cómo exactamente ejecuta tu código dentro del navegador. Bajo el capó, el método page.evaluate() se basa en el comando de CDP Runtime.evaluate.
Cuando se inyecta un script en el navegador, las versiones modernas de Puppeteer generan una URL fuente específica asociada con ese fragmento de código. Si ocurre un error durante la ejecución del script, el motor V8 crea un rastreo de pila estándar que puede contener entradas como:
at pptr:evaluate;C:\Users\Admin\Projects\...\main.js:17:14
at pptr:evaluate;C:\Users\Admin\Projects\...\main.js:17:14
Al anular las funciones básicas del navegador, los sistemas antifraude pueden provocar intencionadamente errores invisibles e inspeccionar el objeto Error.stack. Pueden descubrir:
El prefijo
pptr:, una referencia directa a Puppeteer.Una ruta absoluta a un archivo en tu máquina local o servidor, que comienza con
C:\o/var/www/....
El navegador de un usuario real nunca ejecuta código de rutas de sistemas de archivos locales cuando visita un sitio web público. Por lo tanto, dichos marcadores representan una evidencia definitiva de automatización.

Cambiar tu dirección IP o suplantar las huellas de Canvas no resolverá este problema. Para ocultar estos marcadores, debes modificar la biblioteca misma o el entorno de ejecución del navegador.
La solución más confiable es eliminar el marcador pptr:evaluate directamente del código fuente de Puppeteer antes de que se envíen los comandos al navegador. Dado que buscar y editar archivos manualmente después de cada instalación de npm no es práctico, se puede usar un parche simple:
const fs = require('fs'); const path = require('path'); // Path to ExecutionContext.js in recent Puppeteer versions const targetFile = path.resolve(__dirname, 'node_modules/puppeteer-core/lib/cjs/puppeteer/cdp/ExecutionContext.js'); if (fs.existsSync(targetFile)) { let content = fs.readFileSync(targetFile, 'utf8'); // Replace the pptr:evaluate prefix with an anonymous call // and remove the local file path const patchedContent = content.replace(/pptr:evaluate;.*?\\n/g, 'anonymous:evaluation;\n'); fs.writeFileSync(targetFile, patchedContent, 'utf8'); console.log('Puppeteer patched successfully. pptr:evaluate markers removed.'); }
const fs = require('fs'); const path = require('path'); // Path to ExecutionContext.js in recent Puppeteer versions const targetFile = path.resolve(__dirname, 'node_modules/puppeteer-core/lib/cjs/puppeteer/cdp/ExecutionContext.js'); if (fs.existsSync(targetFile)) { let content = fs.readFileSync(targetFile, 'utf8'); // Replace the pptr:evaluate prefix with an anonymous call // and remove the local file path const patchedContent = content.replace(/pptr:evaluate;.*?\\n/g, 'anonymous:evaluation;\n'); fs.writeFileSync(targetFile, patchedContent, 'utf8'); console.log('Puppeteer patched successfully. pptr:evaluate markers removed.'); }
Si modificar node_modules no es una opción, los marcadores se pueden filtrar en tiempo de ejecución inyectando un script de suplantación antes de que se cargue la página de destino. El script anula el comportamiento del objeto Error nativo y limpia los rastreos de pila:
await page.evaluateOnNewDocument(() => { // Save the original Error constructor const NativeError = window.Error; window.Error = function(...args) { const err = new NativeError(...args); const originalStack = err.stack; if (originalStack) { Object.defineProperty(err, 'stack', { get: function() { // Break stack trace into strings and remove Puppeteer-related entries from it return originalStack .split('\n') .filter(line => !line.includes('pptr:evaluate')) .join('\n'); } }); } return err; }; // Restore the prototype chain to avoid detection window.Error.prototype = NativeError.prototype; });
await page.evaluateOnNewDocument(() => { // Save the original Error constructor const NativeError = window.Error; window.Error = function(...args) { const err = new NativeError(...args); const originalStack = err.stack; if (originalStack) { Object.defineProperty(err, 'stack', { get: function() { // Break stack trace into strings and remove Puppeteer-related entries from it return originalStack .split('\n') .filter(line => !line.includes('pptr:evaluate')) .join('\n'); } }); } return err; }; // Restore the prototype chain to avoid detection window.Error.prototype = NativeError.prototype; });

Como resultado, en lugar de exponer las rutas de archivos locales, el rastreo de pila mostrará algo como esto
Vulnerabilidades de Page.addScriptToEvaluateOnNewDocument
Los intentos de ocultar la automatización del navegador, incluido el uso de complementos ocultos populares, suelen basarse en inyectar JavaScript de suplantación antes de que se cargue el sitio web de destino. En Puppeteer, esto se hace habitualmente a través del comando Page.addScriptToEvaluateOnNewDocument.
Sin embargo, el uso de este método en sí deja rastros claros en el entorno de ejecución.
Anomalías de tiempo. El comando obliga al motor V8 a ejecutar tu código de forma síncrona cuando se crea el contexto de la página, antes de que el analizador HTML comience su trabajo. Inyectar scripts grandes introduce microrretrasos medibles durante la fase
document_start. Los sistemas antifraude miden el tiempo entre los eventos internos del navegador y pueden detectar estas brechas no naturales.Violaciones del ciclo de vida. Los complementos de ocultación no pueden simplemente eliminar los indicadores de automatización; en su lugar, dependen de ganchos (hooks) y anulaciones complejas. Los sistemas de protección pueden detectar que han aparecido objetos proxy complejos y propiedades anuladas en el objeto
windowinusualmente temprano, antes del eventoDOMContentLoadedo incluso antes de que se haya analizado la etiqueta<head>. Esto rompe el ciclo de vida natural de la página.Falta de aislamiento. Cualquier script inyectado a través del comando de CDP
addScriptToEvaluateOnNewDocumentse ejecuta en el contexto de ejecución principal de la página. Como resultado, tu código de suplantación y los scripts antifraude del sitio web comparten el mismo entorno. El más mínimo error o una variable expuesta accidentalmente puede ser suficiente para que el sistema de protección detecte la automatización.
No puedes abandonar por completo la suplantación, pero puedes cambiar la forma en que se entrega el código de suplantación. En lugar de inyectar código a través del protocolo de depuración, puedes usar el sistema de extensiones nativo del navegador.
Los navegadores fueron diseñados para permitir que las extensiones inyecten código de manera segura. Si empaquetas tu lógica de suplantación en una extensión Manifest V3 y la cargas al iniciar Puppeteer, los sistemas antifraude percibirán los tiempos e inyecciones como el comportamiento normal de una extensión del navegador.
Por ejemplo, puedes crear un directorio stealth-extension que contenga un archivo manifest.json:
{ "manifest_version": 3, "name": "My Custom Stealth", "version": "1.0", "content_scripts": [ { "matches": ["<all_urls>"], "js": ["inject.js"], "run_at": "document_start", "world": "MAIN" } ] }
{ "manifest_version": 3, "name": "My Custom Stealth", "version": "1.0", "content_scripts": [ { "matches": ["<all_urls>"], "js": ["inject.js"], "run_at": "document_start", "world": "MAIN" } ] }
Y cargarlo al lanzar Puppeteer en lugar de llamar a evaluateOnNewDocument:
const browser = await puppeteer.launch({ args: [ `--disable-extensions-except=${pathToExtension}`, `--load-extension=${pathToExtension}` ] });
const browser = await puppeteer.launch({ args: [ `--disable-extensions-except=${pathToExtension}`, `--load-extension=${pathToExtension}` ] });
Un segundo enfoque es evitar por completo los mecanismos de inyección de V8. Puedes usar un servidor proxy externo o la interceptación de solicitudes integrada de Puppeteer para modificar la respuesta HTML sin procesar sobre la marcha.
Inserta tu etiqueta <script> de suplantación como la primera línea dentro del elemento <head>. En este escenario, el código se ejecuta de forma natural como parte del proceso de análisis de documentos estándar del navegador, sin levantar sospechas en los sistemas de detección basados en el tiempo.
Si debes usar addScriptToEvaluateOnNewDocument, evita cargar complementos de ocultación monolíticos grandes. En su lugar, divide el proceso de suplantación en dos etapas.
Antes de que se cargue la página, elimina solo el marcador webdriver. Este código se ejecuta en una fracción de milisegundo y no crea anomalías detectables a través de la API de rendimiento.
// Inject a minimal payload before HTML parsing begins await page.evaluateOnNewDocument(() => { // Remove the most obvious automation marker Object.defineProperty(navigator, 'webdriver', { get: () => undefined, }); // No heavy WebGL or Canvas spoofing here! });
// Inject a minimal payload before HTML parsing begins await page.evaluateOnNewDocument(() => { // Remove the most obvious automation marker Object.defineProperty(navigator, 'webdriver', { get: () => undefined, }); // No heavy WebGL or Canvas spoofing here! });
Carga todas las demás modificaciones (como la suplantación de GPU, audio, complementos o fuentes) más tarde, después de que el navegador ya haya comenzado a renderizar la página. Esto se puede hacer mediante una llamada estándar a page.evaluate() o asociándolo al evento DOMContentLoaded.
// Navigate to the website await page.goto('https://target-site.com'); // The page is already loading and timing checks are complete. // Now it is safer to inject heavier spoofing logic. await page.evaluate(() => { // Spoof Canvas, WebGL, fonts, etc. const getParameter = WebGLRenderingContext.getParameter; WebGLRenderingContext.prototype.getParameter = function(parameter) { if (parameter === 37445) return 'Intel Inc.'; if (parameter === 37446) return 'Intel Iris OpenGL Engine'; return getParameter(parameter); }; });
// Navigate to the website await page.goto('https://target-site.com'); // The page is already loading and timing checks are complete. // Now it is safer to inject heavier spoofing logic. await page.evaluate(() => { // Spoof Canvas, WebGL, fonts, etc. const getParameter = WebGLRenderingContext.getParameter; WebGLRenderingContext.prototype.getParameter = function(parameter) { if (parameter === 37445) return 'Intel Inc.'; if (parameter === 37446) return 'Intel Iris OpenGL Engine'; return getParameter(parameter); }; });
Los sistemas de protección normalmente comprueban webdriver de forma síncrona al principio del ciclo de vida de la página, lo que hace que este enfoque sea eficaz contra tales comprobaciones. Las comprobaciones antifraude más avanzadas suelen ejecutarse de forma asíncrona una vez que la página ya se ha cargado. Para ese momento, el script de suplantación más pesado de la segunda etapa ya se ha cargado sin introducir retrasos en el inicio de la página.
El problema Network.setUserAgentOverride
Cambiar el User-Agent a través de CDP es fácil, pero el problema es que de esta manera solo se modifica la cabecera HTTP, mientras que otros indicadores ambientales permanecen intactos.
Como resultado, creas una inconsistencia crítica. El método Network.setUserAgentOverride no puede suplantar adecuadamente las propiedades de los objetos de navigator internos o las cabeceras de Client Hints específicas.
Un sistema de análisis puede ver un User-Agent móvil en la cabecera de la solicitud y, al mismo tiempo, detectar el comportamiento de renderizado de la API de escritorio y las cabeceras sec-ch-ua no coincidentes.
Nunca cambies la cadena del User-Agent de forma aislada. Si estás emulando un dispositivo, debes suplantar todo el conjunto de Client Hints, así como los sensores y características del hardware. En lugar de confiar únicamente en setUserAgent, utiliza los parámetros extendidos de CDP y proporciona un objeto userAgentMetadata completo. Recuerda también emular comportamientos específicos del dispositivo, como la emulación de pantalla táctil, cuando te hagas pasar por dispositivos móviles.
Escaneo de puertos TCP de depuración
Para controlar el navegador, Puppeteer lanza Chromium con un puerto abierto para la comunicación de WebSocket. De forma predeterminada, suele ser un puerto de depuración local como el clásico 9222 u otro puerto asignado al azar.
Un script antifraude se ejecuta directamente dentro del navegador del usuario. Desde dentro de tu propio sistema y en nombre de tu navegador, puede simplemente emitir una solicitud AJAX banal como:
http://127.0.0.1:9222/json/version.
Los sistemas de protección utilizan los llamados ataques de temporización o escaneo de redes locales a través de WebSockets. Si un script se conecta a un puerto de depuración estándar y recibe inmediatamente una respuesta del motor del navegador, puede inferir que el navegador está siendo controlado por un script de automatización.
Aleatorizar el puerto no es una solución completa, ya que los escáneres pueden sondear rangos de puertos completos. La solución más sencilla es dejar de usar por completo los puertos TCP para la comunicación entre Node.js y el navegador.
Puppeteer puede comunicarse con Chromium a través de tuberías (pipes) anónimas del sistema operativo en lugar de sockets de red. En este modo, no se abren puertos de depuración, lo que no deja nada que puedan escanear los sistemas antifraude.
Simplemente agrega el argumento pipe: true al lanzar el navegador. Esto te protege del escaneo de la red del host local.
Lograr resultados sin ser detectado
La invisibilidad perfecta de Puppeteer es fundamentalmente imposible porque cada forma de emulación introduce alguna desviación del comportamiento de un usuario genuino. Como se demostró anteriormente, esta es simplemente una realidad técnica.
Para casos de uso serios, los complementos predeterminados nunca son suficientes. Lograr un alto nivel de anonimato requiere un enfoque completamente diferente:
Parcheo de binarios de Chrome. Esto implica modificar directamente el ejecutable del navegador, por ejemplo con un editor hexadecimal. El objetivo es reemplazar las cadenas de protocolo codificadas por valores aleatorios dentro del propio binario. A diferencia de los complementos de ocultación, que dejan una breve ventana de vulnerabilidad entre el inicio y la inyección de JavaScript, las modificaciones binarias eliminan el problema en su origen.
Motores de navegador especializados. Las soluciones a nivel de arquitectura, como los navegadores antidetección, implementan la suplantación de huellas digitales y la ocultación de la automatización dentro del código base de C++ del motor Blink en lugar de hacerlo a través de inyecciones de JavaScript.
Evitar por completo CDP. La lógica de control se puede mover a extensiones personalizadas de Chrome que se comunican con un servidor de control a través de sus propios canales de WebSocket, lo que te permite cerrar los puertos de depuración.
Uso de navegadores antidetección
Las soluciones especializadas como los navegadores antidetección merecen una atención especial. Abordan el problema en cuestión modificando el código fuente de Chromium, afectando directamente al núcleo del navegador. Los indicadores obvios de automatización como navigator.webdriver se eliminan, por supuesto, durante la compilación binaria en lugar de ocultarse después.
Todo el trabajo pesado involucrado en la emulación del entorno ocurre bajo el capó. Cuando un script de protección solicita información de la GPU, como los valores del proveedor o renderizador de WebGL, el motor no necesita ejecutar un contenedor de JavaScript para suplantarlos, ya que el código C++ devuelve de forma nativa e instantánea los valores requeridos. Lo mismo se aplica a métricas más complejas. Es más, el usuario no interactúa directamente con ninguno de estos mecanismos, excepto posiblemente para configurar los parámetros necesarios antes de iniciar un perfil.
Desde la perspectiva de un sistema antifraude, dicho navegador parece ser un usuario normal. Al mismo tiempo, puedes controlar la huella digital a través de Puppeteer simplemente conectándolo al puerto abierto del navegador antidetección.
Detalles menos obvios y conclusiones
Usar el argumento
--disable-blink-features=AutomationControlledelimina el marcador básico dewebdriver, pero deja rastros indirectos.Forzar que
Log.enableyPerformance.enablepermanezcan deshabilitados reduce la telemetría disponible, pero mejora el sigilo general.El nuevo modo Headless (
--headless=new) unifica las arquitecturas de los navegadores estándar y headless, cambiando la forma en que se detectanClientRectsy el renderizado de fuentes, lo que hace que el comportamiento de renderizado parezca más natural.
Superar con éxito la detección no comienza instalando cien paquetes npm. Comienza por comprender cómo funciona realmente el motor del navegador.
La automatización de los navegadores modernos requiere una precisión a nivel de ingeniería. Las fugas de CDP no son errores; son características arquitectónicas de la tecnología. Cuanto más profundo sea tu conocimiento del navegador, más control tendrás sobre cada contexto de ejecución y más resistentes serán tus sistemas de automatización.
Mantén tu anonimato en línea con Octo Browser. Tu huella digital real no se puede rastrear.
¿Te gustaría probar Octo Browser con descuento?
Usa el código promocional OCTOSCRAPER para obtener un 30% de descuento en cualquier suscripción. Esta oferta solo es válida para nuevos usuarios.
¿Qué es CDP y por qué deja rastros digitales?
El protocolo Chrome DevTools proporciona acceso de bajo nivel a la arquitectura del navegador. Fue diseñado originalmente para la depuración, inspección y creación de perfiles, no para el raspado web oculto.
El protocolo opera a través de conexiones WebSocket que interactúan directamente con el motor V8. Cuando tu script envía un comando, como un clic o la navegación por una página, el navegador abre un socket local para la comunicación bidireccional. Este proceso genera inevitablemente registros internos, afecta la asignación de memoria y deja artefactos dentro del entorno del navegador aislado. Los sistemas de seguridad pueden analizar estos microcambios y patrones de sincronización para detectar comportamientos automatizados. Como resultado, la mera existencia de la conexión puede revelar la automatización del navegador.
Cómo difieren las fugas de CDP de la huella digital tradicional
Es importante entender que las fugas de CDP y las fugas de la huella digital del navegador representan dos vectores de detección fundamentalmente diferentes.
La generación de huellas digitales tradicional (Canvas, WebGL, fuentes) identifica características únicas del hardware y el comportamiento de renderizado. Las inconsistencias en la huella digital o los errores de suplantación permiten a los sistemas antibot detectar la manipulación y clasificar al usuario como sospechoso.
Las fugas de CDP revelan indicadores de comportamiento y estructurales de la ejecución del código. Exponen el hecho de que el navegador está siendo controlado de forma remota.
Puedes tener una huella digital WebGL perfectamente única, pero los indicadores de automatización pueden invalidar instantáneamente esa ventaja. Las comprobaciones de la huella digital del navegador requieren recursos y tiempo de procesamiento considerables, mientras que comprobar las variables de entorno o las pilas de llamadas es casi gratuito. Esta es precisamente la razón por la que los sistemas antifraude favorecen la detección basada en CDP. Les permite filtrar bots durante las comprobaciones básicas a nivel de protocolo, conservando los recursos del servidor que de otro modo se gastarían en análisis de comportamiento profundos más costosos.
Anatomía de las fugas del protocolo Chrome DevTools
Marcadores de contexto de ejecución
Una de las principales debilidades de Puppeteer radica en cómo exactamente ejecuta tu código dentro del navegador. Bajo el capó, el método page.evaluate() se basa en el comando de CDP Runtime.evaluate.
Cuando se inyecta un script en el navegador, las versiones modernas de Puppeteer generan una URL fuente específica asociada con ese fragmento de código. Si ocurre un error durante la ejecución del script, el motor V8 crea un rastreo de pila estándar que puede contener entradas como:
at pptr:evaluate;C:\Users\Admin\Projects\...\main.js:17:14
Al anular las funciones básicas del navegador, los sistemas antifraude pueden provocar intencionadamente errores invisibles e inspeccionar el objeto Error.stack. Pueden descubrir:
El prefijo
pptr:, una referencia directa a Puppeteer.Una ruta absoluta a un archivo en tu máquina local o servidor, que comienza con
C:\o/var/www/....
El navegador de un usuario real nunca ejecuta código de rutas de sistemas de archivos locales cuando visita un sitio web público. Por lo tanto, dichos marcadores representan una evidencia definitiva de automatización.

Cambiar tu dirección IP o suplantar las huellas de Canvas no resolverá este problema. Para ocultar estos marcadores, debes modificar la biblioteca misma o el entorno de ejecución del navegador.
La solución más confiable es eliminar el marcador pptr:evaluate directamente del código fuente de Puppeteer antes de que se envíen los comandos al navegador. Dado que buscar y editar archivos manualmente después de cada instalación de npm no es práctico, se puede usar un parche simple:
const fs = require('fs'); const path = require('path'); // Path to ExecutionContext.js in recent Puppeteer versions const targetFile = path.resolve(__dirname, 'node_modules/puppeteer-core/lib/cjs/puppeteer/cdp/ExecutionContext.js'); if (fs.existsSync(targetFile)) { let content = fs.readFileSync(targetFile, 'utf8'); // Replace the pptr:evaluate prefix with an anonymous call // and remove the local file path const patchedContent = content.replace(/pptr:evaluate;.*?\\n/g, 'anonymous:evaluation;\n'); fs.writeFileSync(targetFile, patchedContent, 'utf8'); console.log('Puppeteer patched successfully. pptr:evaluate markers removed.'); }
Si modificar node_modules no es una opción, los marcadores se pueden filtrar en tiempo de ejecución inyectando un script de suplantación antes de que se cargue la página de destino. El script anula el comportamiento del objeto Error nativo y limpia los rastreos de pila:
await page.evaluateOnNewDocument(() => { // Save the original Error constructor const NativeError = window.Error; window.Error = function(...args) { const err = new NativeError(...args); const originalStack = err.stack; if (originalStack) { Object.defineProperty(err, 'stack', { get: function() { // Break stack trace into strings and remove Puppeteer-related entries from it return originalStack .split('\n') .filter(line => !line.includes('pptr:evaluate')) .join('\n'); } }); } return err; }; // Restore the prototype chain to avoid detection window.Error.prototype = NativeError.prototype; });

Como resultado, en lugar de exponer las rutas de archivos locales, el rastreo de pila mostrará algo como esto
Vulnerabilidades de Page.addScriptToEvaluateOnNewDocument
Los intentos de ocultar la automatización del navegador, incluido el uso de complementos ocultos populares, suelen basarse en inyectar JavaScript de suplantación antes de que se cargue el sitio web de destino. En Puppeteer, esto se hace habitualmente a través del comando Page.addScriptToEvaluateOnNewDocument.
Sin embargo, el uso de este método en sí deja rastros claros en el entorno de ejecución.
Anomalías de tiempo. El comando obliga al motor V8 a ejecutar tu código de forma síncrona cuando se crea el contexto de la página, antes de que el analizador HTML comience su trabajo. Inyectar scripts grandes introduce microrretrasos medibles durante la fase
document_start. Los sistemas antifraude miden el tiempo entre los eventos internos del navegador y pueden detectar estas brechas no naturales.Violaciones del ciclo de vida. Los complementos de ocultación no pueden simplemente eliminar los indicadores de automatización; en su lugar, dependen de ganchos (hooks) y anulaciones complejas. Los sistemas de protección pueden detectar que han aparecido objetos proxy complejos y propiedades anuladas en el objeto
windowinusualmente temprano, antes del eventoDOMContentLoadedo incluso antes de que se haya analizado la etiqueta<head>. Esto rompe el ciclo de vida natural de la página.Falta de aislamiento. Cualquier script inyectado a través del comando de CDP
addScriptToEvaluateOnNewDocumentse ejecuta en el contexto de ejecución principal de la página. Como resultado, tu código de suplantación y los scripts antifraude del sitio web comparten el mismo entorno. El más mínimo error o una variable expuesta accidentalmente puede ser suficiente para que el sistema de protección detecte la automatización.
No puedes abandonar por completo la suplantación, pero puedes cambiar la forma en que se entrega el código de suplantación. En lugar de inyectar código a través del protocolo de depuración, puedes usar el sistema de extensiones nativo del navegador.
Los navegadores fueron diseñados para permitir que las extensiones inyecten código de manera segura. Si empaquetas tu lógica de suplantación en una extensión Manifest V3 y la cargas al iniciar Puppeteer, los sistemas antifraude percibirán los tiempos e inyecciones como el comportamiento normal de una extensión del navegador.
Por ejemplo, puedes crear un directorio stealth-extension que contenga un archivo manifest.json:
{ "manifest_version": 3, "name": "My Custom Stealth", "version": "1.0", "content_scripts": [ { "matches": ["<all_urls>"], "js": ["inject.js"], "run_at": "document_start", "world": "MAIN" } ] }
Y cargarlo al lanzar Puppeteer en lugar de llamar a evaluateOnNewDocument:
const browser = await puppeteer.launch({ args: [ `--disable-extensions-except=${pathToExtension}`, `--load-extension=${pathToExtension}` ] });
Un segundo enfoque es evitar por completo los mecanismos de inyección de V8. Puedes usar un servidor proxy externo o la interceptación de solicitudes integrada de Puppeteer para modificar la respuesta HTML sin procesar sobre la marcha.
Inserta tu etiqueta <script> de suplantación como la primera línea dentro del elemento <head>. En este escenario, el código se ejecuta de forma natural como parte del proceso de análisis de documentos estándar del navegador, sin levantar sospechas en los sistemas de detección basados en el tiempo.
Si debes usar addScriptToEvaluateOnNewDocument, evita cargar complementos de ocultación monolíticos grandes. En su lugar, divide el proceso de suplantación en dos etapas.
Antes de que se cargue la página, elimina solo el marcador webdriver. Este código se ejecuta en una fracción de milisegundo y no crea anomalías detectables a través de la API de rendimiento.
// Inject a minimal payload before HTML parsing begins await page.evaluateOnNewDocument(() => { // Remove the most obvious automation marker Object.defineProperty(navigator, 'webdriver', { get: () => undefined, }); // No heavy WebGL or Canvas spoofing here! });
Carga todas las demás modificaciones (como la suplantación de GPU, audio, complementos o fuentes) más tarde, después de que el navegador ya haya comenzado a renderizar la página. Esto se puede hacer mediante una llamada estándar a page.evaluate() o asociándolo al evento DOMContentLoaded.
// Navigate to the website await page.goto('https://target-site.com'); // The page is already loading and timing checks are complete. // Now it is safer to inject heavier spoofing logic. await page.evaluate(() => { // Spoof Canvas, WebGL, fonts, etc. const getParameter = WebGLRenderingContext.getParameter; WebGLRenderingContext.prototype.getParameter = function(parameter) { if (parameter === 37445) return 'Intel Inc.'; if (parameter === 37446) return 'Intel Iris OpenGL Engine'; return getParameter(parameter); }; });
Los sistemas de protección normalmente comprueban webdriver de forma síncrona al principio del ciclo de vida de la página, lo que hace que este enfoque sea eficaz contra tales comprobaciones. Las comprobaciones antifraude más avanzadas suelen ejecutarse de forma asíncrona una vez que la página ya se ha cargado. Para ese momento, el script de suplantación más pesado de la segunda etapa ya se ha cargado sin introducir retrasos en el inicio de la página.
El problema Network.setUserAgentOverride
Cambiar el User-Agent a través de CDP es fácil, pero el problema es que de esta manera solo se modifica la cabecera HTTP, mientras que otros indicadores ambientales permanecen intactos.
Como resultado, creas una inconsistencia crítica. El método Network.setUserAgentOverride no puede suplantar adecuadamente las propiedades de los objetos de navigator internos o las cabeceras de Client Hints específicas.
Un sistema de análisis puede ver un User-Agent móvil en la cabecera de la solicitud y, al mismo tiempo, detectar el comportamiento de renderizado de la API de escritorio y las cabeceras sec-ch-ua no coincidentes.
Nunca cambies la cadena del User-Agent de forma aislada. Si estás emulando un dispositivo, debes suplantar todo el conjunto de Client Hints, así como los sensores y características del hardware. En lugar de confiar únicamente en setUserAgent, utiliza los parámetros extendidos de CDP y proporciona un objeto userAgentMetadata completo. Recuerda también emular comportamientos específicos del dispositivo, como la emulación de pantalla táctil, cuando te hagas pasar por dispositivos móviles.
Escaneo de puertos TCP de depuración
Para controlar el navegador, Puppeteer lanza Chromium con un puerto abierto para la comunicación de WebSocket. De forma predeterminada, suele ser un puerto de depuración local como el clásico 9222 u otro puerto asignado al azar.
Un script antifraude se ejecuta directamente dentro del navegador del usuario. Desde dentro de tu propio sistema y en nombre de tu navegador, puede simplemente emitir una solicitud AJAX banal como:
http://127.0.0.1:9222/json/version.
Los sistemas de protección utilizan los llamados ataques de temporización o escaneo de redes locales a través de WebSockets. Si un script se conecta a un puerto de depuración estándar y recibe inmediatamente una respuesta del motor del navegador, puede inferir que el navegador está siendo controlado por un script de automatización.
Aleatorizar el puerto no es una solución completa, ya que los escáneres pueden sondear rangos de puertos completos. La solución más sencilla es dejar de usar por completo los puertos TCP para la comunicación entre Node.js y el navegador.
Puppeteer puede comunicarse con Chromium a través de tuberías (pipes) anónimas del sistema operativo en lugar de sockets de red. En este modo, no se abren puertos de depuración, lo que no deja nada que puedan escanear los sistemas antifraude.
Simplemente agrega el argumento pipe: true al lanzar el navegador. Esto te protege del escaneo de la red del host local.
Lograr resultados sin ser detectado
La invisibilidad perfecta de Puppeteer es fundamentalmente imposible porque cada forma de emulación introduce alguna desviación del comportamiento de un usuario genuino. Como se demostró anteriormente, esta es simplemente una realidad técnica.
Para casos de uso serios, los complementos predeterminados nunca son suficientes. Lograr un alto nivel de anonimato requiere un enfoque completamente diferente:
Parcheo de binarios de Chrome. Esto implica modificar directamente el ejecutable del navegador, por ejemplo con un editor hexadecimal. El objetivo es reemplazar las cadenas de protocolo codificadas por valores aleatorios dentro del propio binario. A diferencia de los complementos de ocultación, que dejan una breve ventana de vulnerabilidad entre el inicio y la inyección de JavaScript, las modificaciones binarias eliminan el problema en su origen.
Motores de navegador especializados. Las soluciones a nivel de arquitectura, como los navegadores antidetección, implementan la suplantación de huellas digitales y la ocultación de la automatización dentro del código base de C++ del motor Blink en lugar de hacerlo a través de inyecciones de JavaScript.
Evitar por completo CDP. La lógica de control se puede mover a extensiones personalizadas de Chrome que se comunican con un servidor de control a través de sus propios canales de WebSocket, lo que te permite cerrar los puertos de depuración.
Uso de navegadores antidetección
Las soluciones especializadas como los navegadores antidetección merecen una atención especial. Abordan el problema en cuestión modificando el código fuente de Chromium, afectando directamente al núcleo del navegador. Los indicadores obvios de automatización como navigator.webdriver se eliminan, por supuesto, durante la compilación binaria en lugar de ocultarse después.
Todo el trabajo pesado involucrado en la emulación del entorno ocurre bajo el capó. Cuando un script de protección solicita información de la GPU, como los valores del proveedor o renderizador de WebGL, el motor no necesita ejecutar un contenedor de JavaScript para suplantarlos, ya que el código C++ devuelve de forma nativa e instantánea los valores requeridos. Lo mismo se aplica a métricas más complejas. Es más, el usuario no interactúa directamente con ninguno de estos mecanismos, excepto posiblemente para configurar los parámetros necesarios antes de iniciar un perfil.
Desde la perspectiva de un sistema antifraude, dicho navegador parece ser un usuario normal. Al mismo tiempo, puedes controlar la huella digital a través de Puppeteer simplemente conectándolo al puerto abierto del navegador antidetección.
Detalles menos obvios y conclusiones
Usar el argumento
--disable-blink-features=AutomationControlledelimina el marcador básico dewebdriver, pero deja rastros indirectos.Forzar que
Log.enableyPerformance.enablepermanezcan deshabilitados reduce la telemetría disponible, pero mejora el sigilo general.El nuevo modo Headless (
--headless=new) unifica las arquitecturas de los navegadores estándar y headless, cambiando la forma en que se detectanClientRectsy el renderizado de fuentes, lo que hace que el comportamiento de renderizado parezca más natural.
Superar con éxito la detección no comienza instalando cien paquetes npm. Comienza por comprender cómo funciona realmente el motor del navegador.
La automatización de los navegadores modernos requiere una precisión a nivel de ingeniería. Las fugas de CDP no son errores; son características arquitectónicas de la tecnología. Cuanto más profundo sea tu conocimiento del navegador, más control tendrás sobre cada contexto de ejecución y más resistentes serán tus sistemas de automatización.
Mantente al día de las últimas noticias sobre Octo Browser
Al hacer clic en el botón, aceptas nuestra Política de privacidad.
Mantente al día de las últimas noticias sobre Octo Browser
Al hacer clic en el botón, aceptas nuestra Política de privacidad.
Mantente al día de las últimas noticias sobre Octo Browser
Al hacer clic en el botón, aceptas nuestra Política de privacidad.

Únete a Octo Browser ahora
O contacta al servicio al cliente en cualquier momento si tienes alguna pregunta.

Únete a Octo Browser ahora
O contacta al servicio al cliente en cualquier momento si tienes alguna pregunta.
Únete a Octo Browser ahora
O contacta al servicio al cliente en cualquier momento si tienes alguna pregunta.