Protégez vos ressources contre les attaques sur le Web avec Fetch Metadata

Empêchez les attaques CSRF, XSSI et les fuites d'informations inter-origines.

De nombreuses applications Web sont vulnérables aux attaques inter-origines, telles que la falsification des requêtes intersites (CSRF), l'inclusion de script intersites (XSSI), les attaques par synchronisation, les fuites d'informations inter-origines ou les attaques par canal auxiliaire d'exécution spéculative (Spectre).

Les en-têtes de requête Fetch Metadata vous permettent de déployer un mécanisme de défense en profondeur efficace (une stratégie d'isolation des ressources) pour protéger votre application contre ces attaques inter-origines courantes.

Il est courant que les ressources exposées par une application Web donnée ne soient chargées que par l'application elle-même, et non par d'autres sites Web. Dans ce cas, déployer une stratégie d'isolation des ressources basée sur les en-têtes de requête de récupération de métadonnées ne demande que peu d'efforts, tout en protégeant l'application contre les attaques intersites.

Compatibilité du navigateur

Les en-têtes de requête de récupération des métadonnées sont compatibles avec tous les moteurs de navigateur modernes.

Navigateurs pris en charge

  • Chrome: 76.
  • Edge: 79.
  • Firefox: 90.
  • Safari: 16.4.

Source

Contexte

De nombreuses attaques intersites sont possibles, car le Web est ouvert par défaut et votre serveur d'application ne peut pas facilement se protéger des communications provenant d'applications externes. Une attaque inter-origine typique est la falsification de requêtes intersites (CSRF, Cross-Site Request Forgery), où un pirate informatique attire un utilisateur sur un site qu'il contrôle, puis envoie un formulaire au serveur auquel l'utilisateur est connecté. Étant donné que le serveur ne peut pas déterminer si la requête provient d'un autre domaine (intersite) et que le navigateur associe automatiquement des cookies aux requêtes intersites, le serveur exécute l'action demandée par l'attaquant au nom de l'utilisateur.

D'autres attaques intersites, telles que l'inclusion de script intersites (XSSI) ou les fuites d'informations inter-origines, sont de nature similaire à la CSRF. Elles consistent à charger des ressources à partir d'une application victime dans un document contrôlé par un pirate informatique et à divulguer des informations sur les applications victimes. Étant donné que les applications ne peuvent pas facilement distinguer les requêtes approuvées des requêtes non approuvées, elles ne peuvent pas supprimer le trafic intersites malveillant.

Présentation de la fonctionnalité Récupérer les métadonnées

Les en-têtes de requête de récupération des métadonnées sont une nouvelle fonctionnalité de sécurité de la plate-forme Web conçue pour aider les serveurs à se défendre contre les attaques inter-origines. En fournissant des informations sur le contexte d'une requête HTTP dans un ensemble d'en-têtes Sec-Fetch-*, ils permettent au serveur répondant d'appliquer des règles de sécurité avant de traiter la requête. Cela permet aux développeurs de décider d'accepter ou de refuser une requête en fonction de la manière dont elle a été effectuée et du contexte dans lequel elle sera utilisée. Ils ne peuvent ainsi répondre qu'aux requêtes légitimes émises par leur propre application.

Same-Origin
Les requêtes provenant de sites desservis par votre propre serveur (même origine) continueront de fonctionner. Une requête de récupération à partir de https://site.example pour la ressource https://site.example/foo.json en JavaScript entraîne l'envoi par le navigateur de l'en-tête de requête HTTP "Sec Fetch-Site: same-origin".
Intersite
Les requêtes intersites malveillantes peuvent être refusées par le serveur en raison du contexte supplémentaire fourni par les en-têtes Sec-Fetch-* dans la requête HTTP. Une image sur https://evil.example qui a défini l'attribut src d'un élément img sur "https://site.example/foo.json" entraîne l'envoi par le navigateur de l'en-tête de requête HTTP "Sec-Fetch-Site: cross-site".

Sec-Fetch-Site

Navigateurs pris en charge

  • Chrome: 76.
  • Edge: 79.
  • Firefox: 90.
  • Safari: 16.4.

Source

Sec-Fetch-Site indique au serveur quel site a envoyé la requête. Le navigateur définit cette valeur sur l'une des valeurs suivantes:

  • same-origin, si la requête a été effectuée par votre propre application (par exemple, site.example)
  • same-site, si la requête a été effectuée par un sous-domaine de votre site (par exemple, bar.site.example)
  • none, si la requête a été explicitement déclenchée par l'interaction d'un utilisateur avec l'user-agent (par exemple, en cliquant sur un favori)
  • cross-site, si la requête a été envoyée par un autre site Web (par exemple, evil.example)

Sec-Fetch-Mode

Navigateurs pris en charge

  • Chrome: 76.
  • Edge: 79.
  • Firefox: 90.
  • Safari: 16.4.

Source

Sec-Fetch-Mode indique le mode de la requête. Il correspond approximativement au type de la requête et vous permet de distinguer les chargements de ressources des requêtes de navigation. Par exemple, une destination de navigate indique une requête de navigation de premier niveau, tandis que no-cors indique des requêtes de ressources telles que le chargement d'une image.

Sec-Fetch-Dest

Navigateurs pris en charge

  • Chrome: 80.
  • Edge: 80.
  • Firefox: 90.
  • Safari: 16.4.

Source

Sec-Fetch-Dest expose la destination d'une requête (par exemple, si une balise script ou img a entraîné la demande d'une ressource par le navigateur).

Utiliser les métadonnées de récupération pour se protéger contre les attaques inter-origines

Les informations supplémentaires fournies par ces en-têtes de requête sont assez simples, mais le contexte supplémentaire vous permet de créer une logique de sécurité puissante côté serveur, également appelée "règle d'isolation des ressources", avec seulement quelques lignes de code.

Implémenter une règle d'isolation des ressources

Une règle d'isolation des ressources empêche les sites Web externes de demander vos ressources. Le blocage de ce trafic atténue les failles Web intersites courantes telles que les attaques CSRF, XSSI, par cassage de délai et les fuites d'informations inter-origines. Cette règle peut être activée pour tous les points de terminaison de votre application. Elle autorise toutes les requêtes de ressources provenant de votre propre application, ainsi que les navigations directes (via une requête HTTP GET). Vous pouvez désactiver cette logique pour les points de terminaison censés être chargés dans un contexte intersites (par exemple, les points de terminaison chargés à l'aide de CORS).

Étape 1: Autorisez les requêtes provenant de navigateurs qui n'envoient pas de métadonnées de récupération

Étant donné que tous les navigateurs ne sont pas compatibles avec la récupération des métadonnées, vous devez autoriser les requêtes qui ne définissent pas d'en-têtes Sec-Fetch-* en vérifiant la présence de sec-fetch-site.

if not req['sec-fetch-site']:
  return True  # Allow this request

Étape 2: Autorisez les requêtes du même site et celles initiées par le navigateur

Toutes les requêtes qui ne proviennent pas d'un contexte inter-origine (comme evil.example) sont autorisées. En particulier, il peut s'agir des demandes suivantes:

  • Proviennent de votre propre application (par exemple, une requête de même origine où les requêtes site.example site.example/foo.json sont toujours autorisées).
  • proviennent de vos sous-domaines ;
  • sont explicitement causées par l'interaction d'un utilisateur avec l'agent utilisateur (par exemple, navigation directe ou clic sur un favori, etc.) ;
if req['sec-fetch-site'] in ('same-origin', 'same-site', 'none'):
  return True  # Allow this request

Étape 3: Autoriser la navigation de premier niveau et l'iframing simples

Pour vous assurer que votre site peut toujours être associé à d'autres sites, vous devez autoriser la navigation de premier niveau simple (HTTP GET).

if req['sec-fetch-mode'] == 'navigate' and req.method == 'GET'
  # <object> and <embed> send navigation requests, which we disallow.
  and req['sec-fetch-dest'] not in ('object', 'embed'):
    return True  # Allow this request

Étape 4: Désactiver les points de terminaison destinés à diffuser du trafic intersites (facultatif)

Dans certains cas, votre application peut fournir des ressources destinées à être chargées entre les sites. Ces ressources doivent être exemptées par chemin d'accès ou par point de terminaison. Voici quelques exemples de points de terminaison de ce type:

  • Points de terminaison destinés à être accessibles entre origines: si votre application diffuse des points de terminaison CORS activés, vous devez les désactiver explicitement de l'isolation des ressources pour vous assurer que les requêtes intersites vers ces points de terminaison restent possibles.
  • Ressources publiques (images, styles, etc.): Toutes les ressources publiques et non authentifiées qui doivent être chargées inter-origines à partir d'autres sites peuvent également être exclues.
if req.path in ('/my_CORS_endpoint', '/favicon.png'):
  return True

Étape 5: Refusez toutes les autres requêtes intersites qui ne sont pas liées à la navigation

Toute autre requête intersites sera refusée par cette règle d'isolation des ressources, ce qui protégera votre application contre les attaques intersites courantes.

Exemple:Le code suivant illustre une implémentation complète d'une règle d'isolation des ressources robuste sur le serveur ou en tant que middleware pour refuser les requêtes de ressources intersites potentiellement malveillantes, tout en autorisant les requêtes de navigation simples:

# Reject cross-origin requests to protect from CSRF, XSSI, and other bugs
def allow_request(req):
  # Allow requests from browsers which don't send Fetch Metadata
  if not req['sec-fetch-site']:
    return True

  # Allow same-site and browser-initiated requests
  if req['sec-fetch-site'] in ('same-origin', 'same-site', 'none'):
    return True

  # Allow simple top-level navigations except <object> and <embed>
  if req['sec-fetch-mode'] == 'navigate' and req.method == 'GET'
    and req['sec-fetch-dest'] not in ('object', 'embed'):
      return True

  # [OPTIONAL] Exempt paths/endpoints meant to be served cross-origin.
  if req.path in ('/my_CORS_endpoint', '/favicon.png'):
    return True

  # Reject all other requests that are cross-site and not navigational
  return False

Déployer une règle d'isolation des ressources

  1. Installez un module tel que l'extrait de code ci-dessus pour consigner et surveiller le comportement de votre site, et vous assurer que les restrictions n'affectent aucun trafic légitime.
  2. Résolvez les cas de non-respect potentiels en excluant les points de terminaison inter-origine légitimes.
  3. Appliquez la règle en abandonnant les requêtes non conformes.

Identifier et corriger les cas de non-respect des règles

Nous vous recommandons de tester votre stratégie sans effet secondaire en l'activant d'abord en mode création de rapports dans votre code côté serveur. Vous pouvez également implémenter cette logique dans un middleware ou dans un proxy inverse qui consigne toutes les infractions que votre règle peut produire lorsqu'elle est appliquée au trafic de production.

D'après notre expérience de déploiement d'une stratégie d'isolation des ressources de métadonnées de récupération chez Google, la plupart des applications sont compatibles par défaut avec une telle stratégie et nécessitent rarement d'exempter des points de terminaison pour autoriser le trafic intersites.

Application d'une règle d'isolation des ressources

Une fois que vous avez vérifié que votre règle n'a pas d'impact sur le trafic de production légitime, vous pouvez appliquer des restrictions pour vous assurer que d'autres sites ne peuvent pas demander vos ressources et protéger vos utilisateurs contre les attaques intersites.

Documentation complémentaire