Tous les articles

Dans les coulisses de Web Unblocker : ce que fait réellement le flag Unblocker

Un seul flag active trois leviers : de vrais headers de navigateur, une empreinte TLS correspondante et la décompression automatique pour gzip et brotli. Voici ce qui a changé et pourquoi.

La plupart des scrapers échouent avant même la lecture du premier header.

Le serveur analyse le handshake TLS (ordre des suites de chiffrement, ordre des extensions, préférences de courbes) et détermine si vous êtes un navigateur ou une bibliothèque cliente qui tente de l'imiter. Python requests, net/http de Go, simple curl : tous transmettent une empreinte distinctive dès la connexion. Les sites qui s'en protègent (Datadome, Akamai, Imperva, la partie managée de Cloudflare) coupent la connexion ou affichent une page de challenge avant même que votre chaîne User-Agent n'entre en jeu.

C'est ce que résout unblocker: true sur FourA. Le mois dernier, nous avons stabilisé les composants qui garantissent son fonctionnement fiable.

Nouveautés

unblocker: true est un simple flag sur n'importe quel appel /api/single. Activez-le et nous effectuons trois actions : injecter le jeu de headers du navigateur, envoyer la request via curl-impersonate avec une empreinte TLS de navigateur réel, et décompresser tout ce que le serveur renvoie (gzip, brotli, deflate). Les deux premières fonctionnalités sont disponibles depuis la bêta. La troisième (la décompression automatique brotli) a été déployée le 25 mars, et le travail de verrouillage de la version du navigateur est arrivé le lendemain pour maintenir les headers et le TLS parfaitement synchronisés.

Fonctionnement

Voici à quoi ressemble une request :

curl -X POST "https://api.foura.ai/api/single" \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "url": "https://example.com/products",
    "method": "GET",
    "unblocker": true
  }'

Trois couches s'exécutent en arrière-plan.

Injection de headers. Nous définissons l'ensemble complet de headers du navigateur : User-Agent, Sec-Ch-Ua, Sec-Ch-Ua-Platform, Sec-Fetch-Site, Sec-Fetch-Mode, Sec-Fetch-Dest, Accept, Accept-Language et Accept-Encoding. L'ordre est crucial. Les vrais navigateurs les envoient dans une séquence spécifique, et les bibliothèques de détection la vérifient.

Empreinte TLS. curl-impersonate 0.8.2 compile libcurl avec BoringSSL et réorganise les extensions TLS pour correspondre à ce que la version du navigateur cible envoie réellement sur le réseau. Vos empreintes JA3 et JA4 deviennent identiques à celles d'une session de navigateur réelle. Le curl standard, Python requests et net/http de Go génèrent des empreintes qui sont signalées automatiquement en quelques millisecondes sur les infrastructures protégées.

Décompression automatique. Lorsque unblocker est activé, nous définissons Accept-Encoding sur gzip, deflate, br et laissons libcurl décompresser le corps de la réponse. Vous recevez une chaîne décodée en retour (ou un Buffer si vous passez returnBuffer: true). Pas de gestion manuelle de brotli, pas d'incohérence entre headers et corps de réponse lorsqu'un site choisit deflate plutôt que gzip.

Pourquoi le verrouillage de version est crucial

Les empreintes TLS sont liées à des versions spécifiques. L'ordre des chiffrements d'un navigateur ce mois-ci n'est pas le même que le mois dernier, et un site qui analyse finement les empreintes remarquera cette dérive. curl-impersonate fournit des profils pour des builds de navigateurs spécifiques, et nous verrouillons notre binaire de navigateur réel sur la build actuellement ciblée par curl-impersonate. Les headers, les objets navigator et le TLS signalent tous la même version.

Si cela semble complexe, ça l'est. Nous avons été piégés par une incohérence lors de la migration du monorepo en mars, lorsque le navigateur s'est mis à jour automatiquement et que les headers se sont désynchronisés de curl-impersonate. La correction a nécessité deux commits : verrouiller le binaire du navigateur et ne jamais faire confiance au gestionnaire de paquets pour les maintenir alignés.

Impact

Lors de tests internes sur des cibles appliquant un fingerprinting strict (finance, voyage, e-commerce protégé), la différence entre unblocker: false and unblocker: true est celle entre une page de challenge et un code 200. Un simple curl ciblant un Cloudflare managé se solde par une erreur 403 dès la première tentative. La même URL avec unblocker: true passe sans problème car le hello TLS ressemble à un handshake de navigateur réel.

Mais pour les sites qui n'analysent pas les empreintes (la plupart des API publiques, les anciens templates de CMS, tout ce qui est uniquement limité par le rate limit d'IP), laisser unblocker désactivé convient très bien et permet d'économiser quelques millisecondes de négociation TLS. Utilisez-le là où c'est nécessaire.

Pour les utilisateurs avancés

Quelques schémas utiles à connaître.

Associez unblocker à un proxy résidentiel lorsque la cible vérifie également la réputation de l'IP. Des IP de datacenter combinées à un handshake TLS parfait restent détectées sur les ASN mis sur liste noire par le site. Notre endpoint de proxy (/api/proxy) effectue une rotation par domaine cible, donc ajouter "proxy": "residential" à la request suffit généralement.

Ignorez unblocker lors de l'appel d'API JSON qui ne se soucient pas des navigateurs. Les headers supplémentaires peuvent en réalité sembler suspects à une API qui attend un client programmatique, par exemple un backend appelant son propre microservice.

Si le site utilise des scripts anti-bots JavaScript (challenges interactifs Turnstile, Perimeter X configuré au plus strict, Akamai Bot Manager avec les heuristiques au maximum), unblocker seul ne suffira pas. Vous aurez besoin de l'endpoint browser, qui exécute un vrai Chromium et peut résoudre le challenge. Il s'agit d'un produit distinct avec une tarification en crédits différente, que nous avons détaillé dans Browser Tasks : comment scraper les sites riches en JavaScript.

Et vous pouvez combiner unblocker avec le bloc validate pour rejeter les réponses qui renvoient techniquement un code 200 mais contiennent une page de challenge :

{
  "url": "https://example.com/products",
  "method": "GET",
  "unblocker": true,
  "validate": {
    "data": { "fail": ["captcha", "Access Denied"] }
  }
}

Cela transforme les échecs silencieux en échecs catégorisés, ce qui est important pour le suivi de votre taux de réussite dans le tableau de bord.

Et ensuite ?

Les navigateurs publient une nouvelle version stable toutes les quatre semaines. Le mainteneur de curl-impersonate effectue généralement la mise à niveau un mois plus tard, et nous mettons à jour notre stack à ce moment-là. Vous n'avez rien à modifier de votre côté : unblocker: true continue de pointer vers la version du navigateur que nous avons validée de bout en bout.

Le plus difficile reste à faire. Le fingerprinting HTTP/3 apparaît déjà sur les systèmes anti-bots managés, le transport QUIC est plus complexe à usurper que le TLS 1.3, et la transition des paquets de headers statiques vers une émulation réellement dynamique commence. Les sites protégés vérifient désormais l'ordonnancement des frames HTTP/2 et les variantes JA4+, et l'écart entre « un curl qui ressemble à un navigateur » et « un vrai navigateur » va se réduire des deux côtés. Nous publierons un article à ce sujet dès que nous le déploierons.