Utilisation de la stratégie de sécurité de contenu (CSP) pour contrôler les ressources qui peuvent être exécutées
Pour contrôler le contenu qui peut être exécuté par votre extension, dans le fichier de manifest.json
l’extension, utilisez la content_security_policy
clé et sa valeur de chaîne de stratégie, selon la syntaxe suivante :
{
...,
"content_security_policy": "[policy string]"
...
}
Par exemple, voici la stratégie de sécurité du contenu par défaut, comme décrit ci-dessous dans Restrictions de stratégie par défaut :
{
...,
"content_security_policy": "script-src 'self'; object-src 'self'; worker-src 'self'"
...
}
Pour atténuer une grande classe de problèmes potentiels de script intersites, le système d’extension Microsoft Edge intègre la stratégie de sécurité du contenu (CSP). Csp introduit des stratégies strictes qui rendent les extensions plus sécurisées par défaut, et vous permet de créer et d’appliquer des règles régissant les types de contenu qui peuvent être chargés et exécutés par vos extensions et applications.
En général, csp fonctionne comme un mécanisme de liste de blocs/d’autorisation pour les ressources chargées ou exécutées par votre extension. La définition d’une stratégie raisonnable pour votre extension vous permet d’examiner attentivement les ressources dont votre extension a besoin et de demander au navigateur de s’assurer qu’il s’agit des seules ressources auxquelles votre extension a accès. Les stratégies fournissent une sécurité au-delà des autorisations de l’hôte que votre extension demande ; il s’agit d’une couche supplémentaire de protection, et non d’un remplacement.
En revanche, dans une page web, une telle stratégie est définie via un en-tête HTTP ou via un meta
élément. Mais à l’intérieur du système d’extension Microsoft Edge, un en-tête HTTP ou un meta
élément n’est pas un mécanisme approprié.
Voir :
- Stratégie de sécurité du contenu (CSP) sur MDN.
- Manifest - Content Security Policy in Chrome Extensions>Reference.
Restrictions de stratégie par défaut
Les packages qui ne définissent pas de manifest_version
n’ont pas de stratégie de sécurité de contenu par défaut.
Les packages qui utilisent manifest_version
ont la stratégie de sécurité de contenu par défaut suivante :
script-src 'self'; object-src 'self'; worker-src 'self'
La stratégie ajoute la sécurité en limitant les extensions et les applications de trois manières :
Eval et les fonctions associées sont désactivées
Le code comme celui-ci ne fonctionne pas :
alert(eval("foo.bar.baz"));
window.setTimeout("alert('hi')", 10);
window.setInterval("alert('hi')", 10);
new Function("return foo.bar.baz");
L’évaluation des chaînes de JavaScript comme celle-ci est un vecteur d’attaque XSS courant. Au lieu de cela, vous devez écrire du code comme suit :
alert(foo && foo.bar && foo.bar.baz);
window.setTimeout(function() { alert('hi'); }, 10);
window.setInterval(function() { alert('hi'); }, 10);
function() { return foo && foo.bar && foo.bar.baz };
JavaScript inline ne sont pas exécutés
Les javascripts inline ne sont pas exécutés. Cette restriction interdit à la fois les blocs inline <script>
et les gestionnaires d’événements inline, tels que <button onclick="...">
.
La première restriction supprime une énorme classe d’attaques de script intersites en vous rendant impossible d’exécuter accidentellement le script fourni par un tiers malveillant. Toutefois, cela vous oblige à écrire votre code avec une séparation propre entre le contenu et le comportement. Un exemple peut rendre cela plus clair. Vous pouvez essayer d’écrire une fenêtre contextuelle d’action de navigateur en tant que simple pop-up.html
contenant les éléments suivants :
<!doctype html>
<html>
<head>
<title>My Awesome Pop-up!</title>
<script>
function awesome() {
// do something awesome!
}
function totallyAwesome() {
// do something TOTALLY awesome!
}
function clickHandler(element) {
setTimeout("awesome(); totallyAwesome()", 1000);
}
function main() {
// Initialization work goes here.
}
</script>
</head>
<body onload="main();">
<button onclick="clickHandler(this)">
Click for awesomeness!
</button>
</body>
</html>
Mais trois choses doivent changer pour que cela fonctionne comme vous l’attendez :
La
clickHandler
définition doit être déplacée dans un fichier JavaScript externe (popup.js
peut être une bonne cible).Les définitions du gestionnaire d’événements inline doivent être réécrites en termes de
addEventListener
et extraites danspopup.js
. Si vous démarrez actuellement votre programme à l’aide de code tel que<body onload="main();">
, envisagez de le remplacer par un raccordement à l’événementDOMContentLoaded
du document ou à l’événementload
de la fenêtre, en fonction de vos besoins. Utilisez le premier, car il se déclenche généralement plus rapidement.L’appel
setTimeout
doit être réécrit pour éviter de convertir la chaîne"awesome(); totallyAwesome()"
en JavaScript pour l’exécution.
Ces modifications peuvent ressembler à ce qui suit :
function awesome() {
// Do something awesome!
}
function totallyAwesome() {
// do something TOTALLY awesome!
}
function awesomeTask() {
awesome();
totallyAwesome();
}
function clickHandler(e) {
setTimeout(awesomeTask, 1000);
}
function main() {
// Initialization work goes here.
}
// Add event listeners once the DOM has fully loaded by listening for the
// `DOMContentLoaded` event on the document, and adding your listeners to
// specific elements when it triggers.
document.addEventListener('DOMContentLoaded', function () {
document.querySelector('button').addEventListener('click', clickHandler);
main();
});
<!doctype html>
<html>
<head>
<title>My Awesome Pop-up!</title>
<script src="popup.js"></script>
</head>
<body>
<button>Click for awesomeness!</button>
</body>
</html>
Seules les ressources de script et d’objet locales sont chargées
Les ressources de script et d’objet ne peuvent être chargées qu’à partir du package d’extension, et non à partir du web à grande échelle. Cela garantit que votre extension exécute uniquement le code que vous avez spécifiquement approuvé, ce qui empêche un attaquant réseau actif de rediriger de manière malveillante votre demande pour une ressource.
Au lieu d’écrire du code qui dépend du chargement de jQuery (ou de toute autre bibliothèque) à partir d’un CDN externe, envisagez d’inclure la version spécifique de jQuery dans votre package d’extension. Autrement dit, au lieu de :
<!doctype html>
<html>
<head>
<title>My Awesome Pop-up!</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
</head>
<body>
<button>Click for awesomeness!</button>
</body>
</html>
Utilisez plutôt l’approche suivante. Téléchargez le fichier, incluez-le dans votre package et écrivez :
<!doctype html>
<html>
<head>
<title>My Awesome Pop-up!</title>
<script src="jquery.min.js"></script>
</head>
<body>
<button>Click for awesomeness!</button>
</body>
</html>
Assouplissement de la stratégie par défaut
Vous pouvez autoriser l’exécution des types de script suivants :
Les détails sont ci-dessous.
Script inline
Les scripts inline peuvent être autorisés en spécifiant le hachage codé en base64 du code source dans la stratégie. Ce hachage doit être préfixé par l’algorithme de hachage utilisé (sha256, sha384 ou sha512). Pour obtenir un exemple, consultez Utilisation du hachage W3C > pour <les éléments de script>.
Script distant
Si vous avez besoin de ressources JavaScript ou d’objets externes, vous pouvez assouplir la stratégie dans une mesure limitée en autorisant les origines sécurisées à partir desquelles les scripts doivent être acceptés. Vérifiez que les ressources d’exécution chargées avec des autorisations élevées d’une extension sont exactement les ressources attendues et ne sont pas remplacées par un attaquant réseau actif. Comme les attaques de l’intercepteur sont à la fois triviales et indétectables sur HTTP, ces origines ne sont pas acceptées.
Actuellement, vous pouvez autoriser les origines qui ont les schémas suivants : blob
, filesystem
, https
et extension
. La partie hôte de l’origine doit être spécifiée explicitement pour les https
schémas et extension
. Les caractères génériques tels que https :, https://*
et https://*.com
ne sont pas autorisés ; les caractères génériques de sous-domaine tels que https://*.example.com
sont autorisés. Les domaines de la liste Suffixe public sont également vus comme des domaines génériques de niveau supérieur. Pour charger une ressource à partir de ces domaines, le sous-domaine doit être répertorié explicitement. Par exemple, https://*.cloudfront.net
n’est pas valide, mais https://XXXX.cloudfront.net
et https://*.XXXX.cloudfront.net
peut être allowlisted
.
Pour faciliter le développement, les ressources chargées via HTTP à partir de serveurs sur votre ordinateur local peuvent être allowlisted
. Vous pouvez autoriser les sources de script et d’objet sur n’importe quel port de http://127.0.0.1
ou http://localhost
.
Remarque
La restriction par rapport aux ressources chargées sur HTTP s’applique uniquement aux ressources qui sont directement exécutées. Vous êtes toujours libre, par exemple, d’établir XMLHTTPRequest
des connexions à n’importe quelle origine de votre choix ; la stratégie par défaut ne restreint connect-src
ni l’une des autres directives CSP de quelque manière que ce soit.
Une définition de stratégie souple qui permet de charger des ressources de script à partir de example.com
https peut ressembler à ceci :
"content_security_policy": "script-src 'self' https://example.com; object-src 'self'"
Remarque
et object-src
sont tous deux script-src
définis par la stratégie. Microsoft Edge n’accepte pas une stratégie qui ne limite pas chacune de ces valeurs à (au moins) «self
».
JavaScript évalué
La stratégie par rapport eval()
à et les fonctions associées telles que setTimeout(String)
, setInterval(String)
et new Function(String)
peuvent être assouplies en ajoutant unsafe-eval
à votre stratégie :
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'"
Toutefois, vous devez éviter d’assouplir les stratégies. Ces types de fonctions sont des vecteurs d’attaque XSS notoires.
Renforcement de la stratégie par défaut
Vous pouvez renforcer cette politique dans la mesure où votre extension le permet, afin d’accroître la sécurité, au détriment de la commodité. Pour spécifier que votre extension peut uniquement charger des ressources de n’importe quel type (images, etc.) à partir du package d’extension associé, par exemple, une stratégie de default-src 'self'
peut être appropriée.
Scripts de contenu
La stratégie en cours s’applique aux pages d’arrière-plan et aux pages d’événements de l’extension. La façon dont les scripts de contenu s’appliquent aux scripts de contenu de l’extension est plus complexe.
Les scripts de contenu ne sont généralement pas soumis au csp de l’extension. Étant donné que les scripts de contenu ne sont pas html, l’impact main de cela est qu’ils peuvent utiliser eval
même si le fournisseur de solutions Cloud de l’extension ne spécifie unsafe-eval
pas , bien que cela ne soit pas recommandé. En outre, le csp de la page ne s’applique pas aux scripts de contenu. Les balises que les scripts de contenu créent et placent dans le DOM de la page sur laquelle ils s’exécutent sont plus complexes <script>
. Ceux-ci sont référencés en tant que scripts injectés DOM à l’avenir.
Les scripts injectés dom qui s’exécutent immédiatement après l’injection dans la page s’exécutent comme prévu. Imaginez un script de contenu avec le code suivant comme exemple simple :
document.write("<script>alert(1);</script>");
Ce script de contenu provoque un alert
immédiatement sur le document.write()
. Notez que cela s’exécute quelle que soit la stratégie spécifiée par une page. Toutefois, le comportement devient plus compliqué à la fois à l’intérieur de ce script injecté DOM et pour tout script qui ne s’exécute pas immédiatement lors de l’injection.
Imaginez que votre extension s’exécute sur une page qui fournit un fournisseur de services de configuration associé qui spécifie script-src 'self'
. Imaginez maintenant que le script de contenu exécute le code suivant :
document.write("<button onclick='alert(1);'>click me</button>'");
Si un utilisateur clique sur ce bouton, le onclick
script ne s’exécute pas. Cela est dû au fait que le script n’a pas été exécuté immédiatement et que le code qui n’est pas interprété tant que l’événement click
ne se produit pas n’est pas considéré comme faisant partie du script de contenu, de sorte que le csp de la page (et non de l’extension) limite le comportement. Et étant donné que ce fournisseur csp ne spécifie unsafe-inline
pas , le gestionnaire d’événements inline est bloqué.
La bonne façon d’implémenter le comportement souhaité dans ce cas consiste à ajouter le onclick
gestionnaire en tant que fonction à partir du script de contenu, comme suit :
document.write("<button id='mybutton'>click me</button>'");
var button = document.getElementById('mybutton');
button.onclick = function() {
alert(1);
};
Un autre problème similaire se produit si le script de contenu exécute ce qui suit :
var script = document.createElement('script');
script.innerHTML = 'alert(1);'
document.getElementById('body').appendChild(script);
Dans ce cas, le script s’exécute et l’alerte s’affiche. Toutefois, considérez le cas suivant :
var script = document.createElement('script');
script.innerHTML = 'eval("alert(1);")';
=document.getElementById('body').appendChild(script);
Pendant l’exécution du script initial, l’appel à eval
est bloqué. Autrement dit, bien que le runtime de script initial soit autorisé, le comportement dans le script est réglementé par le fournisseur de solutions Cloud de la page. Par conséquent, selon la façon dont vous écrivez des scripts injectés dom dans votre extension, les modifications apportées au fournisseur de solutions cloud de la page peuvent affecter le comportement de votre extension.
Étant donné que les scripts de contenu ne sont pas affectés par le fournisseur de solutions Cloud de la page, c’est une excellente raison de placer autant de comportement que possible de votre extension dans le script de contenu, plutôt que des scripts injectés dom.
Voir aussi
- Stratégie de sécurité du contenu (CSP) sur MDN.
- Manifest - Content Security Policy in Chrome Extensions>Reference.
Remarque
Les parties de cette page sont des modifications basées sur le travail créé et partagé par Google et utilisées conformément aux termes décrits dans la licence internationale Creative Commons Attribution 4.0. La page d’origine se trouve ici.
Cette œuvre est concédée sous licence creative commons attribution 4.0 international.