diff --git a/files/en-us/web/http/csp/csp-overview.svg b/files/en-us/web/http/csp/csp-overview.svg new file mode 100644 index 000000000000000..761c34f708e2c71 --- /dev/null +++ b/files/en-us/web/http/csp/csp-overview.svg @@ -0,0 +1,3 @@ + + +
Content-Security-Policy: default-src 'self'; img-src 'self' example.com;
default-src 'self'
img-src 'self' example.com
\ No newline at end of file diff --git a/files/en-us/web/http/csp/csp-source-expressions.svg b/files/en-us/web/http/csp/csp-source-expressions.svg new file mode 100644 index 000000000000000..482cb5f19847bd8 --- /dev/null +++ b/files/en-us/web/http/csp/csp-source-expressions.svg @@ -0,0 +1,3 @@ + + +
Content-Security-Policy: default-src 'self'; img-src 'self' example.com;
Content-Security-Policy: default-src 'self'; img-src 'self' example.com;
default-src 'self'
default-src 'self'
img-src 'self' example.com
img-src 'self' example.com
'self'
'self'
example.com
example.com
'self'
'self'
Source expressions
Source expressions
Fetch directives
Fetch directives
\ No newline at end of file diff --git a/files/en-us/web/http/csp/index.md b/files/en-us/web/http/csp/index.md index 7d5086943e0afac..fe031703b481c9e 100644 --- a/files/en-us/web/http/csp/index.md +++ b/files/en-us/web/http/csp/index.md @@ -2,139 +2,508 @@ title: Content Security Policy (CSP) slug: Web/HTTP/CSP page-type: guide -browser-compat: http.headers.Content-Security-Policy --- {{HTTPSidebar}} -**Content Security Policy** ({{Glossary("CSP")}}) is an added layer of security that helps to detect and mitigate certain types of attacks, -including Cross-Site Scripting ({{Glossary("Cross-site_scripting", "XSS")}}) and data injection attacks. -These attacks are used for everything from data theft, to site defacement, to malware distribution. +**Content Security Policy** (CSP) is a feature that helps to prevent or minimize the risk of certain types of security threats. It consists of a series of instructions from a website to a browser, which instruct the browser to place restrictions on the things that the code comprising the site is allowed to do. -CSP is designed to be fully backward compatible (except CSP version 2 where there are some explicitly-mentioned inconsistencies in backward compatibility; more details [here](https://www.w3.org/TR/CSP2/) section 1.1). -Browsers that don't support it still work with servers that implement it, and vice versa. Browsers that don't support CSP ignore it, functioning as usual; they will only apply the protections of the standard [same-origin policy](/en-US/docs/Web/Security/Same-origin_policy) without the further restrictions that the CSP would add. +The primary use case for CSP is to control which resources, in particular JavaScript resources, a document is allowed to load. This is mainly used as a defense against {{glossary("cross-site scripting")}} (XSS) attacks, in which an attacker is able to inject malicious code into the victim's site. -To enable CSP, you need to configure your web server to return the {{HTTPHeader("Content-Security-Policy")}} HTTP header. -(Sometimes you may see mentions of the `X-Content-Security-Policy` header, but that's an older version and you don't need to specify it anymore.) +A CSP can have other purposes as well, including defending against {{glossary("clickjacking")}} and helping to ensure that a site's pages will be loaded over HTTPS. -Alternatively, the {{HTMLElement("meta")}} element can be used to configure a policy, for example: +In this guide we'll start by describing how a CSP is delivered to a browser and what it looks like at a high level. -```html - +Then we'll describe how it can be used to [control which resources are loaded](#controlling_resource_loading) to protect against XSS, and then other use cases such as [clickjacking protection](#clickjacking_protection) and [upgrading insecure requests](#upgrading_insecure_requests). Note that there's no dependency between the different use cases: if you want to add clickjacking protection but not XSS mitigation, you can just add the directives for that use case. + +Finally we'll describe [strategies for deploying a CSP](#testing_your_policy) and tools that can help to make this process easier. + +## CSP overview + +A CSP should be delivered to the browser in the {{httpheader("Content-Security-Policy")}} response header. It should be set on all responses to all requests, not just the main document. + +You can also specify it using the [`http-equiv`](/en-US/docs/Web/HTML/Element/meta#http-equiv) attribute of your document's {{htmlelement("meta")}} element, and this is a useful option for some use cases, such as a client-side-rendered {{glossary("SPA", "single page app")}} which has only static resources, because you can then avoid relying on any server infrastructure. However, this option does not support all CSP features. + +The policy is specified as a series of _directives_, separated by semi-colons. Each directive controls a different aspect of the security policy. Each directive has a name, followed by a space, followed by a value. Different directives can have different syntaxes. + +For example, consider the following CSP: + +```http +Content-Security-Policy: default-src 'self'; img-src 'self' example.com ``` +It sets two directives: + +- the `default-src` directive is set to `'self'` +- the `img-src` directive is set to `'self' example.com`. + +![A CSP broken into its directives.](csp-overview.svg) + +The first directive, `default-src`, tells the browser to load only resources that are same-origin with the document, unless other more specific directives set a different policy for other resource types. The second, `img-src`, tells the browser to load images that are same-origin or that are served from `example.com`. + +In the next section, we'll look at the tools available to control resource loads, which is the main function of a CSP. + +## Controlling resource loading + +A CSP can be used to control the resources that a document is allowed to load. This is primarily used for protection against cross-site scripting (XSS) attacks. + +In this section we'll first see how controlling resource loads can help protect against XSS, then at the tools CSP provides to control what resources are loaded. Finally we'll describe one particular recommended strategy, which is called a "Strict CSP". + +### XSS and resource loading + +A cross-site scripting (XSS) attack is one in which an attacker is able to execute their code in the context of the target website. This code is then able to do anything that the website's own code could do, including, for example: + +- access or modify the content of the site's loaded pages +- access or modify content in local storage +- make HTTP requests with the user's credentials, enabling them to impersonate the user or access sensitive data + +An XSS attack is possible when a website accepts some input which might have been crafted by an attacker (for example, URL parameters, or a comment on a blog post) and then includes it in the page without _sanitizing_ it: that is, without ensuring that it can't be executed as JavaScript. + +Websites should protect themselves against XSS by sanitizing this input before including it in the page. A CSP provides a complementary protection, which can protect the website even if sanitization fails. + +If sanitization does fail, there are various forms the injected malicious code can take in the document, including: + +- A {{htmlelement("script")}} tag that links to a malicious source: + + ```html + + ``` + +- A ` + ``` + +- An inline event handler: + + ```html + + ``` + +- A `javascript:` URL: + + ```html + + ``` + +- A string argument to an unsafe API like [`eval()`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval): + + ```js + eval("console.log(`You've been hacked!`)"); + ``` + +A CSP can provide protection against all of these. With a CSP, you can: + +- define the permitted sources for JavaScript files and other resources, effectively blocking loads from `https://evil.com` +- disable inline script tags +- allow only script tags which have the correct nonce or hash set +- disable inline event handlers +- disable `javascript:` URLs +- disable dangerous APIs like `eval()` + +In the next section we'll go over the tools CSP provides to do these things. + > [!NOTE] -> Some features, such as sending CSP violation reports, are only available when using the HTTP headers. +> Setting a CSP is not an alternative to sanitizing input. Websites should sanitize input _and_ set a CSP, providing defense in depth against XSS. + +### Fetch directives + +Fetch directives are used to specify a particular category of resource that a document is allowed to load — such as JavaScript, CSS stylesheets, images, fonts, and so on. -## Threats +There are different fetch directives for different types of resource. For example: -### Mitigating cross-site scripting +- [`script-src`](/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src) sets allowed sources for JavaScript. +- [`style-src`](/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/style-src) sets allowed sources for CSS stylesheets. +- [`img-src`](/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/img-src) sets allowed sources for images. -A primary goal of CSP is to mitigate and report XSS attacks. XSS attacks exploit the browser's trust in the content received from the server. -Malicious scripts are executed by the victim's browser because the browser trusts the source of the content, even when it's not coming from where it seems to be coming from. +One special fetch directive is `default-src`, which sets a fallback policy for all resources whose directives are not explicitly listed. -CSP makes it possible for server administrators to reduce or eliminate the vectors by which XSS can occur by specifying the domains that the browser should consider to be valid sources of executable scripts. -A CSP compatible browser will then only execute scripts loaded in source files received from those allowed domains, ignoring all other scripts (including inline scripts and event-handling HTML attributes). +For the complete set of fetch directives, see the [reference documentation](/en-US/docs/Web/HTTP/Headers/Content-Security-Policy#fetch_directives). -As an ultimate form of protection, sites that want to never allow scripts to be -executed can opt to globally disallow script execution. +Each fetch directive is specified as either the single keyword `'none'` or one or more _source expressions_, separated by spaces. When more than one source expression is listed: if any of the methods allow the resource, then the resource is allowed. -### Mitigating packet sniffing attacks +For example, the CSP below sets two fetch directives: -In addition to restricting the domains from which content can be loaded, the server can specify which protocols are allowed to be used; -for example (and ideally, from a security standpoint), a server can specify that all content must be loaded using HTTPS. -A complete data transmission security strategy includes not only enforcing HTTPS for data transfer, but also marking all [cookies with the `secure` attribute](/en-US/docs/Web/HTTP/Cookies) and providing automatic redirects from HTTP pages to their HTTPS counterparts. -Sites may also use the {{HTTPHeader("Strict-Transport-Security")}} HTTP header to ensure that browsers connect to them only over an encrypted channel. +- `default-src` is given the single source expression `'self'` +- `img-src` is given two source expressions: `'self'` and `example.com` -## Using CSP +![CSP diagram showing source expressions](csp-source-expressions.svg) -Configuring Content Security Policy involves adding the {{HTTPHeader("Content-Security-Policy")}} HTTP header to a web page and giving it values to control what resources the user agent is allowed to load for that page. -For example, a page that uploads and displays images could allow images from anywhere, but restrict a form action to a specific endpoint. -A properly designed Content Security Policy helps protect a page against a cross-site scripting attack. -This article explains how to construct such headers properly, and provides examples. +The effect of this is that: -### Specifying your policy +- images must be either same-origin with the document, or loaded from `example.com` +- all other resources must be same-origin with the document. -You can use the {{HTTPHeader("Content-Security-Policy")}} HTTP header to specify your policy, like this: +In the next few sections we'll describe some of the ways you can use source expressions to control resource loads. Note that although we're describing them separately, these expressions can in general be combined: for example, a single fetch directive may include nonces as well as hostnames. + +#### Blocking resources + +To block a resource type entirely, use the `'none'` keyword. For example, the following directive blocks all {{htmlelement("object")}} and {{htmlelement("embed")}} resources: ```http -Content-Security-Policy: policy +Content-Security-Policy: object-src 'none' ``` -The policy is a string containing the policy directives describing your Content Security Policy. +Note that `'none'` cannot be combined with any other method in a particular directive: in practice, if any other source expressions are given alongside `'none'`, then they are ignored. + +#### Nonces -### Writing a policy +A `nonce` is the recommended approach for restricting the loading of {{htmlelement("script")}} and {{htmlelement("style")}} resources. -A policy is described using a series of policy directives, each of which describes the policy for a certain resource type or policy area. -Your policy should include a {{CSP("default-src")}} policy directive, which is a fallback for other resource types when they don't have policies of their own (for a complete list, see the description of the {{CSP("default-src")}} directive). -A policy needs to include a {{CSP("default-src")}} or {{CSP("script-src")}} directive to prevent inline scripts from running, as well as blocking the use of `eval()`. -A policy needs to include a {{CSP("default-src")}} or {{CSP("style-src")}} directive to restrict inline styles from being applied from a {{HTMLElement("style")}} element or a `style` attribute. -There are specific directives for a wide variety of types of items, so that each type can have its own policy, including fonts, frames, images, audio and video media, scripts, and workers. +With a nonce, the server generates a random value for every HTTP response, and includes it in a `script-src` and/or a `style-src` directive: -For a complete list of policy directives, see the reference page for the [Content-Security-Policy header](/en-US/docs/Web/HTTP/Headers/Content-Security-Policy). +```http +Content-Security-Policy: + script-src 'nonce-416d1177-4d12-4e3b-b7c9-f6c409789fb8' +``` -## Examples: Common use cases +The server then includes this value as the value of the `nonce` attribute of all the ` + +

Hello world

+ `; +} + +app.get("/", (req, res) => { + const nonce = crypto.randomUUID(); + res.setHeader("Content-Security-Policy", `script-src 'nonce-${nonce}'`); + res.send(content(nonce)); +}); +``` + +On every request, the server generates a new nonce, inserts it into the CSP and into the {{htmlelement("script")}} tags in the returned document. Note that the server: + +- generates a new nonce for every request +- can use nonces with both external and inline scripts +- uses the same nonce for all ` + +

Hello world

+ `; + +app.get("/", (req, res) => { + res.setHeader("Content-Security-Policy", csp); + res.send(content); +}); +``` + +Note that: + +- We have a separate hash for every script in the document. +- For the external script "main.js", we also include the `integrity` attribute, and give it the same value. +- Unlike the example using nonces, both the CSP and the content can be static, because the hashes stay the same. This makes hash-based policies more suitable for static pages or websites that rely on client-side rendering. + +#### Scheme-based policies + +Fetch directives can list a scheme, like `https:`, to allow resources that are served using that scheme. This, for example, allows a policy to require HTTPS for all resource loads: ```http -Content-Security-Policy: default-src 'self' +Content-Security-Policy: default-src https: ``` -### Example 2 +#### Location-based policies + +Fetch directives can control resource loads based on where the resource is located. -A website administrator wants to allow content from a trusted domain and all its subdomains (it doesn't have to be the same domain that the CSP is set on.) +The keyword `'self'` allows resources which are same-origin with the document itself: ```http -Content-Security-Policy: default-src 'self' example.com *.example.com +Content-Security-Policy: img-src 'self' ``` -### Example 3 +You can also specify one or more hostnames, potentially including wildcards, and only resources served from those hosts will be allowed. This might be used, for example, to allow content to be served from a trusted CDN. + +```http +Content-Security-Policy: img-src *.example.org +``` -A website administrator wants to allow users of a web application to include images from any origin in their own content, -but to restrict audio or video media to trusted providers, and all scripts only to a specific server that hosts trusted code. +You can specify multiple locations. The following directive allows only images that are same-origin with the current document, or are served from a subdomain of "example.org", or are served from "example.com": ```http -Content-Security-Policy: default-src 'self'; img-src *; media-src example.org example.net; script-src userscript.example.com +Content-Security-Policy: img-src 'self' *.example.org example.com ``` -Here, by default, content is only permitted from the document's origin, with the following exceptions: +#### Inline JavaScript -- Images may load from anywhere (note the "\*" wildcard). -- Media is only allowed from example.org and example.net (and not from subdomains of those sites). -- Executable script is only allowed from userscript.example.com. +If a CSP contains either a `default-src` or a `script-src` directive, then inline JavaScript will not be allowed to execute unless extra measures are taken to enable it. This includes: -### Example 4 +- JavaScript included inside a ` + ``` + +- JavaScript in an inline event handler attribute: + + ```html + + ``` + +- JavaScript in a `javascript:` URL: + + ```html + + ``` + +The `unsafe-inline` keyword can be used to override this restriction. For example, the following directive requires all resources to be same-origin, but allows inline JavaScript: + +```http example-bad +Content-Security-Policy: default-src 'self' 'unsafe-inline' +``` + +> [!WARNING] +> Developers should avoid `'unsafe-inline'`, because it defeats much of the purpose of having a CSP. Inline JavaScript is one of the most common XSS vectors, and one of the most basic goals of a CSP is to prevent its uncontrolled use. -A website administrator for an online banking site wants to ensure that all its content is loaded using TLS, in order to prevent attackers from eavesdropping on requests. +Inline ` + + +

Example page!

+ + +``` + +It includes a script "main.js", which creates and adds another script, "main2.js": + +```js +console.log("hello"); + +const scriptElement = document.createElement("script"); +scriptElement.src = `main2.js`; + +document.head.appendChild(scriptElement); +``` + +We serve our document with a CSP like this: + +```http +Content-Security-Policy: + script-src 'sha256-gEh1+8U9S1vkEuQSmmUMTZjyNSu5tIoECP4UXIEjMTk=' +``` + +The "main.js" script will be allowed to load, because its hash matches the value in the CSP. But its attempt to load "main2.js" will fail. + +If we add `'strict-dynamic'` to the CSP, then "main.js" will be allowed to load "main2.js": ```http -Content-Security-Policy: default-src https://onlinebanking.example.com +Content-Security-Policy: + script-src 'sha256-gEh1+8U9S1vkEuQSmmUMTZjyNSu5tIoECP4UXIEjMTk=' + strict-dynamic +``` + +The `'strict-dynamic'` keyword makes it much easier to create and maintain nonce- or hash-based CSPs, especially when a website uses third-party scripts. It does make your CSP less secure, though, because if the scripts you include create ` +``` + +## Clickjacking protection + +The [`frame-ancestors`](/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors) directive can be used to control which documents, if any, are allowed to embed this document in a nested browsing context such as an {{htmlelement("iframe")}}. This is an effective protection against clickjacking attacks, because these attacks depend on embedding the target site in a site controlled by the attacker. + +The syntax of `frame-ancestors` is a subset of the fetch directive syntax: you can provide the single keyword value `'none'` or one or more source expressions. However, the only source expressions you can use are schemes, hostnames, or the `'self'` keyword value. + +Unless you need your site to be embeddable, you should set `frame-ancestors` to `'none'`: + +```http +Content-Security-Policy: frame-ancestors 'none' +``` + +This directive is a more flexible replacement for the {{httpheader("X-Frame-Options")}} header. + +## Upgrading insecure requests + +Web developers are strongly encouraged to serve all their content over HTTPS. In the process of upgrading a site to HTTPS, a site sometimes serves the main document over HTTPS but serves its resources over HTTP, for example, using markup like this: + +```html + ``` -The server permits access only to documents being loaded specifically over HTTPS through the single origin onlinebanking.example.com. +This is called _mixed content_, and the presence of insecure resources greatly weakens the protection afforded by HTTPS. Under the [mixed content algorithm](/en-US/docs/Web/Security/Mixed_content) that browsers implement, if a document is served over HTTPS, insecure resources are categorized into "upgradable content" and "blockable content". Upgradable content is upgraded to HTTPS, and blockable content is blocked, potentially breaking the page. -### Example 5 +The ultimate solution to mixed content is for developers to load all resources over HTTPS. However, even if a site is actually able to serve all content over HTTPS, it can still be very difficult (or even effectively impossible, where archived content is concerned) for a developer to rewrite all the URLs the site uses to load resources. -A website administrator of a web mail site wants to allow HTML in email, as well as images loaded from anywhere, but JavaScript or other potentially dangerous content can only come from the same origin as the mail server. +The [`upgrade-insecure-requests`](/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/upgrade-insecure-requests) directive is intended to solve this problem. This directive doesn't have any value: to set it, just include the directive name: ```http -Content-Security-Policy: default-src 'self' *.example.com; img-src * +Content-Security-Policy: upgrade-insecure-requests ``` -Note that this example doesn't specify a {{CSP("script-src")}}, so the {{CSP("default-src")}} directive will be used for JavaScript sources as a fallback. +If this directive is set on a document, then the browser will automatically upgrade to HTTPS any HTTP URLs in the following cases: + +- requests to load resources (such as images, scripts, or fonts) +- navigation requests (such as link targets) which are same-origin with the document +- navigation requests in nested browsing contexts, such as iframes +- form submissions + +However, top-level navigation requests whose target is a different origin will not be upgraded. + +For example, suppose the document at `https://example.org` is served with a CSP containing the `upgrade-insecure-requests` directive, and the document contains markup like this: + +```html + + +``` + +The browser will automatically upgrade both of these requests to HTTPS. + +Suppose the document also contains this: + +```html +See some more cats! +More cats, on another site! +``` + +The browser will upgrade the first link to HTTPS, but not the second, as it is navigating to a different origin. + +This directive is not a substitute for the {{httpheader("Strict-Transport-Security")}} header (also known as HSTS), because it does not upgrade external links to a site. Sites should include this directive and the `Strict-Transport-Security` header. ## Testing your policy To ease deployment, CSP can be deployed in report-only mode. -The policy is not enforced, but any violations are reported to a provided URI. -Additionally, a report-only header can be used to test a future revision to a policy without actually deploying it. +The policy is not enforced, but any violations are sent to the reporting endpoint specified in the policy. Additionally, a report-only header can be used to test a future revision to a policy without actually deploying it. You can use the {{HTTPHeader("Content-Security-Policy-Report-Only")}} HTTP header to specify your policy, like this: @@ -145,7 +514,9 @@ Content-Security-Policy-Report-Only: policy If both a {{HTTPHeader("Content-Security-Policy-Report-Only")}} header and a {{HTTPHeader("Content-Security-Policy")}} header are present in the same response, both policies are honored. The policy specified in `Content-Security-Policy` headers is enforced while the `Content-Security-Policy-Report-Only` policy generates reports but is not enforced. -## Violation reporting +Note that unlike a normal content security policy, a report-only policy cannot be delivered in a `` element. + +### Violation reporting The recommended method for reporting CSP violations is to use the [Reporting API](/en-US/docs/Web/API/Reporting_API), declaring endpoints in {{HTTPHeader("Reporting-Endpoints")}} and specifying one of them as the CSP reporting target using the `Content-Security-Policy` header's {{CSP("report-to")}} directive. @@ -208,24 +579,9 @@ A typical object might look like this: You need to set up a server to receive reports with the given JSON format and content type. The server handling these requests can then store or process the incoming reports in a way that best suits your needs. -## Specifications - -{{Specifications}} - -## Browser compatibility - -{{Compat}} - -### Compatibility notes - -A specific incompatibility exists in some versions of the Safari web browser, whereby if a Content Security Policy header is set, but not a Same Origin header, -the browser will block self-hosted content and off-site content, and incorrectly report that this is due to the Content Security Policy not allowing the content. - ## See also -- {{HTTPHeader("Content-Security-Policy")}} HTTP Header -- {{HTTPHeader("Content-Security-Policy-Report-Only")}} HTTP Header -- [Content Security in WebExtensions](/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_Security_Policy) -- [CSP in Web Workers](/en-US/docs/Web/HTTP/Headers/Content-Security-Policy#csp_in_workers) -- [Privacy, permissions, and information security](/en-US/docs/Web/Privacy) -- [CSP Evaluator](https://github.com/google/csp-evaluator) - Evaluate your Content Security Policy +- [Mitigate cross-site scripting with a strict Content Security Policy](https://web.dev/strict-csp) on web.dev (2024) +- [Content Security Policy: A successful mess between hardening and mitigation](https://infocondb.org/con/locomocosec/locomocosec-2019/content-security-policy-a-successful-mess-between-hardening-and-mitigation) +- [Content Security Policy Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html) on owasp.org +- [CSP Evaluator](https://csp-evaluator.withgoogle.com/)