Let’s do some math. There are currently over 1 billion websites in the world, 380 million of which are in the United States [Source]. According to a report by Acunetix, 46% of all websites have critical vulnerabilities. This equates to 460,000,000 websites that have critical vulnerabilities.
Web applications have become the number one target for exploitation. The fundamentals of web security are not always followed, putting customer data at risk.
That’s why Engine Room Technology is putting together a special series of posts outlining how to secure a website. From top to bottom, from networking to code, we’ll discuss all of the important pieces of building a secure website.
We don’t want to see your site counted among the 46%. First up, we’ll discuss common attacks against websites so you know what to defend against.
Common Attacks Against Websites
There seems to be a new attack every week (such is life in the cybersecurity field). But these are the common ones you need to protect against. View these as table stakes for having a site on the Internet today.
Cross-site scripting (XSS) is a popular injection attack against a web page or web application. The attacker aims to execute malicious code in the victim's web browser by injecting it into a legitimate web page. The actual attack occurs when the victim loads the tainted web page and the browser is forced to execute the malicious code.
XSS attacks are serious and can be used to take over accounts, steal data, plant trojans, deface website content and engage in keylogging and phishing.
A web page is vulnerable to XSS if it uses unsanitized user input in the output that it generates, therefore allowing a user's malicious input to be parsed by the victim’s browser. Vulnerable vehicles commonly targeted by XSS attacks are web pages that allow user comments, community forums and message boards.
There are three main types of XSS attacks:
- Reflected XSS
- Stored XSS
- DOM-based XSS
Reflected XSS transmits the payload to the server. The server then sends the data back to the browser in an HTML document and the code is executed. Stored XSS is similar with the only difference being that the payload is saved somewhere on the server, such as in a comment on a blog post.
DOM-based XSS occurs by injecting the code at runtime directly into the browser without submitting anything to the server.
Here are the ways you can protect yourself from XSS:
- Sanitize your input: never output any data received as user input directly to the browser, without first checking it for malicious code
- If available in your programming language, use an anti-XSS encoding library to properly encode untrusted data in the right context
- Validate your input: use whitelisting to only allow the input of only known good characters (instead of finding and eliminating bad ones)
OWASP has a great guide on the rules you should follow to prevent XSS in your apps.
Cross-site Request Forgery (CSRF) occurs when an attacker tricks a user’s browser into sending a request to perform an unwanted action on a trusted site while the user is authenticated.
For example, an image or iframe on a web page may have its “src” attribute set to the URL of the user’s bank account. The image is invisible so the user has no idea, but the request transfers money from the user’s bank account to the attacker’s bank account. In this instance, the bank website has a CSRF vulnerability.
This attack works because authentication information, such as session cookies and IP address, will be sent along with the request. The website has no way of knowing the request is not legitimate.
To mitigate the risk, include a token in every POST and AJAX request that cannot be guessed by the attacker. Verify the token on the server before allowing any transaction. Tokens can be synchronized between the server and browser or be HMAC based with a key on the server for verification.
Check out OWASP’s CSRF Prevention Cheat Sheet for more details on how to stop CSRF attacks.
The prevalence of SQL-based databases and the juicy data they contain make SQL injection a favorite of attackers. SQL injection has been top of the application vulnerability list for a number of years and, despite the ease of remediation, is sadly still an all too common occurrence in web applications.
SQL injection occurs when developers create dynamic queries that depend on untrusted input. An example of a vulnerable piece of code in Java looks like this:
The best defense is to use either parameterized queries (also called prepared statements) or stored procedures. For example, a parameterized query is a query in which placeholders are used for parameters and the parameter values are supplied at execution time which prevents the user input from leading to SQL injection. The separation of command (the query in its pure structure) and data (parameters) makes it safer than puzzling together a query string including parameter values to execute as an ad hoc query.
The below example code with parameterized queries is easier to understand and is much safer:
For more info, check out the OWASP SQL Injection Prevention Cheat Sheet.
HTTP is a stateless protocol. This means that every request from a browser to a server is separate and shares no state. Sessions are required to allow the server to know who is sending each request.
When the user authenticates successfully, a session ID is created and sent back to the user in the form of a session cookie. The session ID then becomes the strongest method of authentication. Having the ID is as good as having the username and password.
Session hijacking occurs when an attacker grabs a user’s session ID and impersonates them. If an attacker manages to steal a session ID, your site won’t be able to tell that the requests are from the wrong person.
There are a host of best practices with session management, so we don’t have the space to go through them all here. However, the basics center around protecting the information in the session cookie.
- Use TLS (HTTPS) for all communications between the browser and the server
- Set the HTTPOnly and Secure flags on the session cookie to make sure the browser only sends it with an HTTPS connection.
- Set a realistic timeout for your sessions so they don’t stick around too long.
- Encrypt persistent cookies (the “Remember Me” cookies) so they can’t be stolen from someone's computer
Denial of Service (DoS) attacks aim to tie up a website’s resources and stop it from serving legitimate users by taking it offline. DoS attacks have evolved into the more complex and sophisticated Distributed Denial of Service (DDoS) attacks, which are performed as a coordinated attack using multiple computers.
A common form of DoS attack is called the SYN Flood attack. Imagine you have a row of five phones in front of you. I take a phone and dial one of your phones. When you answer, I say nothing but I don’t hang up. I do this four more times until you run out of phones to take calls. After this, your mom can’t call you because you have no phones available to take her call.
The SYN attack works the same way. A computer opens a connection to the webserver, initiating a three-way handshake. The handshake is purposely never finished, however, and eventually, all of the servers capacity for connections is taken up by unfinished handshakes. Now real users can’t connect to the server.
DoS attacks can be limited by good architectural design. For example, by ensuring there is no single point of failure in your infrastructure. Rate limiting and caching can also be implemented to reduce the number of connections occurring at the same time, saving bandwidth by serving cached results. The overall goal is to avoid long processes that take up large amounts of memory.
More techniques to defend against DoS can be found at OWASP’s Denial of Service Cheat Sheet.
Social engineering refers to attackers tricking you into divulging confidential information. It’s easier to trick someone into giving up their password than it is to crack it.
A social engineer preys on trust, helpfulness, and curiosity to get what they want. When it comes to hacking your site, attackers seek to trick users into giving up their password. Some have been able to fool customer service associates into divulging sensitive customer information by posing as the customer.
Education is the best defense against social engineering. Help your users see the danger of social engineering and report suspicious emails. Implement an extensive security awareness program for all employees and enforce strong authentication mechanisms, especially for authenticating over the phone, such as asking about a recent transaction or another piece of information only a legitimate user would know.
Vulnerable Third-Party Components
Websites are seldom built from scratch. Common functionality is often delivered using open source components. Unfortunately, when these components have vulnerabilities, the code that depends upon them is also vulnerable.
Equifax was breached because it used a vulnerable version of Struts, an open-source MVC framework for Java web applications. Your code doesn’t have to be the code with the vulnerability for your site to pay the price.
Keep track of all open-source and third-party components your site uses. Make sure they all have a specific purpose.
With a clear inventory of components, you’ll be better able to keep them up to date. When vulnerabilities are found and patches are released, apply them as quickly as possible. Build a mature patch management process and keep your website safe against attack.
Don’t Forget the Fundamentals of Securing Your Website
To some, these may be basic security problems. But even basic problems can become gaping holes in your security.
Don’t let complacency replace good fundamentals. Understand the common attacks against your website and how to defend yourself. Write the code well, and it’ll be much harder for attackers to get a foothold into your systems.