xref: /aosp_15_r20/external/libwebsockets/READMEs/README.content-security-policy.md (revision 1c60b9aca93fdbc9b5f19b2d2194c91294b22281)
1*1c60b9acSAndroid Build Coastguard Worker## Using Content Security Policy (CSP)
2*1c60b9acSAndroid Build Coastguard Worker
3*1c60b9acSAndroid Build Coastguard Worker### What is it?
4*1c60b9acSAndroid Build Coastguard Worker
5*1c60b9acSAndroid Build Coastguard WorkerModern browsers have recently implemented a new feature providing
6*1c60b9acSAndroid Build Coastguard Workera sort of "selinux for your web page".  If the server sends some
7*1c60b9acSAndroid Build Coastguard Workernew headers describing the security policy for the content, then
8*1c60b9acSAndroid Build Coastguard Workerthe browser strictly enforces it.
9*1c60b9acSAndroid Build Coastguard Worker
10*1c60b9acSAndroid Build Coastguard Worker### Why would we want to do that?
11*1c60b9acSAndroid Build Coastguard Worker
12*1c60b9acSAndroid Build Coastguard WorkerScripting on webpages is pretty universal, sometimes the scripts
13*1c60b9acSAndroid Build Coastguard Workercome from third parties, and sometimes attackers find a way to
14*1c60b9acSAndroid Build Coastguard Workerinject scripts into the DOM, eg, through scripts in content.
15*1c60b9acSAndroid Build Coastguard Worker
16*1c60b9acSAndroid Build Coastguard WorkerCSP lets the origin server define what is legitimate for the page it
17*1c60b9acSAndroid Build Coastguard Workerserved and everything else is denied.
18*1c60b9acSAndroid Build Coastguard Worker
19*1c60b9acSAndroid Build Coastguard WorkerThe CSP for warmcat.com and libwebsockets.org looks like this,
20*1c60b9acSAndroid Build Coastguard WorkerI removed a handful of approved image sources like travis
21*1c60b9acSAndroid Build Coastguard Workerstatus etc for clarity...
22*1c60b9acSAndroid Build Coastguard Worker
23*1c60b9acSAndroid Build Coastguard Worker```
24*1c60b9acSAndroid Build Coastguard Worker"content-security-policy": "default-src 'none'; img-src 'self' data:; script-src 'self'; font-src 'self'; style-src 'self'; connect-src 'self'; frame-ancestors 'none'; base-uri 'none';",
25*1c60b9acSAndroid Build Coastguard Worker"x-content-type-options": "nosniff",
26*1c60b9acSAndroid Build Coastguard Worker"x-xss-protection": "1; mode=block",
27*1c60b9acSAndroid Build Coastguard Worker"x-frame-options": "deny",
28*1c60b9acSAndroid Build Coastguard Worker"referrer-policy": "no-referrer"
29*1c60b9acSAndroid Build Coastguard Worker```
30*1c60b9acSAndroid Build Coastguard Worker
31*1c60b9acSAndroid Build Coastguard WorkerThe result of this is the browser won't let the site content be iframed, and it
32*1c60b9acSAndroid Build Coastguard Workerwill reject any inline styles or inline scripts.  Fonts, css, ajax, ws and
33*1c60b9acSAndroid Build Coastguard Workerimages are only allowed to come from 'self', ie, the server that served the
34*1c60b9acSAndroid Build Coastguard Workerpage.  You may inject your script, or deceptive styles: it won't run or be shown.
35*1c60b9acSAndroid Build Coastguard Worker
36*1c60b9acSAndroid Build Coastguard WorkerBecause inline scripts are banned, the usual methods for XSS are dead;
37*1c60b9acSAndroid Build Coastguard Workerthe attacker can't even load js from another server.  So these rules
38*1c60b9acSAndroid Build Coastguard Workerprovide a very significant increase in client security.
39*1c60b9acSAndroid Build Coastguard Worker
40*1c60b9acSAndroid Build Coastguard Worker### Implications of strict CSP
41*1c60b9acSAndroid Build Coastguard Worker
42*1c60b9acSAndroid Build Coastguard WorkerHalfhearted CSP isn't worth much.  The only useful approach is to start
43*1c60b9acSAndroid Build Coastguard Workerwith `default-src 'none'` which disables everything, and then allow the
44*1c60b9acSAndroid Build Coastguard Workerminimum needed for the pages to operate.
45*1c60b9acSAndroid Build Coastguard Worker
46*1c60b9acSAndroid Build Coastguard Worker"Minimum needed for the pages to operate" doesn't mean defeat the protections
47*1c60b9acSAndroid Build Coastguard Workernecessary so everything in the HTML can stay the same... it means adapt the
48*1c60b9acSAndroid Build Coastguard Workerpages to want the minimum and then enable the minimum.
49*1c60b9acSAndroid Build Coastguard Worker
50*1c60b9acSAndroid Build Coastguard WorkerThe main point is segregation of styles and script away from the content, in
51*1c60b9acSAndroid Build Coastguard Workerfiles referenced in the document `<head>` section, along these lines:
52*1c60b9acSAndroid Build Coastguard Worker
53*1c60b9acSAndroid Build Coastguard Worker```
54*1c60b9acSAndroid Build Coastguard Worker<head>
55*1c60b9acSAndroid Build Coastguard Worker <meta charset=utf-8 http-equiv="Content-Language" content="en"/>
56*1c60b9acSAndroid Build Coastguard Worker <link rel="stylesheet" type="text/css" href="test.css"/>
57*1c60b9acSAndroid Build Coastguard Worker <script type='text/javascript' src="/lws-common.js"></script>
58*1c60b9acSAndroid Build Coastguard Worker <script type='text/javascript' src='test.js'></script>
59*1c60b9acSAndroid Build Coastguard Worker <title>Minimal Websocket test app</title>
60*1c60b9acSAndroid Build Coastguard Worker</head>
61*1c60b9acSAndroid Build Coastguard Worker```
62*1c60b9acSAndroid Build Coastguard Worker
63*1c60b9acSAndroid Build Coastguard Worker#### Inline styles must die
64*1c60b9acSAndroid Build Coastguard Worker
65*1c60b9acSAndroid Build Coastguard WorkerAll styling must go in one or more `.css` file(s) best served by the same
66*1c60b9acSAndroid Build Coastguard Workerserver... while you can approve other sources in the CSP if you have to,
67*1c60b9acSAndroid Build Coastguard Workerunless you control that server as well, you are allowing whoever gains
68*1c60b9acSAndroid Build Coastguard Workeraccess to that server access to your users.
69*1c60b9acSAndroid Build Coastguard Worker
70*1c60b9acSAndroid Build Coastguard WorkerInline styles are no longer allowed (eg, "style='font-size:120%'" in the
71*1c60b9acSAndroid Build Coastguard WorkerHTML)... they must be replaced by reference to one or more CSS class, which
72*1c60b9acSAndroid Build Coastguard Workerin this case includes "font-size:120%".  This has always been the best
73*1c60b9acSAndroid Build Coastguard Workerpractice anyway, and your pages will be cleaner and more maintainable.
74*1c60b9acSAndroid Build Coastguard Worker
75*1c60b9acSAndroid Build Coastguard Worker#### Inline scripts must die
76*1c60b9acSAndroid Build Coastguard Worker
77*1c60b9acSAndroid Build Coastguard WorkerInline scripts need to be placed in a `.js` file and loaded in the page head
78*1c60b9acSAndroid Build Coastguard Workersection, again it should only be from the server that provided the page.
79*1c60b9acSAndroid Build Coastguard Worker
80*1c60b9acSAndroid Build Coastguard WorkerThen, any kind of inline script, yours or injected or whatever, will be
81*1c60b9acSAndroid Build Coastguard Workercompletely rejected by the browser.
82*1c60b9acSAndroid Build Coastguard Worker
83*1c60b9acSAndroid Build Coastguard Worker#### onXXX must be replaced by eventListener
84*1c60b9acSAndroid Build Coastguard Worker
85*1c60b9acSAndroid Build Coastguard WorkerInline `onclick()` etc are kinds of inline scripting and are banned.
86*1c60b9acSAndroid Build Coastguard Worker
87*1c60b9acSAndroid Build Coastguard WorkerModern browsers have offered a different system called ["EventListener" for
88*1c60b9acSAndroid Build Coastguard Workera while](https://developer.mozilla.org/en-US/docs/Web/API/EventListener)
89*1c60b9acSAndroid Build Coastguard Workerwhich allows binding of events to DOM elements in JS.
90*1c60b9acSAndroid Build Coastguard Worker
91*1c60b9acSAndroid Build Coastguard WorkerA bunch of different named events are possible to listen on, commonly the
92*1c60b9acSAndroid Build Coastguard Worker`.js` file will ask for one or both of
93*1c60b9acSAndroid Build Coastguard Worker
94*1c60b9acSAndroid Build Coastguard Worker```
95*1c60b9acSAndroid Build Coastguard Workerwindow.addEventListener("load", function() {
96*1c60b9acSAndroid Build Coastguard Worker...
97*1c60b9acSAndroid Build Coastguard Worker}, false);
98*1c60b9acSAndroid Build Coastguard Worker
99*1c60b9acSAndroid Build Coastguard Workerdocument.addEventListener("DOMContentLoaded", function() {
100*1c60b9acSAndroid Build Coastguard Worker...
101*1c60b9acSAndroid Build Coastguard Worker}, false);
102*1c60b9acSAndroid Build Coastguard Worker```
103*1c60b9acSAndroid Build Coastguard Worker
104*1c60b9acSAndroid Build Coastguard WorkerThese give the JS a way to trigger when either everything on the page has
105*1c60b9acSAndroid Build Coastguard Workerbeen "loaded" or the DOM has been populated from the initial HTML.  These
106*1c60b9acSAndroid Build Coastguard Workercan set up other event listeners on the DOM objects and aftwards the
107*1c60b9acSAndroid Build Coastguard Workerevents will drive what happens on the page from user interaction and / or
108*1c60b9acSAndroid Build Coastguard Workertimers etc.
109*1c60b9acSAndroid Build Coastguard Worker
110*1c60b9acSAndroid Build Coastguard WorkerIf you have `onclick` in your HTML today, you would replace it with an id
111*1c60b9acSAndroid Build Coastguard Workerfor the HTML element, then eg in the DOMContentLoaded event listener,
112*1c60b9acSAndroid Build Coastguard Workerapply
113*1c60b9acSAndroid Build Coastguard Worker
114*1c60b9acSAndroid Build Coastguard Worker```
115*1c60b9acSAndroid Build Coastguard Worker   document.getElementById("my-id").addEventListener("click", function() {
116*1c60b9acSAndroid Build Coastguard Worker   ...
117*1c60b9acSAndroid Build Coastguard Worker   }, false);
118*1c60b9acSAndroid Build Coastguard Worker```
119*1c60b9acSAndroid Build Coastguard Worker
120*1c60b9acSAndroid Build Coastguard Workerie the .js file becomes the only place with the "business logic" of the
121*1c60b9acSAndroid Build Coastguard Workerelements mentioned in the HTML, applied at runtime.
122*1c60b9acSAndroid Build Coastguard Worker
123*1c60b9acSAndroid Build Coastguard Worker#### Do you really need external sources?
124*1c60b9acSAndroid Build Coastguard Worker
125*1c60b9acSAndroid Build Coastguard WorkerDo your scripts and fonts really need to come from external sources?
126*1c60b9acSAndroid Build Coastguard WorkerIf your caching policy is liberal, they are not actually that expensive
127*1c60b9acSAndroid Build Coastguard Workerto serve once and then the user is using his local copy for the next
128*1c60b9acSAndroid Build Coastguard Workerdays.
129*1c60b9acSAndroid Build Coastguard Worker
130*1c60b9acSAndroid Build Coastguard WorkerSome external sources are marked as anti-privacy in modern browsers, meaning
131*1c60b9acSAndroid Build Coastguard Workerthey track your users, in turn meaning if your site refers to them, you
132*1c60b9acSAndroid Build Coastguard Workerwill lose your green padlock in the browser.  If the content license allows
133*1c60b9acSAndroid Build Coastguard Workerit, hosting them on "self", ie, the same server that provided the HTML,
134*1c60b9acSAndroid Build Coastguard Workerwill remove that problem.
135*1c60b9acSAndroid Build Coastguard Worker
136*1c60b9acSAndroid Build Coastguard WorkerBringing in scripts from external sources is actually quite scary from the
137*1c60b9acSAndroid Build Coastguard Workersecurity perspective.  If someone hacks the `ajax.googleapis.com` site to serve
138*1c60b9acSAndroid Build Coastguard Workera hostile, modified jquery, half the Internet will instantly
139*1c60b9acSAndroid Build Coastguard Workerbecome malicious.  However if you serve it yourself, unless your server
140*1c60b9acSAndroid Build Coastguard Workerwas specifically targeted you know it will continue to serve what you
141*1c60b9acSAndroid Build Coastguard Workerexpect.
142*1c60b9acSAndroid Build Coastguard Worker
143*1c60b9acSAndroid Build Coastguard WorkerSince these scripts are usually sent with cache control headers for local
144*1c60b9acSAndroid Build Coastguard Workercaching duration of 1 year, the cost of serving them yourself under the same
145*1c60b9acSAndroid Build Coastguard Workerconditions is small but your susceptibility to attack is reduced to only taking
146*1c60b9acSAndroid Build Coastguard Workercare of your own server.  And there is a privacy benefit that google is not
147*1c60b9acSAndroid Build Coastguard Workerinformed of your users' IPs and activities on your site.
148*1c60b9acSAndroid Build Coastguard Worker
149