Säkra webbapplikationer John Wilander, Omegapoint, KTH maj 2010
John Wilander, konsult Omegapoint Forskar inom mjukvarusäkerhet Leder svenska OWASP Certifierad inom Javautveckling och Security Development Lifecycle OWASP En öppen, icke-kommersiell community för alla som utvecklar, förvaltar eller köper webbapplikationer med höga säkerhetskrav
Säkerhet Utveckling
IT-säkerhet Systemutveckling
IT-säkerhet Applikationssäkerhet Systemutveckling
Webbens historia (enligt John)
<html> <head> <title>owasp AppSec Research</title> </head> <body> <form action="login" method="post"> <table> <tr><td>username: </td> <td><input name="username" type="text"></td> </tr> <tr><td>password: </td> <td><input name="password" type="password"></td> </tr> <tr><td></td> <td><input type="submit" value="login"></td> </tr> </table> </form> </body> </html> Statiska HTML-sidor 1991
<html> <head> <title>owasp AppSec Research</title> </head> <body> <form action="login" method="post"> <table> <tr><td>username: </td> <td><input name="username" type="text"></td> </tr> <tr><td>password: </td> <td><input name="password" type="password"></td> </tr> <tr><td></td> <td><input type="submit" value="login"></td> </tr> </form> </body> </html> </table> HTTP/1.1 200 OK Content-type: text/html Set-Cookie: name=value Cookies 1994
<html> <head> <title>owasp AppSec Research</title> </head> <body> <form action="login" method="post"> <table> <tr><td>username: </td> <td><input name="username" type="text"></td> </tr> <tr><td>password: </td> <td><input name="password" type="password"></td> </tr> <tr><td></td> <td><input type="submit" value="login"></td> </tr> </table> </form> </body> </html> HTTP/1.1 200 OK Content-type: text/html Set-Cookie: name=value 1995 $(function() { $("#button").click(function() { var username = $("input#username").val(); var password = $("input#password").val(); var datastring = 'username='+ username + '&password=' + password; $.ajax({ type: "POST", url: "LoginAjax", data: datastring, success: function() { $('#login_form').html("<div id='message'></div>"); $('#message').html("<h2>welcome, " + username +"!</h2>").append("<p>you are now logged in to the system.</p>").hide().fadein(1500); }, error: function() { $('#login_form').html("<div id='message'></div>"); $('#message').html("<h2>username and/or password wrong</h2>").hide().fadein(1500); } }); return false; }); }); JavaScript
<html> <head> <title>owasp AppSec Research</title> </head> <body> <form action="login" method="post"> <table> <tr><td>username: </td> <td><input name="username" type="text"></td> </tr> <tr><td>password: </td> <td><input name="password" type="password"></td> </tr> <tr><td></td> <td><input type="submit" value="login"></td> </tr> </table> HTTP/1.1 200 OK </form> </body> Content-type: text/html 1999 </html> Set-Cookie: name=value $(function() { <html> $("#button").click(function() { <head> var username = $("input#username").val(); <title>owasp AppSec Research 2010 Challenge X</title> var password = $("input#password").val(); </head> var datastring = 'username='+ username + '&password=' + password; <body> $.ajax({ <form action="login" method="post"> type: "POST", <table> url: "LoginAjax", <tr><td>username: </td> data: datastring, <td><input name="username" type="text"></td> success: function() { </tr> $('#login_form').html("<div id='message'></div>"); <tr><td>password: </td> $('#message').html("<h2>welcome, " + username +"!</h2>") <td><input name="password" type="password"></td>.append("<p>you are now logged in to the system.</p>") </tr>.hide() <tr><td><div style="color: red">.fadein(1500); <% if ("true".equals(request.getattribute("loginfailed"))) { %> }, Bad login <% } %> error: function() { </div></td> $('#login_form').html("<div id='message'></div>"); <td><input type="submit" value="login"></td> $('#message').html("<h2>username and/or password wrong</h2>") </tr>.hide() </table>.fadein(1500); </form> } </div> }); </body> return false; }); </html> }); jsp-sidor (dynamisk HTML)
<html> <head> <title>owasp AppSec Research</title> </head> <body> <form action="login" method="post"> <table> <tr><td>username: </td> <td><input name="username" type="text"></td> </tr> <tr><td>password: </td> <td><input name="password" type="password"></td> </tr> <tr><td></td> <td><input type="submit" value="login"></td> </tr> </table> </form> </body> </html> HTTP/1.1 200 OK Content-type: text/html Set-Cookie: name=value function xmlhttppost(strurl) { var xmlhttpreq = false; AJAX var self = this; // Mozilla/Safari if (window.xmlhttprequest) { self.xmlhttpreq = new XMLHttpRequest(); } // IE else if (window.activexobject) { self.xmlhttpreq = new ActiveXObject("Microsoft.XMLHTTP"); } self.xmlhttpreq.open('post', strurl, true); self.xmlhttpreq.setrequestheader('content-type', 'application/xwww-form-urlencoded'); self.xmlhttpreq.onreadystatechange = function() { if (self.xmlhttpreq.readystate == 4) { updatepage(self.xmlhttpreq.responsetext); } } self.xmlhttpreq.send(getquerystring()); } $(function() { <html> $("#button").click(function() { <head> var username = $("input#username").val(); <title>owasp AppSec Research 2010 Challenge X</title> var password = $("input#password").val(); </head> var datastring = 'username='+ username + '&password=' + password; <body> $.ajax({ <form action="login" method="post"> type: "POST", <table> url: "LoginAjax", <tr><td>username: </td> data: datastring, <td><input name="username" type="text"></td> success: function() { </tr> $('#login_form').html("<div id='message'></div>"); <tr><td>password: </td> $('#message').html("<h2>welcome, " + username +"!</h2>") <td><input name="password" type="password"></td>.append("<p>you are now logged in to the system.</p>") </tr>.hide() <tr><td><div style="color: red">.fadein(1500); <% if ("true".equals(request.getattribute("loginfailed"))) { %> }, Bad login <% } %> error: function() { </div></td> $('#login_form').html("<div id='message'></div>"); <td><input type="submit" value="login"></td> $('#message').html("<h2>username and/or password wrong</h2>") </tr>.hide() </table>.fadein(1500); </form> } </div> }); </body> return false; }); </html> }); 2005
Utveckling av (o)säker programkod
Windows, Office
Cisco-routers
SAP
Applikationer!
Distribuera, installera, licensiera, uppgradera
2010 Rich Internet Applications
Applikationer utvecklas överallt
Hemsidor övergår i webbapplikationer
Webbapplikationer exponeras för Internet
Alla utvecklare måste förstå säkerhet
Fundamenten för säkra webbapplikationer
Same Origin Cookies Policy SSL
Same Origin Policy
Same Origin Policy
http://sajt.se/x/a.html http://sajt.se/x/b.html http://sajt.se/y/a.html OK http://www.sajt.se/x/a.html https://sajt.se/x/a.html http://sajt.se:8080/x/a.html Inte OK
Same Origin Policy Inte läsa Men exekvera text, skript, css skript, css
Men det är ju inte det vi vill ha :(
Kringå Same-Origin Policy Kommunicera server-side Använd JSONP JSON with Padding Sätt gemensam document.domain
Content Security Policy (förslag från Mozilla) Vitlista på källor för skript
Content Security Policy (förslag från Mozilla) Vitlista på källor för skript
Cookies
HTTP tillståndslöst GET http://www.sajt.se/ HTTP/1.1 HTTP/1.1 200 OK
HTTP tillståndslöst GET http://www.sajt.se/ HTTP/1.1 HTTP/1.1 200 OK
Att hålla en session Sessions-ID i URL www.sajt.se/ ;sessionid=1234 Sessions-ID i gömda formulärfält <INPUT TYPE= hidden NAME= sessionid VALUE= 1234 > Sessions-ID i kaka Set-Cookie: sessionid= 1234
HTTP + session GET http://www.sajt.se/ HTTP/1.1 HTTP/1.1 200 OK
HTTP + session GET http://www.sajt.se/ HTTP/1.1 HTTP/1.1 200 OK Cookie Monster 2009 Sesame Workshop
Sessionsattacker Cookie replay (återanvända) Cookie poisoning (skapa eller manipulera) Cookie hijacking (stjäla) Session fixation (sätta kaka åt offret)
Sessionsskydd Secure (bara skicka krypterat) HTTPOnly (ej tillgänglig för skript) Inget hemmasnickrat
SSL
Klient Protokollversion, sessions-id, kryptoalgoritm, kompressionsmetod Salt Server ClientHello(crypto_info, ) ServerHello(crypto_info, ) server-certifikat CertificateRequest Kontrollera servercertifikat klient-certifikat FatalHandshakeFailureAlert Kontrollera klientcertifikat Symmetriskt krypterat
Var är hänglåset?
<div class="menu_login_container"><form method="post" action="https:// login.facebook.com/login.php?login_attempt=1" id="login_form">
<div class="menu_login_container"><form method="post" action="https:// login.facebook.com/login.php?login_attempt=1" id="login_form"> Samma källkod? JavaScript som sniffar?
Moxie s SSL Strip Avbryter SSL Gör om https till http Normal https till servern Agerar klient
Moxie s SSL Strip Secure cookie? Encoding, gzip? Cachat innehåll? Sessioner?
Moxie s SSL Strip Secure cookie? Encoding, gzip? Cachat innehåll? Sessioner? Strip! Ta bort secure-biten på alla kakor. Strip! Ta bort alla encodings i request. Strip! Ta bort alla if-modified-since i request. Strip! 302 till samma sida, set-cookie expired
SSL Strip & Tor-nätet login.yahoo.com Gmail Hotmail PayPal 114 50 13 9 På 24 h
Antal som avbröt pga saknad kryptering: 0
Same Origin Cookies Policy SSL
Same Origin Content Policy Security Policy Cookies Äkta sessioner? SSL DNSSec?
john.wilander@omegapoint.se