Integrity protection for third-party JavaScript

Integrity protection for third-party JavaScript

Modern web applications depend on a lot of auxiliary scripts which are often hosted on third-party CDNs. Should an attacker be able to tamper with the files hosted on such a CDN, millions of sites could be compromised. Web developers need a way to guarantee the integrity of scripts hosted elsewhere.

This is the motivation behind a new addition to the web platform being introduced by the W3C: sub-resource integrity (http://www.w3.org/TR/SRI/). Both Firefox and Chrome have initial implementations of this new specification and a few early adopters such as Github are currently evaluating this feature.

0110e86fdb31486c22dd381326d99de9?s=128

Francois Marier

June 04, 2015
Tweet

Transcript

  1. <script src=”https://ajax.googl eapis.com/ajax/libs/jquery/1.8. 0/jquery.min.js” integrity=”typ e:text/javascript sha512-AODL7i dgffQeNsYdTzut09nz9AINcjhj4jHD7 2HcLirsidbC8tz+dof7gceOCQD8Wske uRFfJ9CsgZTHlMiOYg==”></script>

    Integrity protection for 3rd-party JavaScript François Marier @fmarier mozilla
  2. Firefox Security & Privacy

  3. Web Platform

  4. Web Platform

  5. Content Security Policy aka CSP

  6. Content Security Policy aka CSP mechanism for preventing XSS

  7. telling the browser what external content is allowed to load

  8. what does CSP look like?

  9. $ curl --head https://mega.nz HTTP/1.1 200 OK Content-Type: text/html Content-Length:

    1989 Content-Security-Policy: default-src 'self' *.mega.co.nz *.mega.nz http://*.mega.co.nz http://*.mega.nz; script-src 'self' mega.co.nz mega.nz data: blob:; style-src 'self' 'unsafe-inline' *.mega.nz *.mega.co.nz data: blob:; frame-src 'self' mega:; img-src 'self' *.mega.co.nz *.mega.nz data:
  10. Hi you<script> alert('p0wned'); </script>! Tweet! What's on your mind?

  11. without CSP

  12. Hi you! John Doe - just moments ago p0wned Ok

  13. with CSP

  14. Hi you! John Doe - just moments ago

  15. Content-Security-Policy: script-src 'self' https://cdn.example.com

  16. inline scripts are blocked unless unsafe-inline is specified

  17. script-src object-src style-src img-src media-src frame-src font-src connect-src

  18. $ curl --head https://twitter.com HTTP/1.1 200 OK content-length: 58347 content-security-policy:

    … report-uri https://twitter.com/csp_report violation reports:
  19. "csp-report": { "document-uri": "http://example.org/page.html", "referrer": "http://evil.example.com/haxor.html", "blocked-uri": "http://evil.example.com/image.png", "violated-directive": "default-src

    'self'", "effective-directive": "img-src", "original-policy": "default-src 'self'; report-uri http://example.org/..." }
  20. None
  21. support for inline scripts Content-Security-Policy: script-src 'sha256-YWIzOW...'

  22. None
  23. Strict Transport Security aka HSTS

  24. Strict Transport Security aka HSTS mechanism for preventing HTTPS to

    HTTP downgrades
  25. telling the browser that your site should never be reached

    over HTTP
  26. None
  27. GET bank.com.au 301 → GET https://bank.com.au 200 → no HSTS,

    no sslstrip
  28. GET bank.com.au → 200 no HSTS, with sslstrip

  29. what does HSTS look like?

  30. $ curl -i https://login.xero.com HTTP/1.1 200 OK Cache-Control: private Content-Type:

    text/html; charset=utf-8 Strict-Transport-Security: max-age=31536000 X-Frame-Options: SAMEORIGIN
  31. with HSTS, with sslstrip GET https://bank.com.au 200 →

  32. silent client-side redirects HTTP → HTTPS

  33. no HTTP traffic for sslstrip to tamper with

  34. except for the very first connection

  35. https://hstspreload.appspot.com/

  36. pop quiz! how many .au sites are on the preload

    list?
  37. aurainfosec.com.au bcm.com.au bigbrownpromotions.com.au comssa.org.au data.qld.gov.au dreamsforabetterworld.com.au dylanscott.com.au fatzebra.com.au freethought.org.au netrider.net.au

    publications.qld.gov.au technotonic.com.au thomastimepieces.com.au tracktivity.com.au tradingcentre.com.au webandwords.com.au 16
  38. aurainfosec.com.au bcm.com.au bigbrownpromotions.com.au comssa.org.au data.qld.gov.au dreamsforabetterworld.com.au dylanscott.com.au fatzebra.com.au freethought.org.au netrider.net.au

    publications.qld.gov.au technotonic.com.au thomastimepieces.com.au tracktivity.com.au tradingcentre.com.au webandwords.com.au
  39. None
  40. None
  41. None
  42. None
  43. 2015?

  44. None
  45. None
  46. None
  47. None
  48. https://ajax.googleapis.com /ajax/libs/jquery/1.8.0/ jquery.min.js

  49. how common is this?

  50. None
  51. what would happen if that server were compromised?

  52. None
  53. Bad Things™ steal sessions leak confidential data redirect to phishing

    sites enlist DDoS zombies
  54. simple solution

  55. instead of this: <script src=”https://ajax.googleapis.com...”>

  56. <script src=”https://ajax.googleapis.com...” integrity=”sha256-1z4uG/+cVbhShP...”> do this:

  57. You owe me $10.00. f4243c12541be6f79c73e539c426e07a f2f6c4ef8794894f4903aee54542586d

  58. You owe me $1000. 1ebd7a8d15a6dab743f0c4d147f731bc fc6b74752afe43afa5389ba8830a2215

  59. guarantee: script won't change or it'll be blocked

  60. limitation: won't work for scripts that change all the time

  61. 3 types of scripts

  62. dynamically-generated script: not a good fit for SRI I

  63. immutable scripts: perfect for SRI II

  64. https://ajax.googleapis.com /ajax/libs/jquery/1.8.0/ jquery.min.js

  65. what about your own scripts? (they change, but you're the

    one changing them)
  66. III scripts under your control: good fit for SRI

  67. can usually add the hashing to your static resource pipeline

  68. #!/bin/sh cat src/*.js > bundle.js HASH=`sha256sum bundle.js |cut -f1 -d'

    '` mv bundle.js public/bundle-${HASH}.js
  69. public/bundle-c2498bc358....js Cache-Control: max-age=∞

  70. <script src=”widgets.js”> <script src=”app.js”> <script src=”menu.js”>

  71. <script src=”bundle-c2498bc....js”>

  72. <script src=”bundle-c2498bc....js” integrity=”sha256-c2498bc...”>

  73. what else?

  74. integrity=” sha256-9Cm9ekBvKrtQ0A... “ sha256-rKSr3LcX+EkeM=... sha256-1z4uG/+cVbhShP... sha384-RqG7UC/QK2TVRa... sha512-AODL7idgffQeNs... ”

  75. integrity=” sha256-9Cm9ekBvKrtQ0A... sha256-rKSr3LcX+EkeM=... sha256-1z4uG/+cVbhShP... “ sha384-RqG7UC/QK2TVRa... sha512-AODL7idgffQeNs... ”

  76. integrity=” sha256-9Cm9ekBvKrtQ0A... sha256-rKSr3LcX+EkeM=... sha256-1z4uG/+cVbhShP... sha384-RqG7UC/QK2TVRa... sha512-AODL7idgffQeNs... ”

  77. what about cross-origin requests?

  78. “a web browser permits scripts contained in a first web

    page to access data in a second web page, but only if both web pages have the same origin” same-origin policy
  79. example.com/index.html

  80. example.com/index.html example.com/data.js: var secret = 42;

  81. example.com/index.html example.com/data.js: var secret = 42; evil.net/widget.js: exfiltrate(secret);

  82. example.com/index.html example.com/data.js: var secret = 42; evil.net/widget.js: exfiltrate(secret);

  83. None
  84. on the server: Access-Control-Allow-Origin: *

  85. on the server: Access-Control-Allow-Origin: * on the client: crossorigin=”anonymous”

  86. <script src=”https://ajax.googleapis.com...” integrity=”sha256-1z4uG/+cVbhShP...” crossorigin=”anonymous”> complete example:

  87. <link rel="stylesheet" href="style.css" integrity="sha256-PgMdguwx/O..." crossorigin=”anonymous”> complete example:

  88. cat file.js | openssl dgst -sha256 -binary | openssl enc

    -base64 -A
  89. SRIhash.org

  90. None
  91. status?

  92. spec is being finalized

  93. (initial implementations)

  94. demo

  95. <html> <head> <title>Bug 992096 - Implement SRI</title> <link rel="stylesheet" href="http://localhost/francois/sri/style.css"

    integrity=" sha256-PgMdguwx/O1ZJKqtGj54HIScoj0UEDV4ti5tLuc4DvA=" crossorigin="anonymous"> </head> <body> <h1>This should be red if the hash matches!</h1> </body> </html>
  96. h1 { color: red; }

  97. None
  98. None
  99. <html> <head> <title>Bug 992096 - Implement SRI</title> <link rel="stylesheet" href="http://localhost/francois/sri/style.css"

    integrity=" sha256-bogus" crossorigin="anonymous"> </head> <body> <h1>This should be red if the hash matches!</h1> </body> </html>
  100. None
  101. None
  102. Questions? feedback: francois@mozilla.com mozilla.dev.security public-webappsec@w3.org © 2015 François Marier <francois@mozilla.com>

    This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 License.
  103. photo credits: bank notes: https://www.flickr.com/photos/epsos/8463683689 web devs: https://www.flickr.com/photos/mbiddulph/238171366 explosion: https://www.flickr.com/photos/-cavin-/2313239884/