Detectando visitantes que usam PhantomJS

Ecossistema F5 | 22 de janeiro de 2015


Hoje em dia, muitos incidentes de segurança na web envolvem automação. Ataques de raspagem de dados da web, reutilização de senhas e fraude de cliques são realizados por agentes mal-intencionados que tentam imitar usuários reais e, portanto, procuram parecer que estão acessando por meio de um navegador. Como proprietário de um site, você quer garantir que seu conteúdo seja disponibilizado a pessoas; como provedor de serviços web, você quer que o acesso programático ao seu conteúdo seja feito por meio da sua API, em vez de ser extraído pela sua interface web, que é mais pesada e menos estável.

Supondo que você tenha verificações básicas para visitantes semelhantes ao cURL, a próxima etapa razoável é garantir que os visitantes estejam usando navegadores reais, com interface gráfica — e não navegadores sem interface gráfica, como PhantomJS e SlimerJS.

Neste artigo, vamos demonstrar algumas técnicas para identificar acessos feitos pelo PhantomJS. Decidimos nos concentrar no PhantomJS porque ele é o ambiente de navegador sem interface gráfica mais popular, mas muitos dos conceitos que abordaremos também se aplicam ao SlimerJS e a outras ferramentas.

OBSERVAÇÃO: As técnicas apresentadas neste artigo se aplicam tanto ao PhantomJS 1.x quanto ao 2.x, salvo indicação explícita em contrário. Para começar: é possível detectar o PhantomJS sem sequer responder a ele?

Pilha HTTP

Como você já deve saber, o PhantomJS é desenvolvido com base no framework Qt. A forma como o Qt implementa a pilha HTTP faz com que ele se diferencie de outros navegadores modernos.

Primeiro, vamos dar uma olhada no Chrome, que envia os seguintes cabeçalhos:

PhantomJS

No PhantomJS, no entanto, a mesma solicitação HTTP tem esta aparência:

PhantomJS

Você notará que os cabeçalhos do PhantomJS diferem dos do Chrome (e, como se constata, dos de todos os outros navegadores modernos) em alguns aspectos sutis:

  • O cabeçalho Host aparece por último
  • O valor do cabeçalho Connection combina letras maiúsculas e minúsculas
  • O único valor de Accept-Encoding é gzip
  • O User-Agent contém “PhantomJS”

Ao verificar essas anomalias nos cabeçalhos HTTP no servidor, deve ser possível identificar um navegador PhantomJS.

Mas será que é seguro confiar nesses valores? Se um invasor usar um proxy para reescrever os cabeçalhos antes que eles cheguem ao navegador sem interface gráfica, poderá modificá-los para que pareçam vir de um navegador moderno comum.

Parece que lidar com esse problema exclusivamente no servidor não é uma solução infalível. Então, vamos ver o que pode ser feito no lado do cliente usando o ambiente JavaScript do PhantomJS.

Verificação do User-Agent no lado do cliente

Talvez não possamos confiar no valor de User-Agent fornecido via HTTP, mas e no lado do cliente?

PhantomJS

Infelizmente, é igualmente trivial alterar os valores do cabeçalho user-agent e de navigator.userAgent no PhantomJS, portanto isso talvez não seja suficiente.

Plugins

navigator.plugins contém uma lista dos plugins presentes no navegador. Entre os plugins mais comuns estão Flash, ActiveX, suporte a applets Java e o “Auxiliar de Navegador Padrão”, um plugin que indica se este é o navegador padrão no OS X. Em nossa pesquisa, a maioria das instalações novas dos navegadores mais comuns inclui pelo menos um plugin padrão — até mesmo em dispositivos móveis.

Isso é diferente do PhantomJS, que não implementa nenhum plugin nem oferece uma maneira de adicionar um (usando a API do PhantomJS).

A verificação a seguir pode ser útil nesse caso:

PhantomJS

Por outro lado, é bastante simples falsificar essa lista de plugins modificando o ambiente JavaScript do PhantomJS antes que a página seja carregada.

Também não é difícil imaginar uma versão personalizada do PhantomJS com plugins reais e funcionais. Isso é mais fácil do que parece, pois o framework Qt, no qual o PhantomJS se baseia, fornece uma API nativa para implementar plugins.

Temporização

Outro ponto interessante é como o PhantomJS suprime as caixas de diálogo do JavaScript:

PhantomJS

Após realizar várias medições, parece que, se a caixa de diálogo de alerta for fechada em até 15 milissegundos, provavelmente o navegador não está sendo controlado por uma pessoa. No entanto, usar essa abordagem significa incomodar usuários reais com um alerta que eles terão de fechar manualmente.

Propriedades globais

O PhantomJS 1.x expõe duas propriedades no objeto global:

PhantomJS

No entanto, essas propriedades fazem parte de um recurso experimental e podem mudar no futuro.

Ausência de recursos do mecanismo JavaScript

Atualmente, o PhantomJS 1.x e 2.x usam mecanismos WebKit desatualizados, o que significa que alguns recursos presentes em navegadores mais recentes não existem no PhantomJS. Isso também se aplica ao mecanismo JavaScript — algumas propriedades e métodos nativos são diferentes ou não estão disponíveis no PhantomJS.

Um desses métodos é Function.prototype.bind, que não está disponível no PhantomJS 1.x e em versões anteriores. O exemplo a seguir verifica se bind está presente e se não foi falsificado no ambiente de execução.

PhantomJS

Este código é um pouco complexo demais para ser explicado em detalhes aqui, mas você pode saber mais em nossa apresentação.

Rastreamentos de pilha

Os erros gerados pelo código JavaScript avaliado pelo PhantomJS por meio do comando evaluate contêm um rastreamento de pilha que pode ser identificado de forma única, permitindo-nos identificar o navegador sem interface gráfica.

Por exemplo, suponha que o PhantomJS chame evaluate no seguinte código:

PhantomJS

Observe que este exemplo usa uma função personalizada indexOfString(), cuja implementação fica como exercício para o leitor, pois o método nativo String.prototype.indexOf pode ser manipulado pelo PhantomJS para sempre retornar um resultado negativo.

Agora, como fazer um script do PhantomJS avaliar esse código? Uma técnica é sobrescrever algumas funções da API do DOM usadas com frequência e que provavelmente serão chamadas. Por exemplo, o código abaixo sobrescreve document.querySelectorAll para inspecionar o rastreamento de pilha do navegador:

Resumo

Neste artigo, analisamos 7 técnicas diferentes para identificar o PhantomJS, tanto no servidor quanto por meio da execução de código no ambiente JavaScript do cliente do PhantomJS. Ao combinar os resultados da detecção com um mecanismo de resposta robusto — por exemplo, tornando uma página dinâmica inerte ou invalidando o cookie da sessão atual —, você pode criar um obstáculo significativo para visitantes que usam o PhantomJS. No entanto, tenha sempre em mente que essas técnicas não são infalíveis e que um adversário sofisticado acabará conseguindo contorná-las.

Para saber mais, recomendamos assistir a esta gravação da nossa apresentação na AppSec USA 2014 (slides). Também criamos um repositório no GitHub com exemplos de implementação — e possíveis formas de contornar — as técnicas apresentadas aqui.

Agradecemos pela leitura e boa caçada.

Colaboradores

Sergey Shekyan – @sshekyan
Ben Vinegar – @bentlegen
Bei Zhang – @ikarienator

Compartilhar

Publicações relacionadas no blog

Entrega e proteção de agentes de IA em fábricas de IA: F5 para a arquitetura de referência NVIDIA OpenShell para agentes de IA seguros
Ecossistema F5 | 21/10/2026

Entrega e proteção de agentes de IA em fábricas de IA: F5 para a arquitetura de referência NVIDIA OpenShell para agentes de IA seguros

As soluções da F5 ampliam a Arquitetura de Referência NVIDIA OpenShell para agentes de IA seguros.

Como medir – e minimizar – o custo total de propriedade do seu Kubernetes
Ecossistema F5 | 10/12/2020

Como medir – e minimizar – o custo total de propriedade do seu Kubernetes

O Kubernetes pode ser baixado e executado gratuitamente, mas sua manutenção está longe de não ter custos. Assim como outras grandes plataformas de código aberto que são “gratuitas” apenas em um sentido simplista, o Kubernetes quase certamente exigirá investimentos para ser implantado e operado.

As-Code: a pilha de TI contínua
Ecossistema F5 | 08/10/2018

As-Code: a pilha de TI contínua

Infraestrutura, configuração, pipeline, operações. De repente, tudo é “como código”. Lori MacVittie busca esclarecer a terminologia e identificar os diferentes componentes de uma stack contínua de TI.

O estado da entrega de aplicações em 2017: automação, APIs e DevOps
Ecossistema F5 | 17/04/2017

O estado da entrega de aplicações em 2017: automação, APIs e DevOps

Explore o relatório State of Application Delivery de 2017. Leia o blog retrospectivo da F5 sobre o início da ascensão das redes declarativas e dos pipelines de DevOps.

DevOps Summit: onde a rede foi convidada para a festa
Ecossistema F5 | 11/06/2015

DevOps Summit: onde a rede foi convidada para a festa

No DevOps Summit NY, falou-se muito não apenas sobre DevOps, mas também sobre contêineres, IoT e microsserviços. As sessões se concentraram não só na mudança cultural necessária para crescer em escala com uma abordagem DevOps, mas também fizeram questão de incluir...

F5 e Nutanix convergem em infraestrutura no .NEXT
Ecossistema F5 | 08/06/2015

F5 e Nutanix convergem em infraestrutura no .NEXT

Aplicações empresariais como Microsoft SharePoint e Exchange, juntamente com a VDI, continuam sendo a espinha dorsal da sua empresa. A produtividade, embora não seja tão atraente quanto o lucro, é um fator essencial para o sucesso das operações empresariais atuais. Deixar de...