Friday, January 7, 2022

Insecure Direct Object Reference prevention


insecure webapp example: by changing uid in url, user logged in can view others' profile.

log in as bob

logged in

bob can view his profile @ http://localhost:8080/profile/1

change url to http://localhost:8080/profile/2
bob can't get other's profile

log bob out, and log in as tom

tom can view his profile @ http://localhost:8080/profile/2

send put request with bob's credential to view tom's profile using postman
denied by server

//app.js
const jwtFunc = require('./jwt')
const express = require('express')
const app = express()
const port = 8080
const path = require('path');

var bodyParser = require('body-parser')
app.use(bodyParser.json());       // to support JSON-encoded bodies
app.use(bodyParser.urlencoded({     // to support URL-encoded bodies
    extended: true
}));

// serve your css as static
app.use(express.static(__dirname + '/public'));

var mysql = require('mysql')
var connection = mysql.createConnection({
    host: '127.0.0.1',
    user: 'dvwa',
    password: 'p@ssw0rd',
    database: 'sqlinjection'
})

connection.connect()

//render html
app.set('view engine', 'ejs');
app.engine('html', require('ejs').renderFile);

app.get('/', function (req, res) {
    res.render('index');
});

app.post('/', function (req, res) {
    var name = req.body.name;
    var password = req.body.password;

    connection.query('SELECT * from login where name = ? and password = ?', [name, password], function (err, rows, fields) {
        if (err) throw err

        if (rows.length > 0) {
            jwtFunc.createToken(req, res)
        }

        if (rows.length > 1) {
            throw 'find duplicate users in database'
        }

        res.render('index', { data: rows, token: req.token });
    })
});

app.post('/profile/:id', function (req, res) {

    jwtFunc.verifyToken(req, res)

    if (req.message == 'success') {

        connection.query('SELECT * from login where name = ? and id = ?', [req.name, req.params.id], function (err, rows, fields) {
            if (err) throw err

            if (rows.length == 0) {
                return res.render('profile', { message: 'not authorized to view other\'s profile' });
            }

            if (rows.length > 1) {
                throw 'find duplicate users in database'
            }

            return res.render('profile', { data: rows[0] });
        })
    }
    else {
        return res.render('profile', { message: req.message });
    }
});

app.listen(port, () => {
    console.log(`Example app listening at http://localhost:${port}`)
})

------------------------
//jwt.js
const jwtFunc = require('./jwt.js')
var jwt = require('jsonwebtoken');
var secret = 'secret'

function verifyToken(req, res) {
    var token = req.body.tokenInput;
    if (!token) {
        req.message = 'No token provided.';
        return
    }

    jwt.verify(token, secret, function (err, decoded) {
        if (err) {
            req.message = err.toString();
            return
        }

        // if everything good, save to request for use in other routes
        req.name = decoded.name
        req.message = 'success'
        return
    });
}

function createToken(req, res) {
    var name = req.body.name;

    var token = jwt.sign({ name: name }, secret, {
        expiresIn: 300 // expires in 5 min
    });

    req.token = token
}

module.exports = { verifyToken, createToken };

-----------------------------------
//index.ejs
<html>

<head>
  <%- include('partials/header'); %>
</head>

<body>
  <div style="margin:100px;">
    <%- include('partials/nav'); %>

      <div class="jumbotron" style="padding:40px;">

        <form action="\" method="get" id='logoutForm'>
          <div id='loginName'></div>
          <input type="submit" value="log out" onclick="localStorage.removeItem('token');
            localStorage.removeItem('user');" />
        </form>

        <form method="post" onsubmit="getProfile(event)" id='profileForm'>
          <input type="hidden" id='tokenInput' name='tokenInput'>
          <input type="submit" value="view profile" />
        </form>

        <form action="\" method="post" id='loginForm'>
          <table>
            <tr>
              <td><label>Name</label></td>
              <td><input type="text" name="name" /></td>
            </tr>
            <tr>
              <td><label>Password</label></td>
              <td><input type="password" name="password" /></td>
            </tr>
          </table><br />
          <input type="submit" value="log in" />
        </form>

        <% if (locals.data) { %>
          <% if (data.length==0) {%>
            <div>login failed</div>
            <% }else{ %>
              <script>
                var token = '<%= token %>';
                var user = '<%= data[0].name %>'
                var id = '<%= data[0].id %>'
                localStorage.setItem('token', token);
                localStorage.setItem('user', user)
                localStorage.setItem('id', id)
              </script>
              <% } %>
                <% } %>

                  <script>
                    var token = localStorage.getItem('token');
                    if (token) {
                      document.getElementById('loginForm').style.display = 'none';
                      document.getElementById('logoutForm').style.display = 'block';
                      document.getElementById('profileForm').style.display = 'block';
                      document.getElementById('loginName').innerHTML = 'welcome ' + localStorage.getItem('user');
                    }
                    else {
                      document.getElementById('loginForm').style.display = 'block';
                      document.getElementById('logoutForm').style.display = 'none';
                      document.getElementById('profileForm').style.display = 'none';
                    }

                    function getProfile(e) {
                      var id = localStorage.getItem('id');
                      var url = 'http://localhost:8080/profile/' + id;
                      document.getElementById('profileForm').action = url;
                      document.getElementById('tokenInput').value = token;
                    }
                  </script>

      </div>
  </div>
</body>

</html>
---------------------------
//profile.ejs
<html>

<head>
    <%- include('partials/header'); %>
</head>

<body>
    <div style="margin:100px;">
        <%- include('partials/nav'); %>

            <div class="jumbotron" style="padding:40px;">
                <h3>profile</h3>
                <% if (locals.message) { %>
                    message: <%= message %>
                        <% } %>
                            <% if (locals.data) { %>
                                <ul>
                                    <li>id: <%= data.id %>
                                    </li>
                                    <li>name: <%= data.name %>
                                    </li>
                                    <li>password: <%= data.password %>
                                    </li>
                                </ul>
                                <% } %>

                                    <form action="\" method="get">
                                        <input type="submit" value="home" />
                                    </form>
            </div>
    </div>
</body>

</html>

reference:

No comments:

Post a Comment