1 pontos por GN⁺ 2024-11-30 | 1 comentários | Compartilhar no WhatsApp
  • Projeto que criou um modelo em TensorFlow.js para resolver automaticamente o CAPTCHA do 4Chan no navegador, alcançando a meta mínima de 80% e a meta desejada de mais de 90% de precisão
  • A coleta de CAPTCHAs era difícil de fazer com scraping em massa simples por causa de ttl, cd, do Cloudflare Turnstile e do tempo de espera progressivamente maior
  • Soluções comerciais baseadas em humanos e rotulagem manual foram limitadas por erros e throttling, então foram geradas cerca de 50.000 imagens de dados sintéticos com aproximadamente 2.500 fundos reais e 50–150 imagens por caractere para garantir escala de treino
  • O modelo usou arquitetura CNN+LSTM e codificação CTC, e após treino com Keras/TensorFlow foi convertido para TensorFlow.js passando por Python 3.10, Keras 2 e formato .h5
  • No navegador real, o primeiro carregamento levava cerca de 1 segundo e depois a execução parecia instantânea, mostrando taxa de sucesso acima de 90% em centenas de CAPTCHAs reais

Objetivo e código público

  • O objetivo era, ao mesmo tempo, aprender machine learning e TensorFlow e criar um modelo que resolvesse com confiabilidade o CAPTCHA do 4Chan no navegador
  • A referência era no mínimo 80% de precisão e, se possível, mais de 90%, o que acabou sendo alcançado
  • O código relacionado foi publicado no GitHub em 4chan-captcha-playground

Como funciona o CAPTCHA do 4Chan

  • O 4Chan exige entrada de CAPTCHA antes de publicar um post ou resposta
  • O CAPTCHA normal é uma imagem com 5–6 caracteres alfanuméricos, e o usuário precisa digitar todos corretamente
  • O CAPTCHA de slider funciona alinhando uma imagem de fundo que parece formada por fragmentos aleatórios de caracteres com uma imagem de frente com um buraco transparente, revelando assim o texto do CAPTCHA

Limitações encontradas na coleta de CAPTCHA

  • Ao observar uma nova requisição de CAPTCHA, o navegador envia uma chamada para https://sys.4chan.org/captcha?framed=1&board={board}
  • Ao remover framed=1, retorna JSON bruto em vez de postMessage() dentro de HTML
    • O JSON inclui challenge, ttl, cd, img, img_width, img_height, bg, bg_width e outros campos
    • ttl parece indicar quando o CAPTCHA expira, cerca de 2 minutos depois
    • cd foi interpretado como o valor de cooldown até a próxima requisição de CAPTCHA
  • Ao enviar requisições em sequência, cd cresce gradualmente
    • Nas primeiras vezes, era possível pedir um CAPTCHA a cada 5 segundos
    • Depois isso aumentava para 8 segundos e continuava crescendo aproximadamente em dobro
    • No fim, atingia um teto de 280 segundos
  • Depois de chegar ao temporizador de 280 segundos, o CAPTCHA ficava mais difícil
    • Passavam a aparecer imagens com várias linhas horizontais e elementos ovais de interferência
    • A qualidade dos dados caía, mas eles ainda podiam ser usados
  • Antes de requisitar o CAPTCHA, era necessário passar pelo Cloudflare Turnstile
    • Usar muitos proxies e scripts simples não era realista
    • O script de coleta copiava os cookies do Cloudflare do navegador e os reutilizava, substituindo-os manualmente quando expiravam
  • Com esse método, foram coletadas algumas centenas de CAPTCHAs, mas isso ainda não era suficiente para o treino e também não havia rótulos de resposta

Limites da rotulagem baseada em humanos

  • O alinhamento do CAPTCHA de slider mostrou 100% de sucesso com um script heurístico em trainer/captcha_aligner.py
  • Foi escrito trainer/labeler.py para enviar CAPTCHAs a um serviço comercial de resolução, onde pessoas reais digitavam as respostas
  • Nas primeiras dezenas de CAPTCHAs enviadas, a maioria era resolvida com pelo menos um caractere errado
  • Foi usada a função “100% Recognition” do serviço para receber resultados apenas quando várias respostas de trabalhadores coincidissem
    • Os parâmetros eram n = 2, x = 2, y = 3
    • Primeiro enviava para 2 pessoas e, se não houvesse concordância, enviava para até mais 3 até que duas respostas coincidissem
  • Com essa configuração, cerca de 80% dos CAPTCHAs foram resolvidos e, entre eles, cerca de 90% estavam corretos, mas aproximadamente 10% ainda tinham erro
    • Havia casos em que vários trabalhadores cometiam o mesmo erro
  • Também foi usado um userscript para resolver CAPTCHAs manualmente, pelo próprio autor ou com ajuda de conhecidos, salvando imagem e resposta
    • Isso rendeu mais algumas centenas de imagens para o conjunto de treino
    • A abordagem foi interrompida por causa do throttling de requisições repetidas e do aumento de dificuldade do CAPTCHA

Geração de dados sintéticos

  • O 4Chan e o código desse CAPTCHA não são open source, então não era possível executar localmente o mesmo código
  • Em vez disso, foram gerados CAPTCHAs sintéticos que aproximavam a estrutura dos reais
  • O CAPTCHA foi tratado em duas partes: fundo e caracteres
    • O fundo foi obtido encontrando grandes contours em imagens reais e removendo a área dos caracteres
    • Depois da remoção dos caracteres, restava apenas o fundo com ruído
  • Os caracteres individuais foram obtidos por rotulagem manual
    • VoTT foi usado para marcar os caracteres
    • Um script simples extraía os caracteres e fazia o pós-processamento
    • Foram obtidas de 50 a 150 imagens isoladas por caractere
  • O CAPTCHA do 4Chan contém apenas 0, 2, 4, A, D, G, H, J, K, M, N, P, R, S, T, W, X, Y
    • Isso provavelmente foi escolhido para evitar ambiguidades
  • Os caracteres extraídos e os fundos foram combinados para gerar imagens sintéticas, seguindo os padrões de posicionamento observados
  • Como os caracteres de entrada já estavam rotulados, as respostas corretas dos CAPTCHAs sintéticos também podiam ser geradas automaticamente

Arquitetura do modelo e pré-processamento

  • Os dados de treino misturavam CAPTCHAs de slider previamente alinhados, CAPTCHAs normais e CAPTCHAs sintéticos
  • O script de treino ajustava todas as imagens para 300x80 pixels e as convertia para preto e branco puro
  • O modelo usou uma arquitetura LSTM CNN montada com base em vários textos sobre resolução de CAPTCHA
    • Foram usadas 3 camadas de convolution/max-pooling
    • Foram usadas 2 camadas LSTM
    • Uma 4ª camada de convolution também foi testada, mas não melhorou o desempenho
  • Como o comprimento de saída era variável, com 5 ou 6 caracteres, foi usada codificação CTC
  • A implementação usou Keras e TensorFlow

Problema com a ordem dos argumentos de tf.image.resize()

  • Alguns CAPTCHAs antigos de slider alinhados não se encaixavam na resolução 300x80 nem na proporção esperada
  • O script de treino passou a usar tf.image.resize() para lidar com entradas variadas
  • Inicialmente, foi assumido que o argumento de tamanho era uma tupla (width, height), mas na prática tf.image.resize() exige a ordem (height, width)
  • Esse erro fazia a imagem ficar 80x300, esticada verticalmente e ilegível
    • Mesmo após treinar por mais de 32 epochs, o desempenho em imagens vistas era quase nulo
    • Em CAPTCHAs novos, as previsões ficavam próximas do aleatório
  • O problema foi identificado ao visualizar as imagens de entrada já processadas, e depois da correção o desempenho do treino melhorou bastante

Escala do treino e resultados

  • O dataset final foi composto por cerca de 500 imagens resolvidas manualmente e cerca de 50.000 imagens sintéticas
  • As imagens sintéticas foram geradas com amostragem aleatória a partir de cerca de 2.500 imagens de fundo e 50–150 imagens por caractere
  • O dataset foi embaralhado aleatoriamente e dividido em proporção 90/10 entre treino e avaliação
  • Em uma NVIDIA RTX A4000 Laptop GPU, o tempo de treino por epoch era de cerca de 45 segundos
  • Ao fim do primeiro epoch, a loss estava em torno de 19 e as previsões quase sempre erravam
  • Ao fim do 4º epoch, a loss caiu para 0,55 e 5 de 5 previsões em testes aleatórios estavam corretas
  • Entre 8 e 16 epochs parecia haver o melhor equilíbrio entre tempo e desempenho final
    • Por volta do 8º epoch, a loss se estabilizava
    • Acima de 16 epochs, a melhora adicional diminuía bastante
  • A inferência foi testada em Python com trainer/infer.py, com resultados promissores mesmo em imagens não vistas

Conversão para TensorFlow.js e execução no navegador

  • O userscript foi escrito com TensorFlow.js e TypeScript
  • O algoritmo de alinhamento de CAPTCHA do código Python e o pré-processamento de imagem foram reimplementados
  • O código relacionado está no diretório user-scripts/ do repositório
  • O formato do modelo Python TensorFlow/Keras não é compatível com o formato esperado pelo TensorFlow.js
  • Foi necessário usar o script oficial de conversão, mas surgiram dois problemas
    • O conversor oficial de TensorFlow para TFJS não funcionava no Python 3.12 e a mensagem de erro não era clara
    • Ao usar Python 3.10 com PyEnv, a conversão passou a funcionar
  • O script de conversão conseguia transformar modelos Keras 3 para o formato do TensorFlow.js, mas o TensorFlow.js não conseguia realmente ler o modelo convertido
  • A solução foi usar Keras 2
    • Foi instalado o pacote legado tf_keras
    • A variável de ambiente TF_USE_LEGACY_KERAS=1 foi definida no treino
    • O modelo foi exportado no formato legado .h5 e o formato de entrada foi especificado no script de conversão
    • A mudança no código exigiu apenas uma linha simples

Desempenho em CAPTCHAs reais do 4Chan

  • O modelo também funcionou bem em CAPTCHAs reais do 4Chan
  • O primeiro carregamento do modelo levava cerca de 1 segundo
  • Depois disso, a execução parecia instantânea
  • Com base na experiência resolvendo centenas de CAPTCHAs reais no navegador, a taxa de sucesso foi superior a 90%
  • Erros no reconhecimento dos caracteres em si eram raros; quando falhava, normalmente um caractere inteiro era omitido
  • Ainda há espaço para melhorar com mais treino em dados reais ou ajustando o layout do gerador de dados sintéticos
  • A precisão desse modelo foi muito superior à de serviços comerciais de resolução de CAPTCHA baseados em humanos

CAPTCHA de 4 caracteres e encerramento

  • Depois da conclusão do projeto, enquanto o texto era escrito e editado, o 4Chan começou às vezes a oferecer CAPTCHAs de 4 caracteres
  • O modelo havia sido treinado apenas com CAPTCHAs de 5 e 6 caracteres, mas mostrou desempenho semelhante também nos de 4 caracteres
  • Ao longo do projeto, houve muito aprendizado em machine learning e visão computacional, e o objetivo inicial de criar um modelo de resolução de CAPTCHA no navegador foi alcançado

1 comentários

 
GN⁺ 2024-11-30
Opiniões no Hacker News
  • A parte em que a integração entre Keras e TensorFlow.js é uma bagunça parece bem típica do TensorFlow
    Sempre que eu usava TensorFlow, a impressão era menos de um produto integrado e polido e mais de um monte de ferramentas mais ou menos relacionadas colocadas sob o mesmo guarda-chuva
    Na verdade, dá até para dizer que todas as bibliotecas e ferramentas open source do Google passam essa sensação

    • Em relação a isso, houve um contexto parecido no post de 15 dias atrás sobre François Chollet deixando o Google: https://news.ycombinator.com/item?id=42130881
      A resposta para “por que decidiram fundir o Keras ao TensorFlow em 2019?” foi: “Não fui eu que decidi. Foi uma decisão tomada pelos líderes do TF em 2018; na época eu era um contribuidor individual L5, e aquilo era uma decisão L8”
    • Isso lembra a Lei de Conway
  • Eu precisava de um CAPTCHA para impedir spam no formulário de comentários do meu site[0], então reaproveitei uma abordagem divertida que tinha visto antes
    Não é nem de longe perfeito nem difícil, mas gostei muito do processo de criação
    [0] https://www.hybridlogic.co.uk/contact

  • Há um motivo pelo qual as pessoas se afastaram dos CAPTCHAs baseados em texto distorcido
    Estamos quase no ponto em que computadores os resolvem melhor que humanos
    https://www.usenix.org/system/files/conference/woot14/woot14... é um artigo sobre esse tema, e acho bem interessante
    Ainda assim, uma quantidade surpreendente de CAPTCHAs baseados em texto pode ser resolvida com um shell script de poucas linhas que usa ImageMagick para converter para escala de cinza, aplica dilatação e erosão, e depois passa para o Tesseract
    Mas também existem sites como https://2captcha.net, então, no fim, CAPTCHA é mais um mecanismo que exige um pequeno esforço mínimo

    • O fato de ser tecnicamente quebrável não significa que seja inútil
      A solução deste artigo também exigiu bastante tempo, técnica e esforço, e o resultado não generaliza bem; para outro tipo de CAPTCHA, seria preciso começar do zero
      A maioria dos spammers não consegue reproduzir isso, e quem consegue provavelmente pode ganhar dinheiro de forma legítima ou mirar alvos mais lucrativos
      Esse tipo de CAPTCHA ainda funciona bem para elevar o custo de um spam bem-sucedido acima da receita esperada
    • Fico curioso para saber o que vem a seguir
      Será que daria para criar um fórum em que todos os membros precisassem fazer uma entrevista por vídeo de 15 minutos com um moderador? Sei que “não escala”, mas como uma espécie de pegadinha engraçada parece possível
    • Vejo CAPTCHA apenas como mais uma linha de defesa que aumenta a dificuldade para agentes que abusam do sistema
      Não é uma solução; é como uma pequena fortaleza que vai ficando obsoleta aos poucos
    • Não dá para dizer que seja pequena
      Segundo o link, o reCAPTCHA v3 leva de 10 a 15 segundos e custa US$ 1,30 por 1000 CAPTCHAs
      Para muitas tarefas em que se quer contornar CAPTCHA, como raspar um grande site em escala, esse custo se torna realmente considerável e difícil de bancar
    • Nesse caso, um CAPTCHA de prova de trabalho provavelmente pode ser a melhor opção
      mCaptcha.org é um deles, e há outras implementações
      CAPTCHAs tradicionais, quando são minimamente eficazes, tendem a virar um pesadelo de acessibilidade
  • Se você se interessa por esse tema, também há uma análise do Silk Road CAPTCHA que eu organizei em 2014: https://github.com/mieko/sr-captcha

  • A resposta do 4chan parece adequada
    Como, de todo modo, é fácil resolver com redes neurais, eles estão simplificando a tarefa para humanos
    Hoje, mesmo projetando um CAPTCHA muito difícil, é pouco provável que ele se torne difícil para máquinas resolverem; é mais provável que só irrite mais as pessoas

    • Nesse caso, eles poderiam simplesmente bloquear postagens de usuários gratuitos e obrigar todos que quiserem postar a comprar um 4chan Pass de US$ 20 por ano
      https://4chan.org/pass
      Ele já é oferecido como opção para postar sem CAPTCHA
      Se o CAPTCHA é completamente inútil, a conclusão que se segue é eliminar o CAPTCHA e a postagem gratuita, e exigir que todos que queiram postar comprem um 4chan Pass
    • Parece que estamos presos nesse ponto há pelo menos 5 anos, talvez até 10
    • Da próxima vez, é só usar o escaneamento de retina da Worldcoin
    • O 4chan não se importa muito se as pessoas ficam irritadas
      Recentemente introduziram um atraso de 15 minutos para postar, e isso dá muita raiva
      Tive que colocar o 4chan na lista de permissões do Cookie AutoDelete
  • Talvez seja melhor fingir que há um CAPTCHA, mas na prática analisar o timing e o comportamento do usuário
    Sinceramente, também acho que isso já deve estar acontecendo
    Indo totalmente para o lado meta, também daria para treinar uma IA para decidir se o agente do outro lado é uma pessoa ou não
    Ou seja, seria inventar um teste de Turing reverso, em que a pessoa é considerada humana se a IA não conseguir distingui-la de uma resposta humana normal
    A diferença é que não se trata de distinguir de respostas humanas voltadas a marketing
    Só de pensar nisso já estou meio enjoado e preciso me deitar

    • Os grandes provedores de CAPTCHA, em geral, já fazem isso
      Antes mesmo de exibir o CAPTCHA, eles primeiro identificam fingerprint de TLS, IP, HTTP/2, requisição, ambiente JavaScript, capacidade de renderização de fontes e imagens e o próprio navegador
      Com essas informações, calculam uma pontuação de confiança e decidem se vão mostrar um CAPTCHA para começo de conversa
      Só depois disso é que faz sentido analisar a entrada do CAPTCHA, mas, a essa altura, 90% dos bots já foram pegos
      A quantidade de informação que um navegador consegue informar ao servidor sem nenhuma percepção do usuário é absurda, então é bem possível que a impressão digital digital de cada um de nós seja mais única do que uma impressão digital física
    • É isso que o reCAPTCHA faz
  • Acho que o caso original, ou pelo menos um dos pioneiros, de quebrar o CAPTCHA do 4chan ainda é o Yannick Kilcher fazendo fine-tuning do GPT-J com o dataset “Raiders of the Lost Kek”
    Talvez seja um dos exemplos mais legais de uso de modelos de linguagem grandes em vídeo: https://youtu.be/efPrtcLdcdM?si=errY0PrEhnX9ylDw

    • Só o aviso legal e os alertas sobre o 4chan levam quase 1 minuto
      É digno de registro
  • Quase desisti de tentar brincar um pouco com machine learning alguns anos atrás por coisas como “o conversor oficial de modelos TensorFlow para TFJS não funciona no Python 3.12 e nem é documentado direito” e “TensorFlow.js não dá suporte ao Keras 3”
    Tutoriais recentes muitas vezes já estavam obsoletos, havia muitas armadilhas aleatórias, e era chocante como guias de “primeiros passos” já presumiam que você era especialista

    • Como alguém que trabalha com machine learning há alguns anos, eu recomendaria evitar as modas mais recentes
      É melhor aprender os fundamentos com um livro-texto antigo de estatística bayesiana e depois passar para um framework principal como PyTorch
      No começo, é bom implementar você mesmo CNNs, RNNs, arquiteturas Transformer e todas as partes do pipeline de treinamento
      Incluindo até o data loader, mas pode deixar de fora os kernels de matrizes em CUDA
      É melhor ficar longe de wrappers que embrulham wrappers de terceiros, como LangChain
      Muitas vezes a documentação não está apenas desatualizada; ela está simplesmente errada sobre fundamentos
      Hugging Face é excelente se você conhece o básico e consegue consertar quando o wrapper padrão quebra
  • Isso é parecido com passar algumas horas aprendendo como abrir a tampa de uma fossa séptica

    • Curiosamente, a maior parte do 4chan parece apodrecer menos o cérebro do que o Twitter pré-Musk
    • Não dá para subestimar o que se pode aprender estudando sistemas de fossa séptica
  • Se você seguir o link de serviços de resolução de CAPTCHA, dá para ler os perfis das pessoas que fazem esse trabalho
    Eles são divulgados como algo mais ético do que trabalhar em fábricas perigosas