Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
HTTP headers for the responsible developer
Search
stefan judis
March 16, 2019
Technology
5.1k
5
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
HTTP headers for the responsible developer
stefan judis
March 16, 2019
More Decks by stefan judis
See All by stefan judis
Back to boring (part 2)
stefanjudis
0
360
Playwright can do this?
stefanjudis
0
240
Things you should know about Frontend Development in 2022
stefanjudis
0
550
Throw yourself out there for fun and profit
stefanjudis
0
140
Back to Boring
stefanjudis
1
530
Wanna scale up? Make sure your CMS is ready for it!
stefanjudis
0
280
Did we(b development) lose the right direction?
stefanjudis
6
2.2k
Regular expressions – my secret love
stefanjudis
1
1.1k
Write a Function
stefanjudis
0
620
Other Decks in Technology
See All in Technology
2026年6月23日 Syncable Tech + Start Python Club にて
hamukazu
0
150
起点・思考・出力で分解する 〜PM業務の自動化設計〜
kazu_kichi_67
1
910
Oracle AI Database@AWS:サービス概要のご紹介
oracle4engineer
PRO
4
3k
千葉での単身赴任からAWSをやり続け、千葉に戻ってきた話
yama3133
1
110
iOS アプリの「これって不具合ですか?」を AI に調べてもらう
miichan
0
140
【2026年版】 ベクトル検索とEmbedding最前線
mocobeta
23
7.3k
攻撃者視点で考えるDetection Engineering
cryptopeg
3
2.1k
事業会社における 機械学習・推薦システム技術の活用事例と必要な能力 / ml-recsys-in-layerx-wantedly-2026
yuya4
0
160
AIチャット検索改善の3週間
kworkdev
PRO
2
160
AWS Security Hub CSPMの成功・失敗体験
cmusudakeisuke
0
510
【セミナー資料】Claude Code をセキュアに使うための考え方と設定の勘どころ / Claude Code Webinar 20260616
masahirokawahara
2
460
作る力から、見極める力へ — AI時代に広がるエンジニアの価値と役割
rince
0
310
Featured
See All Featured
Marketing to machines
jonoalderson
1
5.5k
Money Talks: Using Revenue to Get Sh*t Done
nikkihalliwell
0
260
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
12
1.2k
Building Experiences: Design Systems, User Experience, and Full Site Editing
marktimemedia
0
540
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
11
950
Testing 201, or: Great Expectations
jmmastey
46
8.2k
Speed Design
sergeychernyshev
33
1.9k
The B2B funnel & how to create a winning content strategy
katarinadahlin
PRO
1
400
Git: the NoSQL Database
bkeepers
PRO
432
67k
The Curious Case for Waylosing
cassininazir
1
400
Optimising Largest Contentful Paint
csswizardry
37
3.7k
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.8k
Transcript
@stefanjudis HTTP headers for the responsible developer
My journey on the web
uboot.com
1999
The web connects people
2010
The web connects people
We connect people! We enable people! We help people!
[he/him] @stefanjudis www.stefanjudis.com Heyo, I'm Stefan!
... and I want to be a responsible developer
None
1999
2019
2019
2019
2019 We should be building for everybody
"We don't have users in/that ..."
"We don't have users in/that ..."
The challenge of building a "good" website
Design Performance Content Accessibility Devices Network Frameworks
Design Performance Content Accessibility Network Frameworks Devices
Let's talk HTTP
https://the-responsible.dev/ Accept: text/html,application/xhtml+xml,application/xml Accept-Encoding: gzip, deflate, br Accept-Language: en-GB,en-US;q=0.9,en;q=0.8,de;q=0.7 ...
Connection: keep-alive Content-Type: text/html; charset=utf-8 Date: Mon, 11 Mar 2019 12:59:38 GMT ... Response Body
Accept: text/html,application/xhtml+xml,application/xml Accept-Encoding: gzip, deflate, br Accept-Language: en-GB,en-US;q=0.9,en;q=0.8,de;q=0.7 ... https://the-responsible.dev/
Connection: keep-alive Content-Type: text/html; charset=utf-8 Date: Mon, 11 Mar 2019 12:59:38 GMT ... Response Body
the-responsible.dev
How can we use headers to make this site better?
The web is a scary place
thenextweb.com/contributors/2018/03/10/protect-website-cryptojacking-attacks/
shoptalkshow.com/episodes/special-one-one-hacker/
blog.npmjs.org/post/180565383195/details-about-the-event-stream-incident
www.twilio.com/blog/learned-about-security-from-calling-35-contact-centers
www.twilio.com/blog/learned-about-security-from-calling-35-contact-centers We always rely on others
The web has to be safe!
HTTPS
HTTP/2 ServiceWorker getUserMedia() ...
whynohttps.com
whynohttps.com
Ensure encryption
Strict-Transport-Security: max-age=1000; includeSubDomains; preload Response Header
hstspreload.org
chromium.googlesource.com/chromium/src/net/+/master/http/ transport_security_state_static.json
None
caniuse.com/#feat=stricttransportsecurity
Upgrade HTTP requests
Content-Security-Policy: upgrade-insecure-requests Response Header
www.chromestatus.com/feature/5557268741357568
Limit what's allowed
requestmap.webperf.tools
base-uri block-all-mixed-content connect-src default-src font-src form-action frame-ancestors frame-src img-src manifest-src
media-src navigate-to object-src plugin-types report-sample report-to require-sri-for sandbox script-src strict-dynamic style-src upgrade-insecure-requests worker-src developer.mozilla.org/en-US/docs/Web/HTTP/CSP prefetch-src
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*;">
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe- inline' 'unsafe-eval' just-comments.com www.google-analytics.com
production-assets.codepen.io storage.googleapis.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: images.contentful.com images.ctfassets.net www.gravatar.com www.google-analytics.com just- comments.com; font-src 'self' data:; connect-src 'self' cdn.contentful.com images.contentful.com videos.contentful.com images.ctfassets.net videos.ctfassets.net service.just-comments.com www.google-analytics.com; media-src 'self' videos.contentful.com videos.ctfassets.net; object-src 'self'; frame-src codepen.io; frame- ancestors 'self'; worker-src 'self'; block-all-mixed-content; manifest-src 'self' 'self'; disown-opener; prefetch-src 'self'; report-uri https:// stefanjudis.report-uri.com/r/d/csp/reportOnly Response Header
Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' just-comments.com www.google- analytics.com
production-assets.codepen.io storage.googleapis.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: images.contentful.com images.ctfassets.net www.gravatar.com www.google-analytics.com just- comments.com; font-src 'self' data:; connect-src 'self' cdn.contentful.com images.contentful.com videos.contentful.com images.ctfassets.net videos.ctfassets.net service.just-comments.com www.google-analytics.com; media-src 'self' videos.contentful.com videos.ctfassets.net; object-src 'self'; frame-src codepen.io; frame- ancestors 'self'; worker-src 'self'; block-all-mixed-content; manifest-src 'self' 'self'; disown-opener; prefetch-src 'self'; report-uri https:// stefanjudis.report-uri.com/r/d/csp/reportOnly Response Header
Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' just-comments.com www.google- analytics.com
production-assets.codepen.io storage.googleapis.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: images.contentful.com images.ctfassets.net www.gravatar.com www.google-analytics.com just- comments.com; font-src 'self' data:; connect-src 'self' cdn.contentful.com images.contentful.com videos.contentful.com images.ctfassets.net videos.ctfassets.net service.just-comments.com www.google-analytics.com; media-src 'self' videos.contentful.com videos.ctfassets.net; object-src 'self'; frame-src codepen.io; frame- ancestors 'self'; worker-src 'self'; block-all-mixed-content; manifest-src 'self' 'self'; disown-opener; prefetch-src 'self'; report-uri https:// stefanjudis.report-uri.com/r/d/csp/reportOnly Response Header
Report-To: { "group": "csp-endpoint", "max_age": 10886400, "endpoints": [{ "url": "https://stefanjudis.com/.../csp-report"
}] }
Report-To: { "group": "csp-endpoint", "max_age": 10886400, "endpoints": [{ "url": "https://stefanjudis.com/.../csp-report"
}] }, { "group": "network-endpoint", "max_age": 10886400, "endpoints": [{ "url": "https://stefanjudis.com/.../network-report" }] }, { "max_age": 10886400, "endpoints": [{ "url": "https://stefanjudis.com/.../general-report" }] }
developers.google.com/web/updates/2018/09/reportingapi
Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' just-comments.com www.google- analytics.com
production-assets.codepen.io storage.googleapis.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: images.contentful.com images.ctfassets.net www.gravatar.com www.google-analytics.com just- comments.com; font-src 'self' data:; connect-src 'self' cdn.contentful.com images.contentful.com videos.contentful.com images.ctfassets.net videos.ctfassets.net service.just-comments.com www.google-analytics.com; media-src 'self' videos.contentful.com videos.ctfassets.net; object-src 'self'; frame-src codepen.io; frame- ancestors 'self'; worker-src 'self'; block-all-mixed-content; manifest-src 'self' 'self'; disown-opener; prefetch-src 'self'; report-uri https:// stefanjudis.report-uri.com/r/d/csp/reportOnly Response Header
Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' just-comments.com www.google- analytics.com
production-assets.codepen.io storage.googleapis.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: images.contentful.com images.ctfassets.net www.gravatar.com www.google-analytics.com just- comments.com; font-src 'self' data:; connect-src 'self' cdn.contentful.com images.contentful.com videos.contentful.com images.ctfassets.net videos.ctfassets.net service.just-comments.com www.google-analytics.com; media-src 'self' videos.contentful.com videos.ctfassets.net; object-src 'self'; frame-src codepen.io; frame- ancestors 'self'; worker-src 'self'; block-all-mixed-content; manifest-src 'self' 'self'; disown-opener; prefetch-src 'self'; report-uri https:// stefanjudis.report-uri.com/r/d/csp/reportOnly Response Header
Content-Security-Policy: default-src 'self'; script-src 'sha256-blL...' <script> console.log('Inline script executing ...');
</script> Response Header
Content-Security-Policy: default-src 'self'; script-src 'nonce-abc...' <script nonce="abcdef"> console.log('Inline script executing
...'); </script> Response Header
caniuse.com/#feat=contentsecuritypolicy
caniuse.com/#feat=contentsecuritypolicy2 * * not complete
httparchive.org
How many pages use CSP?
USE CSP DON'T USE CSP 94% 6%
USE CSP DON'T USE CSP 94% 6% We can do
better!
Always monitor your CSP reports and "test in production" with
report-only before enforcing them! Troy Hunt
Disallow third-party cookies!
Set-Cookie: widget_session=abc123; Response Header Set-Cookie: ...
Set-Cookie: widget_session=abc123; Response Header Set-Cookie: ... This behaviour leads to
security and privacy issues
Set-Cookie: widget_session=abc123; SameSite=None; Secure Set-Cookie: widget_session=abc123; SameSite=Lax; Secure Set-Cookie: widget_session=abc123;
SameSite=Strict; Secure Response Header
caniuse.com/#feat=same-site-cookie-attribute * * somewhat ready but maybe buggy
web.dev/samesite-cookies-explained
the-responsible.dev/safe/
The web is crucial for people.
Your sh** doesn't work in Africa. William Imoh
None
You get 6MB for 2Euros but you have only 24h
to use them! Right...
whatdoesmysitecost.com
The web has to be affordable!
Don't request the same content over and over again
Cache-Control: max-age=31536000, public, immutable Response Header
immutable developer.mozilla.org/en-US/docs/Web/HTTP/ Headers/Cache-Control
csswizardry.com/2019/03/cache-control-for-civilians/
Send the right data
Accept-Encoding: gzip, deflate, br Request Header
None
None
But Brotli compression is so slow!
GZIP Brotli vs Default Mode 6 11
GZIP Brotli Default Mode vs 6 11
GZIP Brotli Optimal middle ground vs 6 4
GZIP Brotli Optimal middle ground vs 6 4 Brotli tends
to compress better with the same speed
GZIP Brotli Optimal middle ground vs 6 4 You don't
have to do it on the fly...
blogs.akamai.com/2016/02/understanding-brotlis-potential.html
caniuse.com/#feat=brotli
None
None
Serve tailored media
<picture> <!-- serve WebP to Chrome and Opera --> <source
media="(min-width: 50em)" sizes="50vw" srcset="/image/thing-200.webp 200w, /image/thing-400.webp 400w, /image/thing-800.webp 800w, /image/thing-1200.webp 1200w, /image/thing-1600.webp 1600w, /image/thing-2000.webp 2000w" type="image/webp"> <source sizes="(min-width: 30em) 100vw" srcset="/image/thing-crop-200.webp 200w, /image/thing-crop-400.webp 400w, /image/thing-crop-800.webp 800w, /image/thing-crop-1200.webp 1200w, /image/thing-crop-1600.webp 1600w, /image/thing-crop-2000.webp 2000w" type="image/webp"> <!-- serve JPEG to others --> <source media="(min-width: 50em)" sizes="50vw" srcset="/image/thing-200.jpg 200w, /image/thing-400.jpg 400w, /image/thing-800.jpg 800w, /image/thing-1200.jpg 1200w, /image/thing-1600.jpg 1600w, /image/thing-2000.jpg 2000w"> <source sizes="(min-width: 30em) 100vw"
/image/thing-800.webp 800w, /image/thing-1200.webp 1200w, /image/thing-1600.webp 1600w, /image/thing-2000.webp 2000w" type="image/webp"> <source
sizes="(min-width: 30em) 100vw" srcset="/image/thing-crop-200.webp 200w, /image/thing-crop-400.webp 400w, /image/thing-crop-800.webp 800w, /image/thing-crop-1200.webp 1200w, /image/thing-crop-1600.webp 1600w, /image/thing-crop-2000.webp 2000w" type="image/webp"> <!-- serve JPEG to others --> <source media="(min-width: 50em)" sizes="50vw" srcset="/image/thing-200.jpg 200w, /image/thing-400.jpg 400w, /image/thing-800.jpg 800w, /image/thing-1200.jpg 1200w, /image/thing-1600.jpg 1600w, /image/thing-2000.jpg 2000w"> <source sizes="(min-width: 30em) 100vw" srcset="/image/thing-crop-200.jpg 200w, /image/thing-crop-400.jpg 400w, /image/thing-crop-800.jpg 800w, /image/thing-crop-1200.jpg 1200w, /image/thing-crop-1600.jpg 1600w, /image/thing-crop-2000.jpg 2000w"> <!-- fallback for browsers that don't support picture --> <img src="/image/thing.jpg" width="50%"> </picture>
Accept: image/webp, image/apng, image/*,*/*;q=0.8 Request Header
caniuse.com/#feat=webp
Accept-CH: Width, Viewport-Width Accept-CH-Lifetime: 100 Request URL: https://.../header.jpg Viewport-Width: 980
Width: 980
<img src="/header.jpg" alt="" sizes="100vw" /> Accept: image/webp,image/apng,image/*,*/*;q=0.8 Request URL: https://.../header.jpg
Viewport-Width: 980 Width: 980
<img src="/header.jpg" alt="" sizes="100vw" /> Accept: image/webp,image/apng,image/*,*/*;q=0.8 Request URL: https://.../header.jpg
Viewport-Width: 980 Width: 1960
<img src="/header.jpg" alt="" sizes="100vw" /> Accept: image/webp,image/apng,image/*,*/*;q=0.8 Request URL: https://.../header.jpg
Viewport-Width: 980 Width: 1064 Serve a tailored version via server/service worker
speaking.jeremy.codes/yD4dKY/take-a-client-hint
www.zdnet.com/article/privacy-concerns-raised-about-upcoming-client-hints-web-standard/
Sec-CH-UA: "Examplary Browser"; v="73" Accept-CH: UA, Platform Sec-CH-UA: "Examplary Browser";
v="73.3R8.2H.1" Sec-CH-UA-Platform: "Windows"; v="10"
wicg.github.io/ua-client-hints/
Save data
save-data: on if ("connection" in navigator) { if (navigator.connection.saveData ===
true) { // Implement data saving operations here. } } Request Header
None
Let's use the platform and make these features more visible
https://.... Save data?
https://.... Save data? We should provide an easy way to
save data!
Save data? https://.... Prefer reduced motion? Prefer a dark interface?
Save data? https://.... Reduced Motion? Dark colour Scheme? All these
settings should be easily accessible all the time!
None
blog.chromium.org/2019/03/chrome-lite-pages-for-faster-leaner.html
blog.chromium.org/2019/03/chrome-lite-pages-for-faster-leaner.html I'm not sure how I feel about that...
Cache-Control: max-age=31536000, public, no-transform Response Header
Be aware of CDNs and proxies – use vary
None
Should browsers or developers optimise?
The browser can only optimise to a certain extend...
None
20% of requests...
https:/ /nooshu.github.io/blog/2019/09/01/speeding-up-the-web-with-save-data-header/
Less Data Doesn't Mean a Lesser Experience Tim Kadlec
the-responsible.dev/affordable/
The web is with us every day
2018.bloomca.me
It has to be respectful!
Get stuff "down" as quickly as possible
Link: </unleashed.jpg>; rel=preload; as=image; no-push <link rel="preload" href="/unleashed.jpg" as="image"> Response
Header
Link: </unleashed.jpg>; rel=preload; as=image; no-push <link rel="preload" href="/unleashed.jpg" as="image"> Response
Header This is great to speed up critical resources
caniuse.com/#feat=link-rel-preload * * behind a flag
Don't annoy the user (aka. the AMP reaction)
speakerdeck.com/stefanjudis/amp-tries-to-fix-the-web-what-can-we-learn-from-it?slide=112
Feature-Policy: vibrate 'none'; geolocation 'none' Response Header
accelerometer ambient-light-sensor autoplay camera document-domain encrypted-media fullscreen geolocation gyroscope layout-animations
legacy-image-formats magnetometer microphone midi oversized-images payment picture-in-picture speaker sync-xhr unoptimized-images unsized-media usb vibrate vr developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy
accelerometer ambient-light-sensor autoplay camera document-domain encrypted-media fullscreen geolocation gyroscope layout-animations
legacy-image-formats magnetometer microphone midi oversized-images payment picture-in-picture speaker sync-xhr unoptimized-images unsized-media usb vibrate vr developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy
accelerometer ambient-light-sensor autoplay camera document-domain encrypted-media fullscreen geolocation gyroscope layout-animations
legacy-image-formats magnetometer microphone midi oversized-images payment picture-in-picture speaker sync-xhr unoptimized-images unsized-media usb vibrate vr developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Feature-Policy
tiny-helpers.dev
<img srcset="/screenshots/{{ item.slug }}@1.jpg 1x, /screenshots/{{ item.slug }}@2.jpg 2x" src="/screenshots/{{
item.slug }}@2.jpg" alt="Screenshot of {{ item.name }}" loading="lazy"> <img srcset="/screenshots/{{ item.slug }}@1.jpg 1x, /screenshots/{{ item.slug }}@2.jpg 2x" src="/screenshots/{{ item.slug }}@2.jpg" alt="Screenshot of {{ item.name }}" width="1000" height="600" loading="lazy">
tiny-helpers.dev
www.youtube.com/watch?v=4-d_SoCHeWE
www.youtube.com/watch?v=4-d_SoCHeWE Define width & height to avoid jumpy pages
None
new ReportingObserver((reports, observer) => { reports.forEach(({type, url, body}) => {
console.log(type, url); // 'feature-policy-violation', https://some-url.com/... console.log(body); // { // featureId: 'oversized-images', // sourceFile: 'https://path-to-image/... // ... // } }); }, {types: ['feature-policy-violation'], buffered: true}).observe();
Report-To: { "max_age": 10886400, "endpoints": [{ "url": "https://stefanjudis.com/.../general-report" }] }
timkadlec.com/remembers/2020-02-20-in-browser-performance-linting-with-feature-policies/
feature-policy: accelerometer 'none'; camera 'none'; geolocation 'none'; gyroscope 'none'; magnetometer
'none'; microphone 'none'; payment 'none'; usb 'none' Response Header
<iframe allow="camera 'none'; microphone 'none'"> document.featurePolicy.allowedFeatures(); // → ["geolocation", "midi",
...] document.featurePolicy.allowsFeature('geolocation'); // → true document.featurePolicy.getAllowlistForFeature('geolocation'); // → ["https://example.com"]
What happened to the most annoying one?
github.com/w3c/webappsec-feature-policy/issues/243
blog.chromium.org/2020/01/introducing-quieter-permission-ui-for.html
caniuse.com/#feat=feature-policy ** support only for allow on iframes ** *
support for Feature-Policy header, allow on iframes, and JS API behind a flag * * * **
Respect privacy
None
caniuse.com/#feat=do-not-track
webkit.org/blog/8594/release-notes-for-safari-technology-preview-75/
caniuse.com/#feat=do-not-track
caniuse.com/#feat=do-not-track It was a nice try, but I don't really
see that happening...
None
None
None
None
www.xanjero.com/news/samsung-internet-beta-version-9-2-now-includes-oneui-design-smart- anti-tracking-and-more-features/
webkit.org/blog/category/privacy/
www.engadget.com/2019/11/04/chromium-edge-browser-release-date/
The next browser war is on its way...
the-responsible.dev/respectful/
Building for the web is very hard
Design Performance Content Accessibility Devices Network Frameworks
Lighthouse
webhint.io
If you want to get a more complete overview...
www.twilio.com/blog/a-http-headers-for-the-responsible-developer
securityheaders.com
schepp.github.io/HTTP-headers
youtu.be/II9m9_esNZc
The web has to be safe...
The web has to be safe, affordable...
The web has to be safe, affordable and respectful...
... so that it really is for everybody!
@stefanjudis www.stefanjudis.com Thanks. Slides: my-links.online/the-responsible-dev
@stefanjudis www.stefanjudis.com Thanks. Slides: my-links.online/the-responsible-dev I have some stickers!