AJAX Crash Course for WebApp Security

Introduction

AJAX stands for Asynchronous JavaScript and XML. By using Ajax, a web application can send and retrieve data from a server asynchronously (in the background) without interfering with the display and behaviour of the existing page. It basically allows a web page to change content dynamically without the need to reload the entire page.

Ajax is basically combination of built-in XMLHttpRequest browser object and HTML DOM with JavaScript. Ajax uses XMLHttpRequest to send request to the server, then server returns a response, which is processed by javascript and according to response front-end webpage gets modified by manipulating html DOM.

Steps to Send AJAX query :

  1. An event occurs in a web page.
  2. An XMLHttpRequest object is created.
  3. The XMLHttpRequest object sends a request to a web server.
  4. The server processes the request.
  5. The server sends a response back to the web page
  6. The response is processed with javascript and according to that, the page is updated by manipulating HTML DOM.

Note : At here one thing to point out that Ajax is not a new technology, or different language, its just existing technologies used in new ways.

XMLHTTPRequest

XMLHttpRequest is a JavaScript object that performs asynchronous interaction with the server and used to exchange data with a web server behind the scenes. All modern browsers (Chrome, Firefox, IE7+, Edge, Safari, Opera) have a built-in XMLHttpRequest object.

XMLHttpRequest Methods :

  • new XMLHttpRequest() : Creates a new XMLHttpRequest object.
var Req = new XMLHttpRequest();
  • open(method, url, async) : Specifies the request. where method denotes the request type (GET/POST), url is location of file or data, async denotes the behaviour or request true (asynchronous) or false (synchronous). There is also two optional parameters user optional user name and pwd optional password.
Req.open("GET", "http://mysite.com/data.txt", true);
  • send() : Sends GET request to the server.
Req.send(); 
  • send(string) : Sends POST request to the server.
Req.open("POST", "http://mysite.com/userinfo.php", true);  
Req.send("fname=John&lname=snow");  
  • setRequestHeader() : Adds a label/value pair to the header to be sent.
Req.open("POST", "http://mysite.com/userinfo.php", true);  
Req.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); 
Req.send("fname=John&lname=snow");  
  • getResponseHeader() : Returns specific header information.
Req.getResponseHeader('Last-Modified');
  • getAllResponseHeaders() : Returns header information.
Req.getAllResponseHeaders();
  • abort() : Cancels the current request.
Req.abort();

XMLHttpRequest Properties

  • onreadystatechange : Defines a function to be called when the readyState property changes.
  • readyState : Holds the status of the XMLHttpRequest. Where 0 means request not initialized, 1 means server connection established, 2 :request received, 3 :processing request, 4 :request finished and response is ready.
  • status : Returns the status-number of a request, 200 (OK), 301 (Moved Permanently), 401 (Unauthorized), 404 (Not Found) etc. You can find the full list here HTTP status codes.
  • statusText : Returns the status-text (e.g. “OK” or “Not Found”).
  • responseText : Returns the response data as a string.
  • responseXML : Returns the response data as XML data.

Making Request to Server

Step 1 : Create XMLHttpRequest object.

var req = new XMLHttpRequest();  

Step 2 : Defining an Event handling function with onreadystatechange property, which will be called everytime when the readyState property changes.

req.onreadystatechange = function() {
    if(this.readyState == 4 && this.status == 200) {
        var ResponseData = this.responseText;
       // statement  to be execute  
    }
}

When the req.readyState is 4 and req.status is 200, then we know that the response is ready to be processed. The Response Data from server can be fetched from req.responseText.

Step 3 : Define the connection parameter by using open() method. This method does not send the request to the webserver but saves its arguments for sending the request later.

req.open(GET, "data.txt", true);

The supported methods are POST, GET, HEADER, PUT, DELETE.

Step 4 : Preparing Data Parameters for Submission. However this is optional and not necessary. Some examples are :

// simple data  
var paramData = "Param1=Value1&Param2=Value2"  

// In json format for Post request
var paramData = encodeURIComponent(JSON.stringify({'param1':'value1', 'param2':'value2'}));  

// In json format for Get request
var paramData = JSON.stringify({'param1':'value1', 'param2':'value2'});  

Step 5 : Submitting Request to the server :

req.send();

If there are some parameters to be submitted then :

req.send(paramData);  

Now a simple AJAX request will look like this :

var req = new XMLHttpRequest();  

req.onreadystatechange = function() {
    if(this.readyState == 4 && this.status == 200) {
        var ResponseData = this.responseText;
       // statement  to be execute  
    }
}

req.open(GET, "data.txt", true);
req.send();

Setting-up test lab

Use a web server like apache to host a file and page index.html. You can also use php, python one liner server for this.

// for php  
php -S localhost:8080  

// for python2
python -m SimpleHTTPServer 8080

// for python3 
python3 -m http.server 8080 

Code for accessing data.txt on server by using AJAX.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WebPage</title>
</head>
<body>
    <p id="demo"></p>

<script>
    var req = new XMLHttpRequest();

    req.onreadystatechange = function() {
        if(this.readyState == 4 && this.status == 200) {
            var responseData = this.responseText;
            document.getElementById("demo").innerText = responseData;
        }
    }

    req.open("GET", "data.txt", true);
    req.send();
</script>

</body>
</html>

Output :

Get and Post Request to the Server

  • GET AJAX Request :

File: server.php

<?php

    if($_SERVER["REQUEST_METHOD"] == "GET") {
        $name = $_GET['name'];
        $age = $_GET['age'];
        echo "Hello $name. <br/>";
        echo "You are $age years old."; 
    } elseif($_SERVER["REQUEST_METHOD"] == "POST") {
        $name = $_POST['name'];
        $age = $_POST['age'];
        echo "Hello $name. <br/>";
        echo "You are $age years old.";
    }

?>

File: index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WebPage</title>
</head>
<body>
    <p id="demo"></p>

<script>

    var req = new XMLHttpRequest();  

    req.onreadystatechange = function() {
        if(this.readyState == 4 && this.status == 200) {
            var responseData = this.responseText;
            document.getElementById("demo").innerHTML = responseData;        
        }
    }

    var paramData = "name=ajay&age=25";
    var url = "server.php?" + paramData;
    req.open("GET", url, true);
    req.send(); 

</script>

</body>
</html>

Output :

Hello ajay.
You are 25 years old.
  • Post Ajax Request :

File: index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WebPage</title>
</head>
<body>
    <p id="demo"></p>

<script>

    var req = new XMLHttpRequest();  

    req.onreadystatechange = function() {
        if(this.readyState == 4 && this.status == 200) {
            var responseData = this.responseText;
            document.getElementById("demo").innerHTML = responseData;        
        }
    }

    var paramData = "name=ajay&age=25";
    req.open("POST", "server.php", true);
    req.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
    req.send(paramData); 

</script>

</body>
</html>

Output:

Hello ajay.
You are 25 years old.

Using a Callback Function

A callback function is a function passed as a parameter to another function. If your web-application make more then one AJAX request, then it is good practice to create one function to execute XMLHttpRequest object, and one callback function for each AJAX task.

loadDoc("server.php", "name=ajay&age=25", myFunc1);
loadDoc("server.php", "name=john&age=30", myFunc2);
loadDoc("server.php", "name=Bruce&age=40", myFunc3);

function loadDoc(url, param, callBackFunc) {
    var req = new XMLHttpRequest();
    req.onreadystatechange = function() {
        if(this.readyState == 4 && this.status == 200) {
            callBackFunc(this);
        }
    }

    var Fullurl = url + "?" + param;
    req.open("GET", Fullurl, true);
    req.send();
}

// callback functions  
function myFunc1(req) {
    document.getElementById("demo1").innerHTML = req.responseText;
}

function myFunc2(req) {
    document.getElementById("demo2").innerHTML = req.responseText;
}

function myFunc3(req) {
    document.getElementById("demo3").innerHTML = req.responseText;
}

Test Example :  

File: server.php  

<?php

    if($_SERVER["REQUEST_METHOD"] == "GET") {
        $name = $_GET['name'];
        $age = $_GET['age'];
        echo "Hello $name. <br/>";
        echo "You are $age years old."; 
    }

?>

File: index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WebPage</title>
</head>
<body>
    <p id="demo1"></p>
    <p id="demo2"></p>
    <p id="demo3"></p>

<script>

loadDoc("server.php", "name=ajay&age=25", myFunc1);
loadDoc("server.php", "name=john&age=30", myFunc2);
loadDoc("server.php", "name=Bruce&age=40", myFunc3);

function loadDoc(url, param, callBackFunc) {
    var req = new XMLHttpRequest();
    req.onreadystatechange = function() {
        if(this.readyState == 4 && this.status == 200) {
            callBackFunc(this);
        }
    }

    var Fullurl = url + "?" + param;
    req.open("GET", Fullurl, true);
    req.send();
}

function myFunc1(req) {
    document.getElementById("demo1").innerHTML = req.responseText;
}

function myFunc2(req) {
    document.getElementById("demo2").innerHTML = req.responseText;
}

function myFunc3(req) {
    document.getElementById("demo3").innerHTML = req.responseText;
}

</script>

</body>
</html>

Output :

Access Across Domains

For security reasons, modern browsers do not allow access across domains. For example if the data.txt file is hosted on the other domain then we can not access it. For more information about this read SOP and CORS.

Fetching Data from API using AJAX

The below github api returns user repositories list

https://api.github.com/users/USERNAME/repos

Here is the implementation of above api using AJAX

<!DOCTYPE html>
<html>
    <head>
        <title>Test</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <script>
            function myFunction() {
                var req = new XMLHttpRequest();  
                var UserName = document.getElementById("Uname").value;
                req.onreadystatechange = function() {
                    if(this.readyState == 4 && this.status == 200) {
                        var VAL=JSON.parse(this.responseText);
                        var data = "<ul>";    
                        for (i=0;i<VAL.length;i++) {
                            data+= "<li><a href='"+VAL[i]['svn_url']+"' target='_'>"+VAL[i]['name']+"</a></li>"
                        }
                        data+="</ul>"
                        document.getElementById("data").innerHTML = data;
                    } else {
                    console.log("Error: User Not Found");
                    }
                }

                req.open("GET", "https://api.github.com/users/"+UserName+"/repos", true);
                req.send();
            }
        </script>
    </head>
    <body>
        Enter github UserName: <input type="text" id="Uname" onkeyup="myFunction()">
        <p id="data"></p>    
    </body>
</html>

Output :

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.