Security Created by Johannes Hoppe
ZielAngriffsvektoren aufzeigen. Strategien besprechen. Mehr nicht!
FeaturesNeue Angriffsvektoren
Ein Formular Username: Password: Login <form id="login" action="#"> Username: <input type="text" name="username"> Password: <input type="password" name="password"> <input type="submit" value="Login"> </form>
Formaction Username: Password: Login Klick mich! <form id="login" action="#"> Username: <input type="text" name="username"> Password: <input type="password" name="password"> <input type="submit" value="Login"> </form> <button type="submit" form="login" formaction="http://example.org"> Klick mich! </button>
SVG Presto, WebKit, Gecko und sogar Trident 9 <?xml version="1.0"?> <svg xmlns="http://www.w3.org/2000/svg" width="40" height="40"> <circle cx="20" cy="20" r="15" fill="yellow" stroke="black"/> <circle cx="15" cy="15" r="2" fill="black" stroke="black"/> <circle cx="25" cy="15" r="2" fill="black" stroke="black"/> <path d="M 13 26 A 5 3 0 0 0 27 26" stroke="black" fill="none" stroke -width="2"/> </svg>
SVG kann JavaScript enthalten! Test <?xml version="1.0"?> <svg xmlns="http://www.w3.org/2000/svg" width="200" height="50"> <defs><style> </style></defs> <circle cx="20" cy="20" r="15" fill="yellow" stroke="black"/> <circle cx="15" cy="15" r="2" fill="black" stroke="black"/> <circle cx="25" cy="15" r="2" fill="black" stroke="black"/> <path d="M 13 26 A 5 3 0 0 0 27 26" stroke="black" fill="none" stroke -width="2" transform="rotate(180, 20, 28)"/> <text x="11" y="50" id="display">Test</text> <script> </script> </svg> <![CDATA[ text { font-size:6pt; } ]]> alert(document.cookie); document.getElementById('display').textContent = document.cookie;
Business as usual HTML5 es ist auch nicht schlimmer als HTML 4 » http://html5sec.org
XSSEingeschleuster JavaScript-Code
Oldies but Goldies index.html?message=Daten gespeichert index.html?message=<script>alert('XSS')</script> <script> var message = $.url().param('message'); if (message) { Notifier.success(message); } </script>
Eval everywhere Eval is evil » Demo <!-- Self-executing onFocus event via autoFocus --> <input onfocus="alert('XSS onfocus')" autofocus> <!-- Video OnError --> <video><source onerror="javascript:alert('XSS onerror')"></video> <!-- Presto only: Form surveillance --> <form id=test onforminput=alert('XSS onforminput')> <input> </form> <button form=test onformchange=alert('XSS onformchange')>X</button> 1 2 3
OWASPOpen Web Application Security Project XSS Filter Evasion Cheat Sheet <!-- Long UTF-8 Unicode encoding without semicolons --> <IMG SRC="&#34&#32&#111&#110&#101&#114&#114&#111&#114&#61&#34&#97&#108& #101&#114&#116&#40&#39&#88&#83&#83&#39&#41&#59"> » Old IE Demo
XSS Vorbeugen
1.Hier sollten dynamische Daten niemals verwendet werden <script> </script> <!-- HIER --> <div HIER="test"/> <HIER href="test" /> <style> </style> HIER HIER
2.HTML escape dynamic data & → &amp; < → &lt; > → &gt; " → &quot; ' → &apos; / &#39; <div>HTML ESCAPE</div>
Testen? function htmlEncode(input) { // jquery.text == document.createTextNode return ($('<div/>').text(input).html()); } var saveFormat = function () { var args = Array.prototype.slice.call(arguments); var txt = args.shift(); $.each(args, function (i, item) { item = htmlEncode(item); txt = txt.replace("{" + i + "}", item); }); return txt; };
Testen! describe("saveFormat", function () { var original = '{0} - {1} - {2}'; it("should replace placeholders", function () { var expected = 'A - B - C'; var formated = saveFormat(original, 'A', 'B', 'C'); expect(formated).toEqual(expected); }); it("should encode injected content", function () { var expected = 'A - &lt;b&gt;TEST&lt;/b&gt; - C'; var formated = saveFormat(original, 'A', '<b>TEST</b>', 'C'); expect(formated).toEqual(expected); }); });
Test finished in 0.007s •• No try/catch Jasmine 1.3.1 revision 1354556913 Passing2specs saveFormat should replace placeholders should encode injected content » Demo
Moment... describe("saveFormat", function () { var original = '<a title="{0}">Test</a>'; it("should replace quotes", function () { var expected = '<a title="&quot;">Test</a>'; var formated = saveFormat(original, '"'); expect(formated).toEqual(expected); }); });
Richtig testen! finished in 0.006s x No try/catch Jasmine 1.3.1 revision 1354556913 Failing1spec 1spec|1 failing saveFormat should replace quotes. Expected '<a title=""">Test</a>' to equal '<a title="&quot;">Test</a>'. Error: Expected '<a title=""">Test</a>' to equal '<a title="&quot;">Test</a>'. at new jasmine.ExpectationResult (http://localhost:1332/examples/jasmine/lib/j at null.toEqual (http://localhost:1332/examples/jasmine/lib/jasmine-1.3.1/jasm at null.<anonymous> (http://localhost:1332/examples/jasmine-demo2/saveFormat.s at jasmine.Block.execute (http://localhost:1332/examples/jasmine/lib/jasmine-1 at jasmine.Queue.next_ (http://localhost:1332/examples/jasmine/lib/jasmine-1.3 » Demo
3.Attribute escape dynamic data a-z A-Z 0-9 → immun , . - _ → immun Rest → &#xHH; <div attr="ATTRIBUTE ESCAPE"></div> <!-- NIEMALS ohne quotes! --> <div attr=ATTRIBUTE ESCAPE></div>
4. DO NOTJavaScript escape dynamic data HTML parser runs before the JavaScript parser! you are doing it wrong
Das hier ist Alltag UserList.cshtml / Kendo UI Template # if(ID != 0) { # <a href="javascript:DialogManager.ShowPartialDialog('@Url.Action("UserM anagement", "Management")', { userId : '#= htmlEncode(ID) #' }, {title: '#= htmlEncode(Alias) #'})"#= htmlEncode(Alias) #</a> # } else { # #= htmlEncode(Alias) # # } #
?Offensichtlich läuft beim Umgang mit Daten etwas prinzipiell falsch!
Storage
Egal ob Cookies ob Session Storage ob Local Storage ob WebSQL die Daten sind nicht vertrauenswürdig!
Resident XSS richtig fies!
Vertraulichen Informationen gehören in die SERVER-Session!
Session Storage bevorzugen!
WebSQL SQL Injection: Prepared Statement: executeSql("SELECT foo FROM bar WHERE value=" + value); executeSql("SELECT foo FROM bar WHERE value=?", [value]);
Kommunikation
Mashups! define(['jquery', 'knockout', 'knockout.mapping', 'domReady!'], function ($, ko, mapping) { var url ='http://search.twitter.com/search.json?q=%23xss&callback=?'; $.getJSON(url).done(function (data) { var viewModel = mapping.fromJS(data); ko.applyBindings(viewModel, $('#tweets').get(0)); }); });
Loading...
JSON JSON with Padding {"hello": "world"} <script> </script> <script src="http://search.twitter.com/search.json?q=%23dnc13&callback= foo"></script> var foo = function(json) { $('#output').text(JSON.stringify(json, undefined, 2)); }; foo({"hello": "world"}); » Demo
JSONP
SOP Same origin policy → Not macht erfinderisch (JSONP) CORS Cross-Origin Resource Sharing → Access-Control-Allow-Origin: * WebSockets do what you want
JS-Recon Shell of the Future
Intranet == Internet
Danke!
» Sicherheit von Web-Anwendungen

2013 05-03 - HTML5 & JavaScript Security

  • 1.
  • 2.
  • 3.
  • 4.
    Ein Formular Username: Password: Login <form id="login"action="#"> Username: <input type="text" name="username"> Password: <input type="password" name="password"> <input type="submit" value="Login"> </form>
  • 5.
    Formaction Username: Password: Login Klick mich! <form id="login"action="#"> Username: <input type="text" name="username"> Password: <input type="password" name="password"> <input type="submit" value="Login"> </form> <button type="submit" form="login" formaction="http://example.org"> Klick mich! </button>
  • 6.
    SVG Presto, WebKit, Geckound sogar Trident 9 <?xml version="1.0"?> <svg xmlns="http://www.w3.org/2000/svg" width="40" height="40"> <circle cx="20" cy="20" r="15" fill="yellow" stroke="black"/> <circle cx="15" cy="15" r="2" fill="black" stroke="black"/> <circle cx="25" cy="15" r="2" fill="black" stroke="black"/> <path d="M 13 26 A 5 3 0 0 0 27 26" stroke="black" fill="none" stroke -width="2"/> </svg>
  • 7.
    SVG kann JavaScript enthalten! Test <?xmlversion="1.0"?> <svg xmlns="http://www.w3.org/2000/svg" width="200" height="50"> <defs><style> </style></defs> <circle cx="20" cy="20" r="15" fill="yellow" stroke="black"/> <circle cx="15" cy="15" r="2" fill="black" stroke="black"/> <circle cx="25" cy="15" r="2" fill="black" stroke="black"/> <path d="M 13 26 A 5 3 0 0 0 27 26" stroke="black" fill="none" stroke -width="2" transform="rotate(180, 20, 28)"/> <text x="11" y="50" id="display">Test</text> <script> </script> </svg> <![CDATA[ text { font-size:6pt; } ]]> alert(document.cookie); document.getElementById('display').textContent = document.cookie;
  • 9.
    Business as usual HTML5es ist auch nicht schlimmer als HTML 4 » http://html5sec.org
  • 10.
  • 11.
    Oldies but Goldies index.html?message=Datengespeichert index.html?message=<script>alert('XSS')</script> <script> var message = $.url().param('message'); if (message) { Notifier.success(message); } </script>
  • 12.
    Eval everywhere Eval isevil » Demo <!-- Self-executing onFocus event via autoFocus --> <input onfocus="alert('XSS onfocus')" autofocus> <!-- Video OnError --> <video><source onerror="javascript:alert('XSS onerror')"></video> <!-- Presto only: Form surveillance --> <form id=test onforminput=alert('XSS onforminput')> <input> </form> <button form=test onformchange=alert('XSS onformchange')>X</button> 1 2 3
  • 13.
    OWASPOpen Web ApplicationSecurity Project XSS Filter Evasion Cheat Sheet <!-- Long UTF-8 Unicode encoding without semicolons --> <IMG SRC="&#34&#32&#111&#110&#101&#114&#114&#111&#114&#61&#34&#97&#108& #101&#114&#116&#40&#39&#88&#83&#83&#39&#41&#59"> » Old IE Demo
  • 14.
  • 15.
    1.Hier sollten dynamische Datenniemals verwendet werden <script> </script> <!-- HIER --> <div HIER="test"/> <HIER href="test" /> <style> </style> HIER HIER
  • 16.
    2.HTML escape dynamic data &→ &amp; < → &lt; > → &gt; " → &quot; ' → &apos; / &#39; <div>HTML ESCAPE</div>
  • 17.
    Testen? function htmlEncode(input) { //jquery.text == document.createTextNode return ($('<div/>').text(input).html()); } var saveFormat = function () { var args = Array.prototype.slice.call(arguments); var txt = args.shift(); $.each(args, function (i, item) { item = htmlEncode(item); txt = txt.replace("{" + i + "}", item); }); return txt; };
  • 18.
    Testen! describe("saveFormat", function (){ var original = '{0} - {1} - {2}'; it("should replace placeholders", function () { var expected = 'A - B - C'; var formated = saveFormat(original, 'A', 'B', 'C'); expect(formated).toEqual(expected); }); it("should encode injected content", function () { var expected = 'A - &lt;b&gt;TEST&lt;/b&gt; - C'; var formated = saveFormat(original, 'A', '<b>TEST</b>', 'C'); expect(formated).toEqual(expected); }); });
  • 19.
    Test finished in 0.007s •• Notry/catch Jasmine 1.3.1 revision 1354556913 Passing2specs saveFormat should replace placeholders should encode injected content » Demo
  • 20.
    Moment... describe("saveFormat", function (){ var original = '<a title="{0}">Test</a>'; it("should replace quotes", function () { var expected = '<a title="&quot;">Test</a>'; var formated = saveFormat(original, '"'); expect(formated).toEqual(expected); }); });
  • 21.
    Richtig testen! finished in0.006s x No try/catch Jasmine 1.3.1 revision 1354556913 Failing1spec 1spec|1 failing saveFormat should replace quotes. Expected '<a title=""">Test</a>' to equal '<a title="&quot;">Test</a>'. Error: Expected '<a title=""">Test</a>' to equal '<a title="&quot;">Test</a>'. at new jasmine.ExpectationResult (http://localhost:1332/examples/jasmine/lib/j at null.toEqual (http://localhost:1332/examples/jasmine/lib/jasmine-1.3.1/jasm at null.<anonymous> (http://localhost:1332/examples/jasmine-demo2/saveFormat.s at jasmine.Block.execute (http://localhost:1332/examples/jasmine/lib/jasmine-1 at jasmine.Queue.next_ (http://localhost:1332/examples/jasmine/lib/jasmine-1.3 » Demo
  • 22.
    3.Attribute escape dynamic data a-zA-Z 0-9 → immun , . - _ → immun Rest → &#xHH; <div attr="ATTRIBUTE ESCAPE"></div> <!-- NIEMALS ohne quotes! --> <div attr=ATTRIBUTE ESCAPE></div>
  • 23.
    4. DO NOTJavaScriptescape dynamic data HTML parser runs before the JavaScript parser! you are doing it wrong
  • 24.
    Das hier istAlltag UserList.cshtml / Kendo UI Template # if(ID != 0) { # <a href="javascript:DialogManager.ShowPartialDialog('@Url.Action("UserM anagement", "Management")', { userId : '#= htmlEncode(ID) #' }, {title: '#= htmlEncode(Alias) #'})"#= htmlEncode(Alias) #</a> # } else { # #= htmlEncode(Alias) # # } #
  • 25.
    ?Offensichtlich läuft beimUmgang mit Daten etwas prinzipiell falsch!
  • 26.
  • 27.
    Egal ob Cookies ob SessionStorage ob Local Storage ob WebSQL die Daten sind nicht vertrauenswürdig!
  • 28.
  • 29.
  • 30.
  • 31.
    WebSQL SQL Injection: Prepared Statement: executeSql("SELECTfoo FROM bar WHERE value=" + value); executeSql("SELECT foo FROM bar WHERE value=?", [value]);
  • 32.
  • 33.
    Mashups! define(['jquery', 'knockout', 'knockout.mapping', 'domReady!'],function ($, ko, mapping) { var url ='http://search.twitter.com/search.json?q=%23xss&callback=?'; $.getJSON(url).done(function (data) { var viewModel = mapping.fromJS(data); ko.applyBindings(viewModel, $('#tweets').get(0)); }); });
  • 34.
  • 35.
    JSON JSON with Padding {"hello":"world"} <script> </script> <script src="http://search.twitter.com/search.json?q=%23dnc13&callback= foo"></script> var foo = function(json) { $('#output').text(JSON.stringify(json, undefined, 2)); }; foo({"hello": "world"}); » Demo
  • 36.
  • 37.
    SOP Same origin policy→ Not macht erfinderisch (JSONP) CORS Cross-Origin Resource Sharing → Access-Control-Allow-Origin: * WebSockets do what you want
  • 38.
  • 40.
  • 41.
  • 43.
    » Sicherheit vonWeb-Anwendungen