Software developers need to keep a lot of information in their heads. There are many questions to ask when it comes to building a website or app: What technologies to use? How will the structure be set up? What functionality do we need? What will the user interface look like? Particularly in the software market, where app production is more of a reputation race than a well-thought-out process, one of the most important questions that often ends up at the bottom of the “Important List” is: How will our product be protected?
If you’re using a robust, open framework to build your product (and if it’s available and usable, why not?), then basic security issues like CSFR attacks and password encryption may already be solved for you.
However, fast-paced developers will benefit from brushing up on their knowledge of common threats in order to avoid rookie mistakes. Usually the weakest point in the security of your software is you.
Who can hack? There is an ethical hacker – this is someone who looks for possible weaknesses in security and privately tells them to the creators of the project.
And a black hat hacker, also called “Cracker” is someone who uses these weaknesses for extortion or their own benefit.
These two kinds of hackers can use the same set of tools and generally try to get into places where the average user can’t. But white hat hackers do it with permission, and in the interest of strengthening protection, not destroying it. Black hackers are the bad guys.
Here are some examples of the most common attacks that exploit security weaknesses: SQL injection and XXS cross-site scripting.
SQL ATTACKS
SQL injection (SQLi) is a type of injection attack that allows you to execute malicious SQL commands to retrieve data or crash an application. Essentially, attackers can send SQL commands that affect your application through some input on your site, such as a search field that retrieves results from your database. PHP-encoded sites can be particularly susceptible to them, and a successful SQL attack can be devastating to software that relies on a database (for example, your user table is now empty space).
You can test your own site to see how susceptible it is to this kind of attack. (Please only test sites you own, as running SQL codes where you don’t have permission to do so may be illegal in your area; and definitely not very funny.) The following payloads can be used for testing :
' OR 1='1evaluates to a constant true, and on success returns all rows in the table' AND 0='1evaluates to constant false and returns no rows if successful.
Fortunately, there are ways to mitigate SQL code attacks, and they all boil down to one basic concept: don’t trust user input .
MITIGATION OF THE CONSEQUENCES OF SQL CODES.
To effectively deter attacks, developers must prevent users from successfully sending raw SQL commands to any part of the site.
Some frameworks will do most of the hard work for you. For example, Django implements the concept of object-relational mapping, or ORM using querysets. We’ll treat them as wrapper functions that help your application query the database using predefined methods, avoiding the use of raw SQL.
However, being able to use a framework is never a guarantee. When we’re dealing directly with a database, there are other methods we can use to safely abstract our SQL queries from user input, although they vary in efficiency. They are listed in order from most important to least important:
- Prepared statements with variable binding (or parameterized queries)
- Stored procedures
- Whitelisting or escaping user input
If you want to implement the above methods, then these cheat sheets are a great starting point for learning more. Suffice it to say that using these methods to get data instead of using raw SQL queries helps to minimize the chance that SQL will be processed by any part of your application that accepts input from users, thereby mitigating SQL code attacks.
CROSS-SITE SCRIPTING ATTACKS (XSS)
If you’re a hacker, then JavaScript is pretty much your best friend. The right commands will do everything a regular user can do (and even some things they shouldn’t) on a web page, sometimes without any interaction from the real user.
Cross-site scripting attacks, or XSS , occur when JavaScript code is injected into a web page and changes its behavior. Its consequences can range from the appearance of unpleasant jokes to more serious authentication bypasses or credential theft.
XSS can occur on the server or on the client side and typically comes in three flavors: DOM (Document Object Model) based on stored and displayed XSS. The differences come down to where the attack payload is injected into the application.
DOM BASED XSS
DOM-based XSS occurs when a JavaScript payload affects the structure, behavior, or content of a web page that a user has loaded in their browser. They are most often performed via modified URLs, such as in phishing emails.
To see how easy it would be for injected JavaScript to manipulate the page, we can create a working example with an HTML web page. Try creating a file on your local system called xss-test.html(or whatever) with the following HTML and JavaScript code:
<html>
<head>
<title>My XSS Example</title>
</head>
<body>
<h1 id="greeting">Hello there!</h1>
<script>
var name = new URLSearchParams(document.location.search).get('name');
if (name !== 'null') {
document.getElementById('greeting').innerHTML = 'Hello ' + name + '!';
}
</script>
</h1>
</html>
This web page will display a title "Hello!”unless it receives a URL parameter from a query string with a value of name. To see the script in action, open the page in a browser with the added URL parameter, for example:
file:///path/to/file/xss-test.html?name=Victoria
Our insecure page takes the value of a URL parameter for a name and renders it in the DOM. The page expects the value to be a nice friendly string, but what if we change it to something else? Since the page belongs to us and exists only on our local system, we can test it as much as we want. What happens if we change the parameter name, say, to:
<img+src+onerror=alert("pwned")>
This is just one example that demonstrates how an XSS attack can be performed. Funny pop-up alerts can be fun, but JavaScript can do a lot of harm, including helping attackers steal passwords and personal information.
STORED AND REFLECTED XSS
Stored XSS occurs when an attack payload is stored on a server, such as a database. The attack affects the victim whenever this stored data is retrieved and displayed in the browser.
For example, instead of using a URL query string, an attacker could update their profile page on a social site to inject a hidden script into, say, the “About me” section. A script not stored correctly on the site server will run successfully as long as another user is viewing the attacker’s profile.
One of the most notorious examples of this is the Samy worm that nearly took over MySpace in 2005. It spread by sending HTTP requests that copied it to the victim’s profile page whenever the infected profile was viewed. In just 20 hours, it has spread to over a million users.
Reflected XSS similarly occurs when the input is moved to the server, but the malicious code is not stored in the database. Instead, it is immediately returned to the browser by the web application.
Such an attack can be carried out by luring the victim into a malicious link that sends a request to the server of the vulnerable website. The server will then send a response to the attacker as well as the victim, which may result in the attacker being able to obtain passwords or perform actions that supposedly come from the victim.
RELAXING XSS
In all of these cases, XSS can be contained through two key strategies: validating form fields and preventing direct user input on the web page.
VALIDATING FORM FIELDS
Frameworks can again help us when it comes to making sure user submitted forms are up to date. One example is Django’s built-in field classes, which provide fields that validate some commonly used types, as well as set normal default values.
For example, Django’s email field uses a set of rules to determine if the provided input is a valid email. If the submitted string contains characters that are not normally found in email addresses, or if it does not mimic the general format of an email address, then Django will not consider this field valid and the form will not be submitted.
If you can’t rely on a framework, you can implement your own input validation. This can be done using several different methods, including type conversion, such as ensuring that a number is of type int(); checking the minimum and maximum range values for numbers and string lengths; use of a predefined array of options that avoids arbitrary input, such as months of the year; and checking the data against strict regular formulations.
Luckily, we don’t have to start from scratch. Available open source resources will help, such as the validation of the OWASP regular expression repository, which provides patterns for matching against some common data forms. Many programming languages offer validation libraries specific to their syntax, and we can find many such libraries on GitHub.
Although it may seem tedious, correctly implemented input validation can protect our application from XSS susceptibility.
PREVENTING DIRECT DATA ENTRY
Elements of an application that directly return user input to the browser may not be obvious during normal inspection. We can identify application areas that may be at risk by looking at a few questions:
- How is the data flow through the application?
- What does the user expect when they interact with these inputs?
- Where does the data appear on our page? Do they become inline in a string or an attribute?
Here are some sample payloads we can play with to validate inputs on our site (again, only on our own site!). Successful execution of any of these samples may indicate a possible XSS vulnerability due to direct input.
"><h1>test</h1>'+alert(1)+'"onmouserover="alert(1)http://"onmouseover="alert(1)
As a general rule, if you can bypass direct data entry, do so. Also, make sure you fully understand the effectiveness of the methods you choose; for example, using innerText instead of innerHTML in JavaScript ensures that the content is set to plain text instead of (potentially vulnerable) HTML.
BE CAREFUL WITH INPUT!
Software developers are clearly at a disadvantage when it comes to competing with black hat hackers. Despite all the work we’ve done to protect every input that could potentially compromise our application, an attacker only needs to find the one we missed. It’s like putting bolts on all the doors, but leaving the window open!
However, by learning to think in the same vein as the attacker, we can better prepare our software to counter the bad guys. As exciting as it is to add features as quickly as possible, we will avoid a lot of cybersecurity debt if we pre-think our application flow, follow the data, and pay attention to our inputs.
