Chapter 5. Misplaced Trust in the Client

Misplaced trust in the client by itself is a very general and broad topic. However, believe it or not, we already covered some aspects of this topic in the previous chapters.

Misplaced trust in the client generally means that if we, as developers, are overly trusting, especially in terms of how our JavaScript will run in the client or if there is any input from the users, we might just set ourselves up for security flaws.

In short, we cannot simply assume that the JavaScript code will run as intended.

When trust gets misplaced

In general, while we try our best to write secure JavaScript code, we must recognize that the JavaScript code that we write will eventually be sent to a browser. With the existence of XSS/CSRF, code on the browser can be manipulated fairly easily, as you saw in the previous chapter.

We will start off with a simple application, where we attempt to create a user, similar to many of the apps we are familiar with, albeit a more simplified one.

We will walk through the creation of the app, use it, and then utilize it again under modified circumstances where the trust actually gets misplaced.

A simple example

This example is based on Tornado/Python. You can easily recreate this example using Express.js/Node.js. The important things to note here are the issues happening on the client side.

What we are going to code in this section is a simple user creation form, which sends the values to the backend/server side. On the client side, we are going to use JavaScript to prevent users from creating usernames with the a character and passwords containing the s character.

This is typical of many forms we see: we may want to prevent the user from creating input using certain characters.

As usual, if the user's input satisfies our requirements, our JavaScript code will enable the Submit button, enabling the user to create a new user.

With that in mind, let's start coding. To start off, create the following directory structure:

mistrust/
   templates/
          mistrust.html
   mistrust.py

Building the server side – mistrust.py

Since this example is based on Tornado/Python and it has only one functionality (that of creating a user), this is a fairly straightforward piece of code. Open your editor and name a new file mistrust.py. The code is as follows:

import os.path
import re
import torndb
import tornado.auth
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web
import unicodedata
import json

from tornado.options import define, options

define("port", default=8000, help="run on the given port", type=int)

class Application(tornado.web.Application):
    def __init__(self):
        handlers = [
            (r"/", FormHandler)
        ]
        settings = dict(
            blog_title=u"Mistrust",
            template_path=os.path.join(os.path.dirname(__file__), "templates"),
            xsrf_cookies=False,
            debug=True
        )
        tornado.web.Application.__init__(self, handlers, **settings)

class FormHandler(tornado.web.RequestHandler):
    def get(self):
        self.render("mistrust.html")

    def post(self):
        print self.get_argument('username')
        print self.get_argument('password')
        data = {
            'success':True
        }
        self.write(data)

def main():
    tornado.options.parse_command_line()
    http_server = tornado.httpserver.HTTPServer(Application())
    http_server.listen(options.port)
    tornado.ioloop.IOLoop.instance().start()

if __name__ == "__main__":
    main()

Basically, we have only one handler, FormHandler, which shows the form when we hit the / URL. The POST function simply receives the username and password. Presumably, we can save this information for our new user.

The templates

Next, let's work on the client-side code. Create a new file in the templates/ folder and name it mistrust.html. As usual, we start with a basic Bootstrap 3 template, which is as follows:

<!DOCTYPE html>
<html lang="en">
  <head>

    <title>Mistrust Example</title>

    <!-- Bootstrap core CSS -->
    <link href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet">
    <style>
    #username-error, #password-error {
      color:red;
    }
    #success-msg, #fail-msg {
      display:none;
    }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <ul class="nav nav-pills pull-right">
          <li class="active"><a href="#">Home</a></li>
          <li><a href="#">About</a></li>
          <li><a href="#">Contact</a></li>
        </ul>
        <h3 class="text-muted">Mistrust Example</h3>
      </div>
      <div class="jumbotron">
        <h1>Create User</h1>
        <div id="success-msg" class="alert alert-success" role="alert">Success</div>
        <div id="fail-msg" class="alert alert-danger" role="alert">Oops, something went wrong</div>
        <div role="form">
          <div class="form-group">
            <label for="username">User Name </label><span id="username-error"></span>
            <input type="text" class="form-control" id="username">
          </div>
          <div class="form-group">
            <label for="password">Password </label><span id="password-error"></span>
            <input type="password" class="form-control" id="password">
          </div>
          <button id="send" type="submit" class="btn btn-success" disabled>Submit</button>
        </div>
      </div>
      <div class="footer">
        <p>&copy; Company 2014</p>
      </div>
    </div> <!-- /container -->
    <!-- Bootstrap core JavaScript
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
  </body>
</html>

There is nothing special about this piece of code. It is simply a HTML template showing a form.

Next, insert the following JavaScript code beneath <script src="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>:

    <script>
    var okUsername = null;
    var okPassword = null;
    function checkUserNameValues() {
      
      var values = $('#username').val();
     if (values.indexOf("s") < 0) {
        okUsername = true;
        $('#username-error').html("");

      }
      else {
        okUsername = false;
        $('#username-error').html("Not allowed to use character 's' in your password");

      }

      
     if (okUsername === true && okPassword === true) {
        $('#send').prop('disabled', false);
      }

    }

    function checkPasswordValues() {
      var values = $('#password').val();
      
      if (values.indexOf("a") < 0) {
        okPassword = true;
        $('#password-error').html("");

      }
      else {
        okPassword = false;
        $('#password-error').html("Not allowed to use character 'a' in your password");

      }
      
     if (okUsername === true && okPassword === true) {
        $('#send').prop('disabled', false);
      }
    }

    function formEnter() {
      var a = $('#username').keyup(checkUserNameValues);
      var b = $('#password').keyup(checkPasswordValues);
    }

    // here will do the form post and simple validation
    function submitForm() {
      // here I will check for "wrong" stuff
      if (ok_username === true && ok_password === true) {
        // go ahead and post to ajax backend
        var username = $("#username").val();
        var password = $("#password").val()
        var request = $.ajax({
          url: "/",
          type: "POST",
          data: { username : username, password:password },
          dataType: "json"
        });
         
        request.done(function( response ) {
          if(response.success == true) {
            $( "#success-msg" ).show();  
          }
          else {
            $("#fail-msg").show();
          }
          
        });
         
        request.fail(function( jqXHR, textStatus ) {
          $("#fail-msg").show();
        });

      }
      else {
        alert("Please check your error messages");
      }

      // enables or disables the button
      return;
    }
    $('document').ready(function() {
      // so here I will do the form posting.
      formEnter();
      $("#send").click(submitForm);
    })
    </script>

We have four major functions in this piece of JavaScript code, which are discussed as follows:

  • checkUserNameValues(): This function checks whether the username is valid or not. For our purposes, it must not contain the s character. If it does, we will show an error message at the #username-error element.
  • checkPasswordValues(): This function checks whether the password is valid or not. In this case, it is checking whether the password contains the s character or not. If it does, it will show an error message in #password-error.
  • formEnter(): This function simply calls checkUserNameValues() and checkPasswordValues() whenever there is a keyup event when the user is in the process of entering their username or password.
  • submitForm(): This function submits the form if the user input adheres to our rules, or it returns a fail message at the #fail-msg element.

Now that we have coded the app, save everything and change directory to the root of the application. Issue the following command:

python mistrust.py

There is no need to use any database for this app. After you have issued this command, go to http://localhost:8000; you should see the following output:

The templates

The Create User interface

Now you can test the app. Enter your username and password. If you have entered something illegal, this is what you will see:

The templates

Error messages shown if input contains illegal characters

Note the error messages beside the User Name and Password fields.

On the other hand, should you enter the credentials correctly, you will receive a successful message, as shown in the following screenshot:

The templates

Successful creation

To trust or not to trust

Now that we have made sure our code is working correctly, it's time to manipulate the code to show that we, as developers, should never trust the client.

Manipulating the JavaScript code

You need to perform the following steps to manipulate the JavaScript code:

  1. Refresh your app, and assuming that you are using Google Chrome, right-click and open the developer tools by selecting Inspect Element, as shown in the following screenshot:
    Manipulating the JavaScript code

    Right-click and select Inspect Element

  2. Next, you should see the developer tools at the bottom of your browser window or the developer tool in a pop-up window. Both will work in our example.
  3. Now, go to Elements, as shown in the following screenshot:
    Manipulating the JavaScript code

    The developer tool interface

  4. Now, click on Body and find the disabled button. Click on the disabled text and delete it.
  5. Next, enter asd and asd for both your username and password, both of which are illegal under our rules. Going back to your developer tool, head straight to console, and type the following:
    ok_password = true
    ok_username = true
  6. Finally, you should see that your form, although still showing the error messages, allows you to submit the form since the button is now enabled. Click on Submit.

    Presto! It succeeds!

    Manipulating the JavaScript code

    An oxymoron—we have error messages, yet the submission is successful

In my server, I receive both values: asd and asd, as shown in the following screenshot:

Manipulating the JavaScript code

Even our backend receives a successful POST request

Weird isn't it?

Actually, it is not. Remember that the JavaScript code we write is sent to the client side, which means that it is free for all (malicious developers?) to manipulate. Look how much harm my simple technique can possibly cause: simply using Google's developer tools, I side-stepped the basic requirements of not using the s character and the a character for my username and password respectively.

Dealing with mistrust

For our particular example, we could have done something to prevent this from happening. And that is to include server-side checking as well. Now, feel free to check the code in mistrust2.py, and look for FormHandler. The post() function has now been changed, as follows:

class FormHandler(tornado.web.RequestHandler):
    def get(self):
        self.render("mistrust.html")

    def post(self):
        username = self.get_argument('username')
        password =  self.get_argument('password')
        # this time round we simply assume false
        data = {
            'success':False
        }
        if 's' in username:
            self.write(data)
        elif 'a' in password:
            self.write(data)
        else:
            data = {
                'success':True
            }
            self.write(data)

We simply look for illegal characters when accepting the username and password. Should they contain any illegal characters, we simply return a failed message.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.12.163.175