Web applications are everywhere today, and they are used to control just about everything you can imagine. In this section we will look into web application attacks and security.
IDOR vulnerabilities happen when developers have not implemented authorization requirements to access resources.
Eve, by simply changing an identifier, e.g. the document Rest parameter, she can access Alice's documents.
This happens when the web application does not enforce authorization between objects, allowing attackers to enumerate values and test access to other points of data.
For example we might have the following pseudo-code showing no signs of authorization:
$id = getInputFromUser();
$doc = getDocument($id);
return $doc;
The code above asks for input from user, performs no validation or sanitization, then performs a lookup with the getDocument function directly and returns the document in question.
A better implementation would be to check the privileges:
$id = getInputFromUser();
$user = findUsername();
$doc = "";
if (hasAccessToDocument($user, $id)) {
$doc = getDocument($id);
} else {
$doc = "Not authorized for this document";
}
return $doc;
Vulnerabilities like these are easy to find as you can simply change a simple number and see if you get access to someone else's data. Checking if the user is authorized first prevents this vulnerability.
An application want to avoid using sequences of numbers when referencing data. In the IDOR example, the documents had identifiers from 1000 to 1002. Sometimes these numbers are called "Magic Numbers" as they directly point to a resource on the server, e.g. via database, and all values can easily be enumerated. For example an attacker can check all document identifiers from 0 all the way to 10000 and record any results which provides access to data.
While authorization should be properly implemented, it is also helpful to use GUID ("Globally Unique Identifier") or UUID ("Universally Unique Identifier") when referencing data. These identifiers are designed to be globally unique and impossible to enumerate because of the built-in entropy of the generation of the numbers.
This is what a GUID can look like:
Many web applications are connected to a database. The database holds all the information the web application wish to store and use.
SQL Injection is a technique which allows attackers to manipulate the SQL ("Structured Query Language") the developer of the web application is using. This typically happens because of lack of data sanitization. SQL is used regularly by developers to access database resources.
In the request Eve makes in the graphic above, we see she inputs the value: 1000' OR '1'='1
This causes the resulting SQL Query to return all rows of the table because the database evaluates the statement as always true. Think about it: the database receives a request where the value can be either 1000 OR 1 is equal to 1; it will return a value every time! There are many different SQL functions and operations we can use to manipulate the syntax, and this example is just one of very many.
Below is a pseudo-code example which contains a SQL Injection vulnerability.
$username = getUserName();
$pw = getPassword();
$user = mysql_query("SELECT * FROM userTable WHERE username = $username AND password = $pw");
if ($user) {
$loggedIn = True;
} else {
$loggedIn = False;
}
For an attacker to exploit this, they could simply craft a URL against the target domain with the attack in it like this:
/login?username=admin&password=password' OR '1'='1
The password variable is set to contain the SQL characters, causing the resulting SQL string to return a row, even if the password is unknown to us. The resulting SQL query would be:
SELECT * FROM userTable WHERE username = 'admin' AND password = 'password' OR '1'='1'
Parameterized queries is the recommended solution to defeat SQL Injections. Within a parameterized query, the developers carefully ensure each input to the query is defined as a specific value and type. Here is an example from the above code which is considered a secure implementation:
$username = getUserName();
$pw = getPassword();
$parameterizedQuery = prepare_query("SELECT * FROM userTable where username = ? and password = ?");
$parameterizedQuery.setString(1, $username)
$parameterizedQuery.setString(2, $password)
$user = parameterizedQuery.execute();
if ($user) {
$loggedIn = True;
} else {
$loggedIn = False;
}
In the above example, the developer has carefully said that parameter 1 should be a string and contain the username, and the password in the second parameter.
XSS uses the server to attack visitors of the server. The attack does not target the server itself, but instead the users.
The server is simply used to reflect attackers values, typically JavaScript, against visitors who then run the attackers data in their own browser. The attacker has to craft an input which the server does not clean and sanitize, that way when a visitor clicks a link containing the attackers values, or visits a resource on the webpage which the attacker has used in their attack, the user runs code which the attacker supplied.
Here is a graphical example of Eve sending a link to Alice which contains the XSS attack:
This attack is called a Reflected XSS and involves Eve finding the vulnerability, then sending a link containing the attack to an unsuspecting user and having them click the link. The link contains the attack and makes the webserver return the attack to the victim clicking the link.
The code behind this could be something simple as this pseudo-code example:
$nickname = etNickName();
echo "Greeting $nickname, nice to meet you!";
Another kind of XSS is called a Stored XSS attack. In Stored XSS attacks the attacker is capable of saving content on the webpage which is reflected every time someone visits the website. It does not require someone to click a link necessarily.
This graphic describes how Eve is able to store malicious JavaScript to be executed in anyone's browser when the visit the resource:
XSS attacks can accomplish many things, for example:
To defend against XSS there are several best-practices to follow:
HTML encoding allows the web application to return typically unsafe characters in a safe manner. For example the following special characters can be encoded into their respective counterpart:
Special Character | HTML Entity |
---|---|
< | < |
> | > |
" | " |
& | & |
' | ' |
This produces output which can be displayed safely. We can then use the JavaScript on the client-side to safely turn the HTML entities into values.
The webserver can control what kind of JavaScript is allowed to run on the website. This does not remove vulnerabilities but adds defense in depth for when there is an unknown vulnerability.
A common and strict CSP is to provide the users of the web-application with a list of all accepted JavaScript source files.
In addition, it is typical for CSP to prevent execution of in-line JavaScript.
To allow for easier implementation and detection of on-going attacks, CSP allows for clients to report CSP violations to a URL provided by the server
There are many web application scanners out there. These allow for applications to be scanned for vulnerabilities such as SQL Injection and XSS. Contrary to a network vulnerability scanner, a web-application scanner is typically built on heuristics instead of signatures and lists of known vulnerabilities.
Web application scanners are useful, especially when built into development processes such as CI ("Continuous Integration") and CD ("Continuous Delivery")