【Network Security】Introduction to Content Security Policy (CSP)

Content Security Policy (CSP) is an additional layer of security designed to detect and mitigate certain types of attacks, including cross-site scripting (XSS) and data injection attacks. Whether it's data theft, contamination of website content, or distribution of malware, these attacks are the primary means.

origin

view sourceI found a surprise when I stumbled on the Twitter page .

<!DOCTYPE html>
<html lang="en">
<head><meta charset="utf-8" /><title>Twitter</title><style> body {
      
      background-color: #ffffff;font-family: sans-serif;}a {
      
      color: #1da1f2;}svg {
      
      color: #1da1f2;display: block;fill: currentcolor;height: 21px;margin: 13px auto;width: 24px;} </style>
</head>
<body><noscript><center>If you’re not redirected soon, please <a href="/">use this link</a>.</center></noscript><script nonce="SG0bV9rOanQfzG0ccU8WQw=="> document.cookie = "app_shell_visited=1;path=/;max-age=5";location.replace(location.href.split("#")[0]); </script>
</body>
</html> 

Compared with the source code of other sites that I usually see, it can be said to be very refreshing. There are no messy labels, but the functions are the same. It is particularly confusing, thinking that this is all the source code of the page, but after viewing the Source panel of DevTools, it is easy to know that this is not the real HTML code. But why the source code of the page gives such a refreshing version, I will not study it here.

When I moved my eyes to the script tag, I found an nonceattribute . It, and the cryptic string behind it, managed to pique my curiosity. Looking at the source code of Google's homepage, there are also noncesome applications. Time to find out what nonceis .

! <script nonce="SG0bV9rOanQfzG0ccU8WQw==">document.cookie = "app_shell_visited=1;path=/;max-age=5";location.replace(location.href.split("#")[0]);
</script> 

Content Security Policy (CSP)

To understand nonce, first understand Content-Security-Policy (CSP) .

We all know that browsers have the same-origin policy (same-origin policy) security restrictions, that is, each site is only allowed to load data from the same domain (origin) as itself, and cannot be loaded from resources .https://a.com https://b.comEach site is strictly limited to its own isolated island, which is a sandbox by itself, which is very safe and the entire network will not be disorganized. Mainly, it can solve most security problems. If there is no same-origin policy, malicious code can be easily executed on the browser side and obtain various private information: bank account numbers, social data, etc.

Then how to share data between websites, of course there is a way, learn about CORS).

In reality, the problem is that the same-origin policy is not foolproof. Cross-site scripting (XSS) includes a variety of means to bypass restrictions, formally injecting malicious code into the page to complete information theft or attack. For example, UGC-type sites, because the content relies on users to create, this opens a big hole, allowing the content entered by users to run on the page. Of course, because we all know that there will be injection attacks, anti-XSS filtering of user input has become a standard configuration.

On the other hand, Content-Security-Policy adds a layer of protection to the browser, which can greatly reduce the occurrence of such attacks.

principle

By telling the browser a series of rules, CSP strictly stipulates which resources are allowed in the page and which sources are allowed, and all those not within the specified range are rejected. Compared with the same-origin policy, CSP can be said to be very strict.

There are two ways to implement it:

  • The server adds Content-Security-Policyresponse headers to specify rules
  • Add tags to HTML to specify Content-Security-Policyrules

img

For the convenience of testing, the following examples 标签来开启 CSP 规则。但use some commands that cannot be used, which will be learned later. All restriction directives are only available in response headers.

a simple example

Create an HTML file with the following content:

csp_test.html

<!DOCTYPE html>
<html lang="en">
<head><meta http-equiv="Content-Security-Policy" content="script-src 'self' https://unpkg.com"><title>CSP Test</title>
</head>
<body><script src="https://unpkg.com/react@16/umd/react.development.js"></script>
</body>
</html> 

Open a local server in the directory where the test file is located to access, here use the server that comes with Python:

python -m SimpleHTTPServer 8000 

Then visit localhost:8000 to observe the result:

img

Then we Content-Security-Policychange to disallow any resources and try again:

csp_test.html

<!DOCTYPE html>
<html lang="en">
<head>
- <meta http-equiv="Content-Security-Policy" content="script-src 'self' https://unpkg.com">
+ <meta http-equiv="Content-Security-Policy" content="script-src ‘none’"><title>CSP Test</title>
</head>
<body><script src="https://unpkg.com/react@16/umd/react.development.js"></script>
</body>
</html> 

img

Let's explain the CSP rules set here and understand why resource loading fails.

Regardless of whether the CSP rule is specified in the header or the `` tag, the format of its value is uniform and consists of a series of CSP directives (directive).

Example:

Content-Security-Policy: <policy-directive>; <policy-directive>

Here directive, that is, an instruction, is specified in the CSP specification to detail the source of a certain resource. For example, in the previous example, script-srcspecify which legal sources the script can have, img-srcand specify a picture. The following are commonly used instructions:

  • base-uriRestricts the links that can appear in the `` tab of a page.
  • child-srcLists links available for worker and frame embedding. For example: child-src https://youtube.comIndicates that only video resources can be embedded from Youtube.
  • connect-srcAddress to which connections can be initiated (via XHR, WebSockets or EventSource).
  • font-srcfont source. For example, to use Google web fonts font-src https://themes.googleusercontent.coma rule .
  • form-action`` Address to which the tag can be submitted.
  • frame-ancestorsSources from which the current page can be embedded (as child-srcopposed ). Acts on , , . This directive cannot be specified by `` and only takes effect for resources of non-HTML document type.
  • frame-srcThis directive was deprecated in level 2 but will be brought back in level 3. Falls back to tochild-srcthe directive .
  • img-srcSpecifies the image source.
  • media-srcLimit the source of audio and video resources.
  • object-srcSource of Flash and other plug-ins.
  • plugin-typesLimit the types of plugins that can be loaded on a page.
  • report-uriSpecify an address that can receive the CSP report, and the browser will send the report when the corresponding command fails. Cannot be specified via the `` tag.
  • style-srcLimit the source of style files.
  • upgrade-insecure-requestsInstruct the client to rewrite the page address, HTTP to HTTPS. It is used when there are a large number of old addresses in the site that need to be redirected.
  • worker-srcA directive in CSP Level 3 specifying an address that can be used in a worker, shared worker, or service worker.

child-srcframe-ancestorsLooks similar to . The former specifies which iframes can be loaded in the page, and the latter specifies who can load the page with iframe. For example, two webpages A and B from different sites, B, B has an iframe loaded A. So

  • A's frame-ancestors need to contain B
  • B's child-src needs to contain A

By default, these instructions are open with the maximum condition, which can be understood as their default value *. For example img-src, image resources can be loaded from anywhere if not specified explicitly.

There is also a special instruction default-src, if its value is specified, it is equivalent to changing the default value of these unspecified instructions. It can be understood that img-srcif it , the default value is *that images from all sources can be loaded, but default-srcafter , the default value becomes default-srcthe value specified by .

A common practice is to set it default-src ‘self’so that all resources are restricted to the same domain as the page. If you want to load pictures from CDN at this time, just add the picture source separately.

Content-Security-Policy: default-src ‘self’; img-src https://cdn.example.com 

Now look at the example at the beginning, maybe now you can see it. Because the page needs to load the React library from the CDN, we specify the following CSP rules in the `` tag:

script-src 'self' https://unpkg.com 

Here selfand later changed noneto is the default value, which needs to be wrapped in quotation marks, otherwise it will be parsed as a URI. The CSP rule here indicates that scripts on the page can only https://unpkg.combe loaded . If we remove the latter, the React library will fail to load as shown in the screenshot above, and at the same time, there will be a log of the loading failure and the triggered rules listed in the console.

noneAfter changing to means that the page does not load any scripts, even the scripts on your own site cannot be loaded and executed. Let's try to create a script file csp_test.htmlnext test.js:

test.js

alert(‘来自 test.js 的问候!’) 

Also refer to it in the page:

csp_test.html

<!DOCTYPE html>
<html lang="en">
<head><meta http-equiv="Content-Security-Policy" content="script-src 'none'"><title>CSP Test</title>
</head>
<body><script src="https://unpkg.com/react@16/umd/react.development.js"></script>
+<script src="./test.js"></script>
</body>
</html> 

Page execution result:

img

Yes, even your own scripts cannot be loaded and executed. CSP is just that strict and clear, there is no ambiguity. So when specifying the source, we need to make sure that the URI is correct.

Acceptable values ​​for the command

There are two ways to write the source following the command

  • default value
  • URI wildcards

default value

The default values ​​are as follows:

  • none matches nothing.
  • self matches the current domain, but not subdomains. For example, example.com is OK, but api.example.com will fail to match.
  • unsafe-inline allows inline scripts and styles. Yes, you read that right, there are corresponding restrictions on the content embedded in the page.
  • unsafe-eval allows dynamically created script execution via strings, such as eval, setTimeout, etc.

In particular, under the strict control of the CSP, inline scripts and styles in the page are also affected, which cannot be executed by the browser unless explicitly specified.

Consider the following code:

csp_test.html

<!DOCTYPE html>
<html lang="en">
<head><title>CSP Test</title><style> body{
      
      color:red;} </style>
</head>
<body><h1>Hello, World!</h1><script> window.onload=function(){
      
      alert('hi jack!')} </script>
</body>
</html> 

img

According to the description on MDN, if the site does not specify a CSP, the browser will not enable the corresponding check by default, so everything above works normally, only limited by the normal same domain.

If the site doesn't offer the CSP header, browsers likewise use the standard same-origin policy.> — From MDN's description of Content Security Policy (CSP)

We add the CSP limit:

csp_test.html

<!DOCTYPE html>
<html lang="en">
<head>
+<meta http-equiv="Content-Security-Policy" content="default-src 'self'"><title>CSP Test</title><style> body{
      
      color:red;} </style>
</head>
<body><h1>Hello, World!</h1><script> window.onload=function(){
      
      alert('hi jack!')} </script>
</body>
</html> 

By default, the configuration site only information resources of the same domain, but note that this setting does not include inline, so the result will be as shown below.

img

How to fix it. If we want to allow inline scripts or styles within the page, we need to explicitly point this out via script-src and style-src.

csp_test.html

<!DOCTYPE html>
<html lang="en">
<head>
<img src="http-equiv="Content-Security-Policy" content="default-src 'self' ‘unsave-inline’"><title>CSP Test</title><style> body{color:red;} </style" style="margin: auto" />
</head>
<body><h1>Hello, World!</h1><script> window.onload=function(){
      
      alert('hi jack!')} </script>
</body>
</html> 

default-src 'self' ‘unsave-inline’The default trusted sources configured here are: those in the same domain as the page, and inline.

Refresh the page, styles and scripts can be executed normally again.

It is generally unsafe-inlinediscouraged unsafe-eval) because inline scripts and styles are inconvenient to maintain and don't take advantage of well-organized code. The best practice is to extract styles to style files, load scripts into separate js files, and keep HTML files pure. onclick=“myHandler”Even href=“javascript:;”the common writing method of or is an inline script and needs to be modified.

If you have to use inline writing on the page, there is another way. That is, these inline scripts or style tags in the page are assigned an encrypted string, which is generated by the server, and this encrypted string is added to the response header of the page.

<script nonce=EDNnf03nceIOfn39fn3e9h3sdfa> // 这里放置内联在 HTML 中的代码 </script> 

Content-Security-PolicyThe configuration of the page HTTP response header contains the same encrypted string:

Content-Security-Policy: script-src 'nonce-EDNnf03nceIOfn39fn3e9h3sdfa' 

Note nonce-the prefix .

This is the way I saw at the beginning of the article, and I understand it here.

<style>Labels are handled similarly.

The encrypted string here must be random and unpredictable, otherwise the security effect will not be achieved, and it will be regenerated every time the page is accessed.

In addition to nocespecifying the encrypted string, the obfuscated hash value can also be used to achieve the purpose. This method does not need to add on the label nonce, but the code that needs to be embedded uses an encryption algorithm to generate a hash and put it into the CSP instruction as a value. The encryption algorithm here supports sha256, sha384 and sha512. At this time, the prefix used in CSP is the corresponding algorithm name.

Example of hash method:

<script>alert('Hello, world.');</script> 
Content-Security-Policy: script-src 'sha256-qznLcsROx4GACP2dm0UCKCzCG-HiZ1guq6ZZDob_Tng=' 

eval

In many places in js, code can be dynamically created and executed in the form of strings, which is considered unsafe, so it is not recommended, and it is mentioned in general best practices.

  • setTimeout/setInterval can receive a string as code execution. setTimout('alert(1)',1000).
  • eval 。eval(‘alert(1)’)。
  • Function constructor. new Function('alert(1)').

As with inlining, there are special directives unsafe-evalto allow similar code execution. However, it is recommended that evalthe and Functionconstructors should not be used, and setTimeout/setIntervalcan be transformed into a non-string form.

setTimout(function(){alert(1);
}, 1000) 

URI

In addition to the default values ​​above, you can also provide a full URI or an address *with to match to specify the legal source of the resource. The URI rule here is the same as the cross-origin response header of the configuration server, refer to Same-origin policy .

  • *://*.example.com:*would match all subdomains example.comof , but not including example.com.
  • http://example.comand http://www.example.comare two different URIs.
  • http://example.com:80and are http://example.comalso two different URIs, although the default port of the website is 80

According to the explanation given on the Uniform Resource Identifier page of Wikipedia , a complete URI consists of the following parts: >URI = scheme:[//authority]path[?query][#fragment]

which authorityalso includes:>authority = [userinfo@]host[:port]

So you can think that one of them is different, that is two URIs. It is important to understand that, as with the first example listed above *.example.com, it is easy to preconceive that since all subdomains of the domain name are allowed, they must example.comalso be legal.

Because URIs are matched dynamically, that explains why the default values ​​mentioned above are enclosed in quotes. Because if you don't add quotation marks, selfit will indicate hostthat it is selfthe resource address of , but not the original meaning.

The configuration of priority CSP is very flexible. Each command can specify multiple sources, separated by spaces. A CSP rule can consist of multiple instructions, separated by semicolons. There is no order requirement among the instructions, because each instruction performs its own function. Even in a response, Content-Security-Policythe response header can be set repeatedly.

Let's look at the performance of CSP in these scenarios.

  • For cases where multiple response headers are set, the strictest rule takes effect. For example, in the following two response headers, although connect-srcallowed http://example.com/, is is connect-srcset none, so the stricter nonewill take effect. See Multiple content security policies .
Content-Security-Policy: default-src 'self' http://example.com; connect-src 'none';
Content-Security-Policy: connect-src http://example.com/; script-src http://example.com/ 
  • If the same instruction is specified multiple times, the first one shall prevail, and subsequent ones will be ignored.

csp_test.html

<!DOCTYPE html>
<html lang="en">
<head><meta http-equiv="Content-Security-Policy" content="default-src 'self';default-src 'unsafe-inline';"><title>CSP Test</title><style> body{
      
      color:red;} </style>
</head>
<body><h1>Hello, World!</h1><script> window.onload=function(){
      
      alert('hi jack!')} </script>
</body>
</html> 

img

Smartly, the browser will not only print out resources and instructions that cannot be detected, but also prompt instructions that are ignored during repeated configurations.

  • default-srcWhen specified , it acts Fetchas the default for class directives. That is, default-srcit does not take effect for all commands, and the default value of other commands is still *.

send report

When an illegal resource is detected, in addition to the error message seen in the console, the browser can also send the log to the server for subsequent analysis. The address to receive the report Content-Security-Policycan report-uribe configured by the directive in the response header. Of course, the server needs to write a corresponding service to receive the data.

Content-Security-Policy: default-src 'self'; ...; report-uri /my_amazing_csp_report_parser; 

The server gets the data sent in the form of JSON.

{"csp-report": {"document-uri": "http://example.org/page.html","referrer": 
"http://evil.example.com/","blocked-uri": "http://evil.example.com/evil.js","violated-
directive": "script-src 'self' https://apis.google.com","original-policy": "script-src 
'self' https://apis.google.com; report-uri http://example.org/my_amazing_csp_report_parser"}
} 

report mode

CSP provides a reporting mode. In this mode, resources are not really limited to load, but only detected problems are reported and JSONsent to report-urithe specified place in the form of data.

By specifying Content-Security-Policy-Report-Onlyinstead of Content-Security-Policy, reporting mode is turned on.

Content-Security-Policy-Report-Only: default-src 'self'; ...; report-uri /my_amazing_csp_report_parser; 

Of course, you can also specify two response headers at the same time, and the rules in each will be executed normally without affecting each other. for example:

Content-Security-Policy: img-src *;
Content-Security-Policy-Report-Only: img-src ‘none’; report-uri http://reportcollector.example.com/collector.cgi 

Here the image will still load normally, but img-src ‘none’will also detect and send a report.

Report mode is very useful for testing. Before enabling CSP, it is necessary to conduct a comprehensive test on the entire site, and repair the problems found in time before actually enabling it, such as the transformation of the inline code mentioned above.

recommended practice

Such security measures should of course be enabled as soon as possible. The following are recommended practices:

  • Only open the report mode first, see the scope of influence, and modify the problem.
  • When adding instructions, default-src ‘none’start , check the error report, and gradually add rules until the requirements are met.
  • Observe for a period of time after going online, and then switch from reporting mode to enforcement after stabilization.

browser compatibility

Most of the currently released Level 3 specifications have not yet been implemented by browsers. According to the data from Can I Use , except for IE, the functions of Level 2 have been well supported. Here's another statistic for each browser implementation tracked by the W3C: Implementation Report for Content Security Policy Level 2 .

Don't worry if the browser doesn't support it, it will fall back to the restrictions of the same-origin policy.

reference

Original: www.cnblogs.com/Wayou/p/int… >

Guess you like

Origin blog.csdn.net/qq_43842093/article/details/131024159