Contrôle d'accès HTTP

Les requêtes HTTP de type Cross-site sont des requêtes pour des ressources localisées sur un domaine différent de celui à l'origine de la requête. Par exemple, une ressource chargée depuis le domaine A (http://domaina.example) comme une page HTML, effectue une requête pour une ressource provenant du domaine B (http://domainb.foo), comme une image, en utilisant la balise img (http://domainb.foo/image.jpg).  C'est régulièrement le cas aujourd'hui sur le web — des pages chargent un nombre de ressources à la manière Cross-site, en ce inclus des feuilles de style (CSS), des images, des scripts, et d'autres ressources.

Les requêtes HTTP croisées initiées au départ de scripts ont été sujettes à des restrictions bien connues et pour des raisons de sécurité bien compréhensibles. Par exemple les requêtes HTTP effectuées par l'objet XMLHttpRequest sont soumises à la politique de même origine.  En particulier, cela signifiait qu'une application web utilisant XMLHttpRequest ne pouvait que créer des requêtes HTTP vers le domaine d'où elle avait été chargée et non vers d'autres domaines. Les développeurs ont exprimé le désir de voir évoluer en toute sécurité les possibilités comme celles du XMLHttpRequest afin d'effectuer des requêtes croisées (cross-site), pour de meilleures et plus sûres compositions au sein d'applications web.

Le Web Applications Working Group au sein du W3C a recommandé le nouveau mécanisme de Cross-Origin Resource Sharing qui fournit un moyen aux serveurs web de contrôler les accès en mode cross-site et aussi d'effectuer des transferts de données sécurisés en ce mode. Il est particulièrement intéressant de noter que cette spécification est utilisée au sein d'un API container comme le XMLHttpRequest et ce en tant que mécanisme de mitigation, permettant de passer outre la restriction des navigateurs modernes de fonctionner sur base d'une politique "same-domain".  L'information contenue dans cet article est intéressante pour les administrateurs web, les programmeurs de serveurs et les développeurs web.  Un autre article pour les programmeurs serveurs discutant le partage des origines croisées sous l'angle du serveur (avec des extraits de code PHP) constitue une lecture supplémentaire fructueuse.  Sur l'environnement client, le navigateur s'occupe de partager l'origine des ressources, incluant les entêtes et la mise en application de la politique générale en la matière.  En revanche, l'introduction de cette nouvelle possibilité implique nécessairement que les serveurs doivent gérer de nouvelles entêtes, et doivent renvoyer les ressources avec de nouvelles entêtes également.

Ce  standard de partage d'origines croisées est utilisé pour permettre les requêtes HTTP en mode cross-site pour:

Cet article est une discussion générale du partage des ressources d'origines croisées et inclut une discussion du traitement des entêtes HTTP en Firefox 3.5. 

Vue générale

Le standard de partage de ressources d'origines croisées fonctionne grâce à l'ajout d'entêtes HTTP qui permettent aux serveurs de décrire l'ensemble des origines permises. C'est ensuite le navigateur qui lit cette information et en fait l'usage adéquat. Par ailleurs, pour les requêtes HTTP dont les méthodes pourraient avoir des effets secondaires sur les données utilisateur (en particulier pour les méthodes HTTP autres que GET, ou pour l'utilisation du POST avec certains types MIME), la spécification mandate les navigateurs pour "pré-vérifier" la requête en sollicitant le serveur pour connaître les méthodes approuvées. Cette pré-vérification s'effectue avec la méthode HTTP OPTIONS, et ensuite, après "approbation" du serveur, envoit la requête véritable. Les serveurs peuvent aussi notifier les clients de ce que les permissions (incluant les cookies et les données d'authentification HTTP) doivent être envoyées avec les requêtes.

Les sections suivantes discutent des scenarios, autant que de la décomposition des entêtes utilisés. 

Exemples de scenarios de contrôles d'accès

Ici, nous présentons 3 scenarios qui illustrent le fonctionnement du partage de ressources d'origines croisées. Tous ces exemples font usage de l'objet XMLHttpRequest, qui peut être utilisé pour invoquer du cross-site dans n'importe quel navigateur qui le supporte.

Les fragments de JavaScript qui sont inclus dans ces sections (et les occurrences tournant du côté du serveur qui gèrent ces demandes d'origines croisées) peuvent  peuvent être consultées "en action" ici, et fonctionneront dans les navigateurs qui supportent les origines croisées via l'objet XMLHttpRequest.  Une discussion du partage de ressources croisées dans la perspective serveur (en ce inclus les extraits PHP) peut être consulté ici.

Requêtes simples

Une requête cross-site simple est une requête qui:

  • N'utilise que les options GET, HEAD ou POST. Si POST est utlisé pour envoyer des données au serveur le Content-Type des données envoyé au serveur est soit application/x-www-form-urlencoded, multipart/form-data, ou text/plain.
  • Ne positionne pas d'entêtes personnalisés avec la requête HTTP Request (comme par exemple X-Modified, etc.)
Note: Ce sont les mêmes types de requêtes cross-site que du contenu web peuvent déjà lancer, et aucune donnée de réponse n'est soumise à l'appelant sauf si le serveur envoit un entête approprié. Ainsi donc, les sites qui empêchent la falsification de requête inter-site ne doivent rien craindre du contrôle d'accès HTTP.

Par exemple, supposez que le contenu web sur le domaine http://foo.example souhaite invoquer du contenu sur le domaine http://bar.other.  Un code de ce type pourrait être utilisé dans du JavaScript déployé sur foo.example:

var invocation = new XMLHttpRequest();
var url = 'http://bar.other/resources/public-data/';
   
function callOtherDomain() {
  if(invocation) {    
    invocation.open('GET', url, true);
    invocation.onreadystatechange = handler;
    invocation.send(); 
  }
}

 

Voyons à présent ce que le navigateur va envoyer au serveur dans ce cas, et voyons ce que le serveur répond:

GET /resources/public-data/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Referer: http://foo.example/examples/access-control/simpleXSInvocation.html
Origin: http://foo.example


HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 00:23:53 GMT
Server: Apache/2.0.61 
Access-Control-Allow-Origin: *
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/xml

[XML Data]

 Lines 1 - 10 sont les entêtes envoyés par Firefox 3.5.  Notez que l'entête principal ici est l'entête Origin: entête à la ligne 10 ici au-dessus, qui montre que l'invocation vient d'un contenu provenant du domaine http://foo.example.

Lines 13 - 22 montrent que la réponse HTTP du serveur sur le domaine http://bar.other.  En réponse, le server renvoie une entête Access-Control-Allow-Origin:, montrée ci-dessus en ligne 16.  L'utilisation de l'entête Origin: et de Access-Control-Allow-Origin: montrent l'accès au protocle de contrôle dans sa forme la plus simple.  Dans ce cas, le serveur répond avec un Access-Control-Allow-Origin: * qui signifie que la ressource peut être accédée de n'importe quel domaine de manière croisée (cross-site).  Si les propriétaires de la ressource sur http://bar.other souhaitaient restreindre l'accès à la ressource au seul domaine http://foo.example, ils enverraient :

Access-Control-Allow-Origin: http://foo.example

Notez que maintenant, aucun domaine autre que http://foo.example (identifié par l'entête ORIGIN: dans la requête, comme à la ligne 10 ci-dessus) ne peut accéder la ressource d'une manière croisée (cross-site).  L'entête Access-Control-Allow-Origin devrait contenir la valeur qui a été envoyée dans l'entête Origin de la requête. 

Requêtes pré-vérifiées

Contrairement aux requêtes simples (discutées ci-avant), les requêtes prévérifiées ("preflighted requests", stricto sensu, les requêtes avant décollage) envoient d'abord une requête HTTP avec l'entête OPTIONS dans la ressource souhaitée de l'autre domaine et cela en vue de déterminer si la véritable requête est sûre à envoyer. Les requêtes croisées entre site sont prévérifiées de cette manière parce qu'elles peuvent avoir des implications sur les données utilisateur.  En particulier, une requête est prévérifiée si :

  • elle utilise des méthodes autres que GET, HEAD ou POST.  Aussi, si POST est utilisée pour envoyer des reqûetes de données avec un Content-Type autre que application/x-www-form-urlencoded, multipart/form-data, ou text/plain, par exemple si la requête POST envoie au serveur un contenu utile XML en utilisant application/xml ou text/xml, alors la requête est pré-vérifiée.
  • elle positionne des entêtes propres (ex: la requête utilise une entête comme X-PINGOTHER)

Gecko 2.0 note
(Firefox 4 / Thunderbird 3.3 / SeaMonkey 2.1)

À partir de Gecko 2.0 (Firefox 4 / Thunderbird 3.3 / SeaMonkey 2.1), les encodages de données text/plain, application/x-www-form-urlencoded et multipart/form-data peuvent aussi être envoyés en mode croisé (cross-site) sans prévérification. Avant cela, seul text/plain pouvait être envoyé sans cette prévérification.

Un exemple de ce type d'invocation pourrait être:

var invocation = new XMLHttpRequest();
var url = 'http://bar.other/resources/post-here/';
var body = '<?xml version="1.0"?><person><name>Arun</name></person>';
    
function callOtherDomain(){
  if(invocation)
    {
      invocation.open('POST', url, true);
      invocation.setRequestHeader('X-PINGOTHER', 'pingpong');
      invocation.setRequestHeader('Content-Type', 'application/xml');
      invocation.onreadystatechange = handler;
      invocation.send(body); 
    }

......

Dans l'exemple ci-dessus, la ligne 3 crée un corps XML à envoyer avec une requête de type POST (ligne 8).  Aussi, à la ligne 9, un entête "personnalisé" (c'est-à-dire non-standard) est positionné dans la requête HTTP (X-PINGOTHER: pingpong).  De tels entêtes ne sont pas spécifiés dans la documentation du protocole HTTP/1.1, mais sont en général bien utiles à des applications web.  Puisque la requête (POST) utilise un Content-Type application/xml, et puisque un entête personnalisé est employé, cette requête est prévérifiée.

Jetons un oeil aux échanges complets entre le client et le serveur:

OPTIONS /resources/post-here/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Origin: http://foo.example
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER


HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://foo.example
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER
Access-Control-Max-Age: 1728000
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain

POST /resources/post-here/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
X-PINGOTHER: pingpong
Content-Type: text/xml; charset=UTF-8
Referer: http://foo.example/examples/preflightInvocation.html
Content-Length: 55
Origin: http://foo.example
Pragma: no-cache
Cache-Control: no-cache

<?xml version="1.0"?><person><name>Arun</name></person>


HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:40 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://foo.example
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 235
Keep-Alive: timeout=2, max=99
Connection: Keep-Alive
Content-Type: text/plain

[Some GZIP'd payload]

Lignes 1 - 12 ci-dessus: représentent la requête de pré-vérification avec l'entête OPTIONS.  Firefox 3.1 détermine s'il a besoin d'envoyer ceci sur base des paramètres de la requête que l'extrait de JavaScript avait utilisés, de telle sorte que le serveur puisse répondre s'il est acceptable d'envoyer la requête avec de tels paramètres.  OPTIONS est une méthode HTTP/1.1 qui est utilisée pour déterminer de futures informations des serveurs, et est une méthode idempotente, ce qui signifie qu'elle ne peut être utilisée pour modifier la ressource.  Notez qu'en sus, deux autres entêtes sont envoyés (lignes 11 et 12 respectivement):

Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER

L'entête Access-Control-Request-Method notifie le serveur, comme élément de la requête de pré-vérification, que lorsque la véritable requête est envoyée, elle sera sera envoyée avec la méthode POST. L'entête Access-Control-Request-Headers notifie le serveur que lorsque la véritable requête est envoyée  elle le sera avec une entête X-PINGOTHER personnalisée.  Le serveur a maintenant l'opportunité de déterminer s'il souhaite accepter une requête dans ses circonstances.

Lignes 15 - 27 ci-dessus sont la réponse que le serveur renvoit indiquant que la méthode de la requête (POST) et les entêtes de la requête (X-PINGOTHER) sont acceptables.  En particulier, voyons les lignes 18-21:

Access-Control-Allow-Origin: http://foo.example
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER
Access-Control-Max-Age: 1728000

Le serveur répond avec Access-Control-Allow-Methods et indique que les  méthodes POST, GET, et OPTIONS sont des méthodes acceptables pour aller quérir la ressource en question.  Notez que cet entête est similaire à l'entête de réponse HTTP/1.1 Allow, mais qu'il est utilisé de manière stricte dans le contexte du contrôle d'accès.  Le serveur envoie aussi Access-Control-Allow-Headers avec une valeur de X-PINGOTHER, confirmant en cela que c'est un entête permis dans le cadre de la requête effective.  Tout comme Access-Control-Allow-Methods, Access-Control-Allow-Headers est une liste séparée par des virgules d'entêtes acceptés.  Enfin, Access-Control-Max-Age indique la durée en secondes pendant laquelle la requête de pré-vérification peut être mise en cache sans qu'il soit nécessaire d'en envoyer une autre. Ici, 1728000 secondes est 20 jours.

Requêtes avec habilitations

La possibilité la plus intéressante exposée par l'objet XMLHttpRequest et par le contrôle d'accès (Access Control) est de créer des requêtes habilitées qui ont connaissance des cookies HTTP et des informations d'authentification en HTTP.  Par défaut, dans les invocations XMLHttpRequest croisées (cross-site) les navigateurs ne vont pas envoyerles habilitations.  Un tag spécifique doit être positionné dans l'objet XMLHttpRequest quand il est invoqué.

Dans cet exemple, le contenu chargé originellement de http://foo.example effecture une simple requête GET vers une ressource de http://bar.other qui positionne les cookies.  Le contenu dur foo.example peut contenir du JavaScript similaire à :

var invocation = new XMLHttpRequest();
var url = 'http://bar.other/resources/credentialed-content/';
    
function callOtherDomain(){
  if(invocation) {
    invocation.open('GET', url, true);
    invocation.withCredentials = true;
    invocation.onreadystatechange = handler;
    invocation.send(); 
  }

La ligne 7 montre la propriété de XMLHttpRequest qui doit être positionnée pour rendre effective l'invocation avec les Cookies, pour ne pas la nommer la valeur logique withCredentials.  Par défaut, l'invocation est faite sans les Cookies.  Comme il s'agit ici d'un requête GET simple, elle n'est pas pré-vérifiée, mais le navigateur rejettera toute réponse qui n'a pas d'entête Access-Control-Allow-Credentials: true, et NE RENDRA PAS disponible la réponse au contenu web qui l'a demandé.

Voyez ici un échantillon de l'change entre le client et le serveur:

GET /resources/access-control-with-credentials/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Referer: http://foo.example/examples/credential.html
Origin: http://foo.example
Cookie: pageAccess=2


HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:34:52 GMT
Server: Apache/2.0.61 (Unix) PHP/4.4.7 mod_ssl/2.0.61 OpenSSL/0.9.7e mod_fastcgi/2.4.2 DAV/2 SVN/1.4.2
X-Powered-By: PHP/5.2.6
Access-Control-Allow-Origin: http://foo.example
Access-Control-Allow-Credentials: true
Cache-Control: no-cache
Pragma: no-cache
Set-Cookie: pageAccess=3; expires=Wed, 31-Dec-2008 01:34:53 GMT
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 106
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain


[text/plain payload]

Bien que la ligne 12 contienne le cookie destiné au contenu sur http://bar.other, si bar.other ne répondait pas avec un Access-Control-Allow-Credentials: true (ligne 20) la réponse serait ignorée et rendue indisponible.  Note importante: quand on répond à une requête avec informations de compte, le serveur doit spécifier un domaine, et ne peut pas utiliser de jokers (wildcards).  L'exemple ci-dessus échouerait si l'entête utilisait des jokers comme dans: Access-Control-Allow-Origin: *.  Puisque Access-Control-Allow-Origin mentionne explicitement http://foo.example, le contenu lié aux aspects de compte (credentials) est retourné au contenu web qui l'a demandé.  Notez qu'à la ligne 23, un autre cookie est positionné.

Tous ces exemples peuvet être consultés en fonctionnement ici.  La prochaine section traite des entêtes HTTP de manière plus précise.

Les entêtes HTTP de réponse

Cette section liste les entêtes de réponses HTTP que le serveur renvoie au sujet des requêtes contrôle d'accès (Access Control) comme définis par la spécification Cross-Origin Resource Sharing. La section précédent donne un aperçu de ceux-ci en action.

Access-Control-Allow-Origin

Une ressource peut renvoyer un entête Access-Control-Allow-Origin avec la syntaxe suivante :

Access-Control-Allow-Origin: <origin> | *

Le paramètre origin spécifie une URI qui peut accèder à la ressource. Le navigateur doit suivre cela.  Pour une requête sans habilitations (credentials), le serveur peut spécifier "*" comme  joker (wildcards), autorisant ainsi toutes origines à accèder à la ressource.

Par exemple, pour autoriser http://mozilla.com à accèder la ressource, vous pouvez spécifier:

Access-Control-Allow-Origin: http://mozilla.com

Access-Control-Expose-Headers

Requires Gecko 2.0(Firefox 4 / Thunderbird 3.3 / SeaMonkey 2.1)

Cette entête laisse le serveur mettre une liste blanche d'entêtes auquel le navigateur est autorisé à accèder. Par exemple:

Access-Control-Expose-Headers: X-My-Custom-Header, X-Another-Custom-Header

Ceci autorise les entêtes X-My-Custom-Header et X-Another-Custom-Header à être présentés au navigateur.

Access-Control-Max-Age

Cette entête indique combien de temps les résultats peuvent être mis en cache. Pour un exemple de requête pré-vérifiée, allez voir les exemples au-dessus.

Access-Control-Max-Age: <delta-seconds>

Le paramètre  delta-seconds indique la durée en nombre de seconds durant lequel le résultat peut être caché.

Access-Control-Allow-Credentials

Cet entête indique si la réponse peut être ou non présentée lorsque le tag credentials est vrai.  Lorsqu'il est présent dans une réponse à une requête pré-vérifiée, cet entête indique si la requête peut être fait ou non en utilisant les habilitations (credentials). Notez que les requêtes GET simple ne sont pas pré-vérifiée, et par conséquent si une requête est faite sur une ressource avec des habilitations (credentials), si l'entête n'est pas renvoyé via la ressource, la réponse sera ignorée par le navigateur et non retournée au contenu web.

Access-Control-Allow-Credentials: true | false

Les requêtes d'habilitations Les requêtes d'habilitations sont détaillées plus haut.

Access-Control-Allow-Methods

Spécifie la méthode ou les méthodes autorisé lors de l'accès à la resource. Cet entête est utilisé en réponse à une requête pré-vérifiée. Les conditions sous lesquels une requête est pré-vérifiée sont discutées au-dessus.

Access-Control-Allow-Methods: <method>[, <method>]*

Un exemple de requête pré-vérifiée est donnée plus haut, avec un exemple qui envoie cet entête au navigateur.

Access-Control-Allow-Headers

Cet entête utilisé en réponse à une requête pré-vérifiée pour indiquer quels entêtes peuvent être utilisés lorsque la requête actuelle est faite.

Access-Control-Allow-Headers: <field-name>[, <field-name>]*

Les entêtes HTTP de la requête

Cette section liste les entêtes que le client peuvent utiliser lorsqu'il crée des requête HTTP pour utiliser la fonctionnalité Cross-Origin Resource Sharing. Notez que les entêtes sont mis pour vous lorsque vous crée l'appel aux serveurs. Les développeurs qui utilise la fonction cross-site de XMLHttpRequest ne doivent pas mettre, via le code, d'entête de requêtes cross-origing sharing .

Origin

Indique l'origine de la requête d'accès cross-site ou la requête pré-vérifiée.

Origin: <origin>

L'origine est l'URI qui indique le serveur depuis lequel la requête a été initié.  Cela n'inclue pas l'information sur le chemin, mais uniquement le nom du serveur.

Note: L'origine peut être une chaine de caratères vide; ceci est utile, par exemple, si la source est une data URL.

Notez que pour toutes requêtes de contrôle d'accès, l'entête ORIGIN est toujours envoyé.

Access-Control-Request-Method

Cet entête utilisé lorsqu'une requête pré-vérifiée est émise pour faire connaitre au serveur quel méthode sera utilisé lorsque la requêtre actuelle sera faite .

Access-Control-Request-Method: <method>

Des exemples de cette usage peuvent être trouvés plus haut.

Access-Control-Request-Headers

Cet entête utilisé lorsqu'une requête pré-vérifiée est émise pour indiquer au serveur quels seront les entêtes HTTP utilisés lorsque sera fait la requête actuelle.

Access-Control-Request-Headers: <field-name>[, <field-name>]*

Des exemples de cette usage peuvent être trouvé plus haut.

Compatibilité navigateurs

Fonctionnalité Chrome Firefox (Gecko) Internet Explorer Opera Safari
Support simple 4 3.5 8 (via XDomainRequest)
10
12 4
Fonctionnalité Android Chrome Android Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile
Support simple 2.1 yes yes ? 12 3.2

Note

Internet Explorer 8 et 9 expose CORS via l'objet XDomainRequest, mais une implémentation complète est disponible dans IE 10. Lorsque Firefox 3.5  a introduit le support pour les requêtes XMLHttpRequests cross-site et les polices de caratères WEB, certaines requêtes ont été limité jusqu'à une version ultérieur. En particulier, Firefox 7 a introduit la capacité de faire des requêtes HTTP cross-site pour les textures WebGL, et Firefox 9 a ajouté le support pour les Images dessinées via le canvas en utilisant drawImage.

Voir aussi

Étiquettes et contributeurs liés au document

 Contributeurs à cette page : gierschv, ebear, Ltrlg, dattaz, nlaug, cguillemette, Zzortell, fmasy, patboens
 Dernière mise à jour par : gierschv,