-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ensure CSP is effective against XSS attacks #19
Comments
Based on https://content-security-policy.com/nonce/
...here's an implementation: diff --git a/src/main/handlebars/content.handlebars b/src/main/handlebars/content.handlebars
index 5bb7479..c4380d0 100755
--- a/src/main/handlebars/content.handlebars
+++ b/src/main/handlebars/content.handlebars
@@ -37,7 +37,7 @@ parent: feed
</section>
{{/inline}}
{{#*inline "scripts"}}
- <script type="module">
+ <script type="module" nonce="{{request.values.nonce}}">
const markers = {
style : new ol.style.Style({image: new ol.style.Icon(({src: '/static/marker.png'}))}),
list : [],
diff --git a/src/main/handlebars/home.handlebars b/src/main/handlebars/home.handlebars
index 3b5d559..bdc0d58 100755
--- a/src/main/handlebars/home.handlebars
+++ b/src/main/handlebars/home.handlebars
@@ -15,7 +15,7 @@
<!-- About me -->
{{#with cover}}
- <div class="cover" style="background-image: url(/image/{{slug}}/full-{{#with images.0}}{{.}}{{/with}}.webp)">
+ <div class="cover">
<h1>{{title}}</h1>
</div>
<article class="intro">
@@ -55,7 +55,7 @@
» <a href="/feed">Alle Inhalte im Feed</a>
{{/inline}}
{{#*inline "scripts"}}
- <script type="module">
+ <script type="module" nonce="{{request.values.nonce}}">
{{&use 'suggestions'}}
suggestions(document.querySelector('#search'), 'Volltextsuche nach "%s"');
</script>
diff --git a/src/main/handlebars/journey.handlebars b/src/main/handlebars/journey.handlebars
index 434d93b..d21b12c 100755
--- a/src/main/handlebars/journey.handlebars
+++ b/src/main/handlebars/journey.handlebars
@@ -77,7 +77,7 @@ parent: feed
{{/with}}
{{/inline}}
{{#*inline "scripts"}}
- <script type="module">
+ <script type="module" nonce="{{request.values.nonce}}">
{{&use 'mapping'}}
{{#each itinerary}}
diff --git a/src/main/handlebars/journeys.handlebars b/src/main/handlebars/journeys.handlebars
index c2bbae3..2693942 100755
--- a/src/main/handlebars/journeys.handlebars
+++ b/src/main/handlebars/journeys.handlebars
@@ -28,7 +28,7 @@
</div>
{{/inline}}
{{#*inline "scripts"}}
- <script type="module">
+ <script type="module" nonce="{{request.values.nonce}}">
{{&use 'mapping'}}
{{#each journeys}}
diff --git a/src/main/handlebars/layout.handlebars b/src/main/handlebars/layout.handlebars
index 5d496e6..beedd98 100755
--- a/src/main/handlebars/layout.handlebars
+++ b/src/main/handlebars/layout.handlebars
@@ -2,13 +2,14 @@
<html lang="de" prefix="og: http://ogp.me/ns#">
<head>
<meta charset="utf-8">
+ <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'nonce-{{request.values.nonce}}'; style-src 'self' 'nonce-{{request.values.nonce}}'; img-src 'self' https://tile.openstreetmap.org">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="Fotoblog von Timm Friebe">
<meta name="twitter:card" content="summary">
<meta name="twitter:site" content="@timmfriebe">
{{> meta}}
<link rel="stylesheet" type="text/css" href="/assets/{{asset 'vendor.css'}}">
- <style type="text/css">
+ <style type="text/css" nonce="{{request.values.nonce}}">
/* CSS reset, see https://piccalil.li/blog/a-modern-css-reset/ */
*, *::before, *::after {
box-sizing: border-box;
@@ -109,6 +110,7 @@
.cover {
margin: -1rem -1rem 1rem -1rem;
+ background-image: url(/image/{{cover.slug}}/full-{{cover.images.0.name}}.webp);
background-size: cover;
background-position: center;
height: 50vh;
diff --git a/src/main/handlebars/search.handlebars b/src/main/handlebars/search.handlebars
index 17f7ca1..deec835 100755
--- a/src/main/handlebars/search.handlebars
+++ b/src/main/handlebars/search.handlebars
@@ -54,7 +54,7 @@ parent: feed
</div>
{{/inline}}
{{#*inline "scripts"}}
- <script type="module">
+ <script type="module" nonce="{{request.values.nonce}}">
{{&use 'suggestions'}}
suggestions(document.querySelector('#search'), 'Volltextsuche nach "%s"');
</script>
diff --git a/src/main/php/de/thekid/dialog/App.php b/src/main/php/de/thekid/dialog/App.php
index 8afcb3f..1541a70 100755
--- a/src/main/php/de/thekid/dialog/App.php
+++ b/src/main/php/de/thekid/dialog/App.php
@@ -28,6 +28,9 @@ class App extends Application {
$this->install(new BehindProxy([$service => '/']));
}
+ // Generate nonces for every request
+ $this->install(new Nonce());
+
// Cache static content for one week, immutable fingerprinted assets for one year
$manifest= new AssetsManifest($this->environment->path('src/main/webapp/assets/manifest.json'));
$static= ['Cache-Control' => 'max-age=604800']; The Nonce filter is implemented as follows: <?php namespace de\thekid\dialog;
use util\Random;
use web\Filter;
/**
* Generates nonce for every request to be used in CSP
*
* @see https://content-security-policy.com/nonce/
*/
class Nonce implements Filter {
private $random= new Random();
/**
* Filtering implementation
*
* @param web.Request $req
* @param web.Response $res
* @param web.filters.Invocation $invocation
* @return var
*/
public function filter($req, $res, $invocation) {
return $invocation->proceed($req->pass('nonce', bin2hex($this->random->bytes(16))), $res);
}
} |
We should start with |
Cool GOTO conference talk at https://www.youtube.com/watch?v=mr230uotw-Y |
Adds default security headers, see issue #19 and xp-forge/frontend#31
Small improvement released in https://github.com/thekid/dialog/releases/tag/v1.6.1, now sets |
Lighthouse says:
The text was updated successfully, but these errors were encountered: