javascript - example - ¿Puede un sitio web detectar cuándo está usando selenio con chromedriver?
selenium chrome example java (17)
partial interface Navigator { readonly attribute boolean webdriver; };
El atributo IDL de webdriver de la interfaz del navegador debe devolver el valor de la bandera activa de webdriver, que inicialmente es falso.
Esta propiedad permite que los sitios web determinen que WebDriver controla el agente de usuario y se puede usar para ayudar a mitigar los ataques de denegación de servicio.
Tomado directamente del Borrador de WebDriver del Editor del W3C 2017 . Esto implica en gran medida que, al menos, las futuras iteraciones de los controladores de selenio serán identificables para evitar el mal uso. En última instancia, es difícil saber sin el código fuente, qué es exactamente lo que hace que el controlador de Chrome en específico sea detectable.
He estado probando Selenium con Chromedriver y noté que algunas páginas pueden detectar que estás usando Selenium a pesar de que no hay ninguna automatización. Incluso cuando estoy navegando manualmente solo usando Chrome a través de Selenium y Xephyr, a menudo recibo una página que dice que se detectó actividad sospechosa. Revisé mi agente de usuario y la huella digital de mi navegador, y todos son exactamente idénticos al navegador Chrome normal.
Cuando navego por estos sitios en Chrome normal, todo funciona bien, pero en el momento en que uso Selenium me detectan.
En teoría, chromedriver y Chrome deberían verse literalmente exactamente igual para cualquier servidor web, pero de alguna manera pueden detectarlo.
Si quieres un código de prueba prueba esto:
from pyvirtualdisplay import Display
from selenium import webdriver
display = Display(visible=1, size=(1600, 902))
display.start()
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument(''--disable-extensions'')
chrome_options.add_argument(''--profile-directory=Default'')
chrome_options.add_argument("--incognito")
chrome_options.add_argument("--disable-plugins-discovery");
chrome_options.add_argument("--start-maximized")
driver = webdriver.Chrome(chrome_options=chrome_options)
driver.delete_all_cookies()
driver.set_window_size(800,800)
driver.set_window_position(0,0)
print ''arguments done''
driver.get(''http://stubhub.com'')
Si navega por stubhub, será redirigido y ''bloqueado'' dentro de una o dos solicitudes. He estado investigando esto y no puedo entender cómo pueden decir que un usuario está usando Selenium.
¿Cómo lo hicieron?
EDITAR ACTUALIZACIÓN:
Instalé el complemento Selenium IDE en Firefox y me prohibieron cuando fui a stubhub.com en el navegador normal de Firefox con solo el complemento adicional.
EDITAR:
Cuando uso Fiddler para ver las solicitudes HTTP que se envían de un lado a otro, he notado que las solicitudes de ''navegador falso'' a menudo tienen ''no-cache'' en el encabezado de respuesta.
EDITAR:
resultados como este ¿Hay alguna manera de detectar que estoy en una página de Selenium Webdriver desde Javascript sugiere que no debería haber forma de detectar cuando está utilizando un webdriver? Pero esta evidencia sugiere lo contrario.
EDITAR:
El sitio carga una huella digital en sus servidores, pero lo verifiqué y la huella digital de selenio es idéntica a la huella digital cuando se usa Chrome.
EDITAR:
Esta es una de las cargas útiles de huellas digitales que envían a sus servidores
{"appName":"Netscape","platform":"Linuxx86_64","cookies":1,"syslang":"en-US","userlang":"en-US","cpu":"","productSub":"20030107","setTimeout":1,"setInterval":1,"plugins":{"0":"ChromePDFViewer","1":"ShockwaveFlash","2":"WidevineContentDecryptionModule","3":"NativeClient","4":"ChromePDFViewer"},"mimeTypes":{"0":"application/pdf","1":"ShockwaveFlashapplication/x-shockwave-flash","2":"FutureSplashPlayerapplication/futuresplash","3":"WidevineContentDecryptionModuleapplication/x-ppapi-widevine-cdm","4":"NativeClientExecutableapplication/x-nacl","5":"PortableNativeClientExecutableapplication/x-pnacl","6":"PortableDocumentFormatapplication/x-google-chrome-pdf"},"screen":{"width":1600,"height":900,"colorDepth":24},"fonts":{"0":"monospace","1":"DejaVuSerif","2":"Georgia","3":"DejaVuSans","4":"TrebuchetMS","5":"Verdana","6":"AndaleMono","7":"DejaVuSansMono","8":"LiberationMono","9":"NimbusMonoL","10":"CourierNew","11":"Courier"}}
Es idéntico en selenio y en cromo.
EDITAR:
Las VPN funcionan para un solo uso, pero se detectan después de cargar la primera página. Claramente se está ejecutando javascript para detectar Selenium.
Resultado de ofuscación de JavaScripts
He comprobado el código fuente de chromedriver.
Eso inyecta algunos archivos javascript al navegador.
Todos los archivos javascript de este enlace se inyectan en las páginas web:
https://chromium.googlesource.com/chromium/src/+/master/chrome/test/chromedriver/js/
Así que utilicé ingeniería inversa y
ofusqué
los archivos js mediante edición hexadecimal.
Ahora estaba seguro de que no se usaron más variables de JavaScript, nombres de funciones y cadenas fijas para descubrir la actividad de selenio.
¡Pero todavía algunos sitios y reCaptcha detectan selenio!
Tal vez verifican las modificaciones causadas por la ejecución de chromedriver js :)
Editar 1:
Modificación de parámetros de ''navegador'' de Chrome
Descubrí que hay algunos parámetros en ''navegador'' que descubren brevemente el uso de chromedriver. Estos son los parámetros:
- "navigator.webdriver" En modo no automatizado está ''indefinido''. En modo automatizado es ''verdadero''.
- "navigator.plugins" En Chrome sin cabeza tiene 0 longitud. Así que agregué algunos elementos falsos para engañar el proceso de comprobación de la longitud del complemento.
- " navigator.languages" se configuró en el valor predeterminado de Chrome ''["en-US", "en", "es"]''.
Entonces, lo que necesitaba era una extensión de Chrome para ejecutar JavaScript en las páginas web. Hice una extensión con el código js proporcionado en el artículo y usé otro artículo para agregar la extensión comprimida a mi proyecto. He cambiado con éxito los valores; ¡Pero todavía nada ha cambiado!
No encontré otras variables como estas, pero eso no significa que no existan. Todavía reCaptcha detecta chromedriver, por lo que debería haber más variables para cambiar. El siguiente paso debería ser la ingeniería inversa de los servicios de detectores que no quiero hacer.
¡Ahora no estoy seguro de si vale la pena dedicar más tiempo a este proceso de automatización o buscar métodos alternativos!
Para usuarios de Mac
Reemplazar variable
cdc_
usando Vim o Perl
Puede usar
vim
, o como @Vic Seedoubleyew ha señalado en la respuesta de @ Erti-Chris Eelmaa,
perl
, para reemplazar la variable
chromedriver
en
chromedriver
(
consulte la publicación de @ Erti-Chris Eelmaa para obtener más información sobre esa variable
).
El uso de
vim
o
perl
evita que tenga que volver a compilar el código fuente o utilizar un editor hexadecimal.
Asegúrese de hacer una copia del
chromedriver
original antes de intentar editarlo.
Además, los siguientes métodos se probaron en la
chromedriver version 2.41.578706
.
Usando Vim
vim /path/to/chromedriver
Después de ejecutar la línea anterior, probablemente verá un montón de galimatías. Haz lo siguiente:
-
Busque
cdc_
escribiendo/cdc_
y presionando/cdc_
. -
Habilite la edición presionando
a
. -
Elimine cualquier cantidad de
$cdc_lasutopfhvcZLmcfl
y reemplace lo que se eliminó con una cantidad igual de caracteres. Si no lo hace,chromedriver
fallará. -
Una vez que haya terminado de editar, presione
esc
. -
Para guardar los cambios y salir, escriba
:wq!
y presionereturn
. -
Si no desea guardar los cambios, pero desea salir, escriba
:q!
y presionereturn
. - Ya terminaste
Vaya al
chromedriver
alterado y haga doble clic en él.
Se debe abrir una ventana de
terminal
.
Si no ve
killed
en la salida, alteró con éxito el controlador.
Usando Perl
La línea a continuación reemplaza
cdc_
con
dog_
:
perl -pi -e ''s/cdc_/dog_/g'' /path/to/chromedriver
Asegúrese de que la cadena de reemplazo tenga el mismo número de caracteres que la cadena de búsqueda; de lo contrario, el
chromedriver
fallará.
Explicación de Perl
s///g
indica que desea buscar una cadena y reemplazarla globalmente con otra cadena (reemplaza todas las ocurrencias).
por ejemplo,
s/string/replacment/g
Entonces,
s///
denota buscar y reemplazar una cadena.
cdc_
es la cadena de búsqueda.
dog_
es la cadena de reemplazo.
g
es la clave global, que reemplaza cada aparición de la cadena.
Cómo verificar si el reemplazo de Perl funcionó
La siguiente línea imprimirá cada aparición de la cadena de búsqueda
cdc_
:
perl -ne ''while(/cdc_/g){print "$&/n";}'' /path/to/chromedriver
Si esto no devuelve nada, entonces
cdc_
ha sido reemplazado.
Por el contrario, puede usar esto:
perl -ne ''while(/dog_/g){print "$&/n";}'' /path/to/chromedriver
para ver si su cadena de reemplazo,
dog_
, está ahora en el binario
chromedriver
.
Si es así, la cadena de reemplazo se imprimirá en la consola.
Vaya al
chromedriver
alterado y haga doble clic en él.
Se debe abrir una ventana de
terminal
.
Si no ve
killed
en la salida, alteró con éxito el controlador.
Terminando
Después de alterar el binario de
chromedriver
, asegúrese de que el nombre del binario de
chromedriver
alterado sea
chromedriver
y que el binario original se mueva de su ubicación original o
chromedriver
nombre.
Mi experiencia con este método
Anteriormente me detectaban en un sitio web mientras intentaba iniciar sesión, pero después de reemplazar
cdc_
con una cadena de igual tamaño, pude iniciar sesión. Como otros han dicho, si ya lo han detectado, es posible que se bloquee por Una gran cantidad de otras razones, incluso después de usar este método.
Por lo tanto, es posible que deba intentar acceder al sitio que lo estaba detectando utilizando una VPN, una red diferente o lo que sea que tenga.
Además de la gran respuesta de
@ Erti-Chris Eelmaa
: hay un molesto
window.navigator.webdriver
y es de solo lectura.
Evento si cambia su valor a
false
, seguirá siendo
true
.
Es por eso que aún se puede detectar el navegador controlado por software automatizado.
MDN
La variable es administrada por la bandera
--enable-automation
en Chrome.
El chromedriver lanza Chrome con esa bandera y Chrome establece el
window.navigator.webdriver
en
true
.
Lo puedes encontrar
here
.
Debe agregar a "excluir interruptores" la bandera.
Por ejemplo (golang):
//Fools the website into believing a human is navigating it
((JavascriptExecutor)driver).executeScript("window.key = /"blahblah/";");
Algunos sitios están detectando esto:
function d() {
try {
if (window.document.$cdc_asdjflasutopfhvcZLmcfl_.cache_)
return !0
} catch (e) {}
try {
//if (window.document.documentElement.getAttribute(decodeURIComponent("%77%65%62%64%72%69%76%65%72")))
if (window.document.documentElement.getAttribute("webdriver"))
return !0
} catch (e) {}
try {
//if (decodeURIComponent("%5F%53%65%6C%65%6E%69%75%6D%5F%49%44%45%5F%52%65%63%6F%72%64%65%72") in window)
if ("_Selenium_IDE_Recorder" in window)
return !0
} catch (e) {}
try {
//if (decodeURIComponent("%5F%5F%77%65%62%64%72%69%76%65%72%5F%73%63%72%69%70%74%5F%66%6E") in document)
if ("__webdriver_script_fn" in document)
return !0
} catch (e) {}
Básicamente, la forma en que funciona la detección de selenio es que prueban las variables de JavaScript predefinidas que aparecen cuando se ejecuta con selenio.
Los scripts de detección de bot generalmente se ven en cualquier cosa que contenga la palabra "selenium" / "webdriver" en cualquiera de las variables (en el objeto de la ventana), y también documentan variables llamadas
$cdc_
y
$wdc_
.
Por supuesto, todo esto depende del navegador en el que se encuentre.
Todos los diferentes navegadores exponen diferentes cosas.
Para mí, utilicé Chrome, así
que todo lo que tenía que
hacer era asegurarme de que
$cdc_
ya no existiera como variable de documento, y listo (descargue el código fuente de chromedriver, modifique chromedriver y vuelva a compilar
$cdc_
con un nombre diferente. )
esta es la función que modifiqué en chromedriver:
call_function.js:
function getPageCache(opt_doc) {
var doc = opt_doc || document;
//var key = ''$cdc_asdjflasutopfhvcZLmcfl_'';
var key = ''randomblabla_'';
if (!(key in doc))
doc[key] = new Cache();
return doc[key];
}
(tenga en cuenta el comentario, todo lo que hice convertí
$cdc_
a
randomblabla_
.
Aquí hay un pseudocódigo que muestra algunas de las técnicas que las redes bot pueden usar:
runBotDetection = function () {
var documentDetectionKeys = [
"__webdriver_evaluate",
"__selenium_evaluate",
"__webdriver_script_function",
"__webdriver_script_func",
"__webdriver_script_fn",
"__fxdriver_evaluate",
"__driver_unwrapped",
"__webdriver_unwrapped",
"__driver_evaluate",
"__selenium_unwrapped",
"__fxdriver_unwrapped",
];
var windowDetectionKeys = [
"_phantom",
"__nightmare",
"_selenium",
"callPhantom",
"callSelenium",
"_Selenium_IDE_Recorder",
];
for (const windowDetectionKey in windowDetectionKeys) {
const windowDetectionKeyValue = windowDetectionKeys[windowDetectionKey];
if (window[windowDetectionKeyValue]) {
return true;
}
};
for (const documentDetectionKey in documentDetectionKeys) {
const documentDetectionKeyValue = documentDetectionKeys[documentDetectionKey];
if (window[''document''][documentDetectionKeyValue]) {
return true;
}
};
for (const documentKey in window[''document'']) {
if (documentKey.match(//$[a-z]dc_/) && window[''document''][documentKey][''cache_'']) {
return true;
}
}
if (window[''external''] && window[''external''].toString() && (window[''external''].toString()[''indexOf''](''Sequentum'') != -1)) return true;
if (window[''document''][''documentElement''][''getAttribute''](''selenium'')) return true;
if (window[''document''][''documentElement''][''getAttribute''](''webdriver'')) return true;
if (window[''document''][''documentElement''][''getAttribute''](''driver'')) return true;
return false;
};
de acuerdo con el usuario @szx, también es posible simplemente abrir chromedriver.exe en el editor hexadecimal, y simplemente hacer el reemplazo manualmente, sin hacer ninguna compilación.
Como ya hemos descubierto en la pregunta y las respuestas publicadas, hay un servicio anti-scraping y un servicio de detección de Bot llamado "Distil Networks" en juego aquí. Y, según la interview del CEO de la compañía:
A pesar de que pueden crear nuevos bots, descubrimos una forma de identificar a Selenium con la herramienta que están utilizando, por lo que estamos bloqueando a Selenium sin importar cuántas veces iteren en ese bot . Lo estamos haciendo ahora con Python y muchas tecnologías diferentes. Una vez que vemos emerger un patrón de un tipo de bot, trabajamos para aplicar ingeniería inversa a la tecnología que usan e identificarlo como malicioso.
Tomará tiempo y desafíos adicionales comprender cómo exactamente están detectando Selenium, pero qué podemos decir con seguridad en este momento:
- no está relacionado con las acciones que realiza con selenio: una vez que navega por el sitio, se lo detecta y lo prohíbe de inmediato. Intenté agregar retrasos aleatorios artificiales entre acciones, hacer una pausa después de cargar la página, nada ayudó
- tampoco se trata de la huella digital del navegador: lo probé en varios navegadores con perfiles limpios y no en modos de incógnito; nada ayudó
- dado que, de acuerdo con la sugerencia de la entrevista, esto era "ingeniería inversa", sospecho que esto se hace con algún código JS que se ejecuta en el navegador que revela que este es un navegador automatizado a través del controlador web de selenio
Decidí publicarlo como respuesta, ya que claramente:
¿Puede un sitio web detectar cuándo está usando selenio con chromedriver?
Si.
Además, con lo que no he experimentado es con selenio y versiones de navegador anteriores: en teoría, podría haber algo implementado / agregado al selenio en un momento determinado en el que actualmente se basa el detector de bot de Distil Networks. Entonces, si este es el caso, podríamos detectar (sí, vamos a detectar el detector) en qué punto / versión se realizó un cambio relevante, buscar en el registro de cambios y conjuntos de cambios y, tal vez, esto podría darnos más información sobre dónde buscar y qué es lo que usan para detectar un navegador webdriver. Es solo una teoría que necesita ser probada.
Ejemplo de cómo se implementa en wellsfargo.com:
try {
if (window.document.documentElement.getAttribute("webdriver")) return !+[]
} catch (IDLMrxxel) {}
try {
if ("_Selenium_IDE_Recorder" in window) return !+""
} catch (KknKsUayS) {}
try {
if ("__webdriver_script_fn" in document) return !+""
Escribe una página html con el siguiente código. Verá que en el DOM selenio aplica un atributo webdriver en el HTML externo
package main
import (
"github.com/tebeka/selenium"
"github.com/tebeka/selenium/chrome"
)
func main() {
caps := selenium.Capabilities{
"browserName": "chrome",
}
chromeCaps := chrome.Capabilities{
Path: "/path/to/chrome-binary",
ExcludeSwitches: []string{"enable-automation"},
}
caps.AddChrome(chromeCaps)
wd, err := selenium.NewRemote(caps, fmt.Sprintf("http://localhost:%d/wd/hub", 4444))
}
He encontrado cambiar la variable "clave" de JavaScript de esta manera:
//Fools the website into believing a human is navigating it ((JavascriptExecutor)driver).executeScript("window.key = /"blahblah/";");
funciona para algunos sitios web cuando se utiliza Selenium Webdriver junto con Google Chrome, ya que muchos sitios verifican esta variable para evitar que Selenium lo descarte.
Incluso si está enviando todos los datos correctos (por ejemplo, Selenium no aparece como una extensión, tiene una resolución razonable / profundidad de bits, etc.), hay una serie de servicios y herramientas que muestran el comportamiento del visitante para determinar si actor es un usuario o un sistema automatizado.
Por ejemplo, visitar un sitio e inmediatamente realizar alguna acción moviendo el mouse directamente al botón correspondiente, en menos de un segundo, es algo que ningún usuario realmente haría.
También podría ser útil como herramienta de depuración para usar un sitio como https://panopticlick.eff.org/ para verificar cuán único es su navegador; también lo ayudará a verificar si hay algún parámetro específico que indique que está ejecutando en Selenium.
Intente usar selenio con un perfil de usuario específico de Chrome, de esa manera puede usarlo como usuario específico y definir cualquier cosa que desee, al hacerlo se ejecutará como un usuario ''real'', observe el proceso de Chrome con algún explorador de procesos y Verás la diferencia con las etiquetas.
Por ejemplo:
username = os.getenv("USERNAME")
userProfile = "C://Users//" + username + "//AppData//Local//Google//Chrome//User Data//Default"
options = webdriver.ChromeOptions()
options.add_argument("user-data-dir={}".format(userProfile))
# add here any tag you want.
options.add_experimental_option("excludeSwitches", ["ignore-certificate-errors", "safebrowsing-disable-download-protection", "safebrowsing-disable-auto-update", "disable-client-side-phishing-detection"])
chromedriver = "C:/Python27/chromedriver/chromedriver.exe"
os.environ["webdriver.chrome.driver"] = chromedriver
browser = webdriver.Chrome(executable_path=chromedriver, chrome_options=options)
lista de etiquetas de Chrome here
La detección de bot que he visto parece más sofisticada o al menos diferente de lo que he leído en las respuestas a continuación.
EXPERIMENTO 1:
- Abro un navegador y una página web con Selenium desde una consola Python.
- El mouse ya está en una ubicación específica donde sé que aparecerá un enlace una vez que se cargue la página. Nunca muevo el mouse.
- Presiono el botón izquierdo del mouse una vez (esto es necesario para enfocar desde la consola donde Python se está ejecutando al navegador).
- Presiono el botón izquierdo del mouse nuevamente (recuerde, el cursor está sobre un enlace dado).
- El enlace se abre normalmente, como debería.
Experimento 2:
-
Como antes, abro un navegador y la página web con Selenium desde una consola Python.
-
Esta vez, en lugar de hacer clic con el mouse, uso Selenium (en la consola de Python) para hacer clic en el mismo elemento con un desplazamiento aleatorio.
-
El enlace no se abre, pero me llevan a una página de registro.
TRASCENDENCIA:
- abrir un navegador web a través de Selenium no me impide aparecer como humano
- mover el mouse como un humano no es necesario para ser clasificado como humano
- Al hacer clic en algo a través de Selenium con un desplazamiento aún se genera la alarma
Parece misterioso, pero supongo que pueden determinar si una acción se origina en Selenium o no, mientras que no les importa si el navegador se abrió a través de Selenium o no. ¿O pueden determinar si la ventana tiene foco? Sería interesante saber si alguien tiene alguna idea.
Me parece que la forma más sencilla de hacerlo con Selenium es interceptar el XHR que envía la huella digital del navegador.
Pero dado que este es un problema solo de selenio, es mejor usar otra cosa. Se supone que el selenio hace que cosas como esta sean más fáciles, no mucho más difíciles.
Parece que están detrás de un firewall de aplicaciones web. Eche un vistazo a modsecurity y owasp para ver cómo funcionan. En realidad, lo que está preguntando es cómo hacer la evasión de detección de bot. Para eso no está el controlador web de selenio. Es para probar que su aplicación web no afecta a otras aplicaciones web. Es posible, pero básicamente, tendría que mirar lo que busca un WAF en su conjunto de reglas y evitarlo específicamente con selenio si puede. Incluso entonces, podría no funcionar porque no sabes qué WAF están usando. Hiciste el primer paso correcto, que es fingir el agente de usuario. Sin embargo, si eso no funcionó, entonces hay un WAF en su lugar y probablemente deba ser más complicado.
Editar: Punto tomado de otra respuesta. Asegúrese de que su agente de usuario se esté configurando correctamente primero. Tal vez haga que llegue a un servidor web local o huela el tráfico que sale.
Se dice que Firefox establece
window.navigator.webdriver === true
si trabaja con un controlador web.
Eso fue de acuerdo con una de las especificaciones más antiguas (por ejemplo:
archive.org
), pero no pude encontrarla en la
nueva,
excepto por una redacción muy vaga en los apéndices.
Una prueba de esto está en el código de selenio en el archivo
fingerprint_test.js
donde el comentario al final dice "Actualmente solo implementado en Firefox" pero no pude identificar ningún código en esa dirección con un simple
grep
, ni en el actual árbol de lanzamiento de Firefox (41.0.2) ni en el árbol de cromo.
También encontré un comentario para una confirmación anterior con respecto a las huellas digitales en el controlador de
Firefox b82512999938 de enero de 2015
.
Ese código todavía está en el Selenium GIT-master descargado ayer en
javascript/firefox-driver/extension/content/server.js
con un comentario que enlaza con el apéndice redactado de forma ligeramente diferente en la especificación actual del controlador web w3c.
Una cosa más que encontré es que algunos sitios web utilizan una plataforma que verifica el Agente de usuario. Si el valor contiene: "HeadlessChrome", el comportamiento puede ser extraño cuando se utiliza el modo sin cabeza.
La solución para eso será anular el valor del agente de usuario, por ejemplo en Java:
<html>
<head>
<script type="text/javascript">
<!--
function showWindow(){
javascript:(alert(document.documentElement.outerHTML));
}
//-->
</script>
</head>
<body>
<form>
<input type="button" value="Show outerHTML" onclick="showWindow()">
</form>
</body>
</html>