Using Your Headers for Better Security

Drupalcon Vienna 2017

Presented By
Geoff Appleby
https://gapple.github.io/presentation-using-your-headers/

X-Content-Type-Options

X-Content-Type-Options

							public function onRespond(FilterResponseEvent $event) {

								$response = $event->getResponse();

								// ...

								// Prevent browsers from sniffing a response and picking a MIME type
								// different from the declared content-type, since that can lead to
								// XSS and other vulnerabilities.
								// https://www.owasp.org/index.php/List_of_useful_HTTP_headers
								$response->headers->set('X-Content-Type-Options', 'nosniff', FALSE);

								// ...
							}
						
Drupal\Core\EventSubscriber\FinishResponseSubscriber::onRespond()
X-Content-Type-Options

							# Various header fixes.
							<IfModule mod_headers.c>
								# Disable content sniffing, since it's an attack vector.
								Header always set X-Content-Type-Options nosniff
								# Disable Proxy header, since it's an attack vector.
								RequestHeader unset Proxy
							</IfModule>
						
.htaccess
X-Content-Type-Options - Resources

X-Frame-Options

X-Frame-Options
  • DENY
  • SAMEORIGIN
  • ALLOW-FROM https://example.com/
X-Frame-Options

							public function onRespond(FilterResponseEvent $event) {

								$response = $event->getResponse();

								// ...

								$response->headers->set('X-Frame-Options', 'SAMEORIGIN', FALSE);

								// ...
							}
						
Drupal\Core\EventSubscriber\FinishResponseSubscriber::onRespond()
X-Frame-Options - Resources

X-XSS-Protection

X-XSS-Protection
  • 0
  • 1
  • 1; mode=block
  • 1; report=<reporting-uri>
X-XSS-Protection - Resources

Referrer Policy

Referrer Policy
  • no-referrer
  • no-referrer-when-downgrade
  • same-origin
  • origin
  • strict-origin
  • origin-when-cross-origin
  • strict-origin-when-cross-origin
  • unsafe-url
Referrer Policy

strict-origin-when-cross-origin

SourceDestinationReferrer
https://example.com/page-onehttps://example.com/page-twohttps://example.com/page-one
https://example.com/page-onehttps://google.com/https://example.com
https://example.com/page-onehttp://example.com/page-twoNULL
https://example.com/page-onehttp://google.com/NULL

Drupal Event Subscribers

Event Subscriber

							services:
								my_module.response_listener:
									class: Drupal\my_module\EventSubscriber\ResponseSubscriber
									arguments: ['@config.factory']
									tags:
										- { name: event_subscriber }
						
my_module.services.yml
Event Subscriber

							namespace Drupal\my_module\EventSubscriber;

							use Symfony\Component\EventDispatcher\EventSubscriberInterface;
							use Symfony\Component\HttpKernel\Event\FilterResponseEvent;

							class ResponseSubscriber implements EventSubscriberInterface {

								public static function getSubscribedEvents() {
									$events[KernelEvents::RESPONSE] = ['onKernelResponse'];
									return $events;
								}

								public function onKernelResponse(FilterResponseEvent $event) {
									if (!$event->isMasterRequest()) {
										return;
									}

									$response = $event->getResponse();

									$response->headers->set('HeaderName', 'header-value');
								}
							}
						
src/EventSubscriber/ResponseSubscriber.php

Strict Transport Security

Strict Transport Security

							SSLEngine On
							SSLCertificateFile    example.crt
							SSLCertificateKeyFile example.key

							# Set HSTS header for six months
							<IfModule mod_headers.c>
									Header always set Strict-Transport-Security "max-age=15552000"
							</IfModule>
						
vhosts.conf

Public Key Pinning

Public Key Pinning
Public Key Pinning

Content Security Policy

Content Security Policy
Content Security Policy
Content Security Policy
  • script-src
  • style-src
  • img-src
  • connect-src
  • frame-src
  • default-src
  • upgrade-insecure-requests
  • report-uri
Content Security Policy
  • 'none'
  • 'self'
  • *
  • 'unsafe-inline'
  • 'unsafe-eval'
  • example.com
  • *.example.com
  • https://example.com
  • https:
Content Security Policy

							Content-Security-Policy:
								default-src 'self';
								script-src 'self' 'unsafe-inline' code.jquery.com www.google.com www.google-analytics.com;
								style-src 'self' 'unsafe-inline' netdna.bootstrapcdn.com www.google.com ajax.googleapis.com;
								img-src 'self' s3.amazonaws.com www.google-analytics.com stats.g.doubleclick.net;
								connect-src 'self' www.drupal.org www.google-analytics.com;
								report-uri https://gapple.report-uri.io/r/default/csp/enforce;
						
Content Security Policy

							Content-Security-Policy:
								default-src *;
								script-src * 'unsafe-inline';
								style-src * 'unsafe-inline';
								report-uri https://gapple.report-uri.io/r/default/csp/enforce;

							Content-Security-Policy-Report-Only:
								default-src 'self';
								report-uri https://gapple.report-uri.io/r/default/csp/reportOnly;
						
Content Security Policy

								Content-Security-Policy:
									default-src 'self';
									script-src assets.example.com;
									style-src assets.example.com;
									img-src assets.example.com files.example.com;
									connect-src 'self';
							

csp.module

csp.module

								testlib:
									version: "1.x"
									css:
										theme:
											https://example.com/css/testlib.css: {}
									js:
										http://example.com/js/testlib.js: {}
							
mymodule.libraries.yml
csp.module

							<!-- Google Analytics -->
							<script>
								(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
									(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
										m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
								})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
			
								ga('create', 'UA-XXXXX-Y', 'auto');
								ga('send', 'pageview');
							</script>
							<!-- End Google Analytics -->
							
csp.module

							<!-- Google Analytics -->
							<script>
								window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
								ga('create', 'UA-XXXXX-Y', 'auto');
								ga('send', 'pageview');
							</script>
							<script async src='https://www.google-analytics.com/analytics.js'></script>
							<!-- End Google Analytics -->
						
csp.module

// TODO

  • Report Logging
  • Dynamic Policy Directives
  • Manual Configuration

Contribution Sprints

Friday, 29 September, 2017

Mentored Core Sprint 9:00-18:00 Room: Stolz 2
First time Sprinter Workshop 9:00-12:00 Room: Lehar 1 - Lehar 2
General Sprint 9:00-18:00 Room: Mall
#drupalsprints

What did you think?