A common misunderstanding in the world of Web Application Security is the difference between the consequences of a Cross-Site Scripting vulnerability and the consequences of an Injection vulnerability. We can even go a step back and say the misunderstanding is on a much broader level; the difference in consequences between a client-side exploitable vulnerability and a server-side exploitable vulnerability.
Both server-side and client-side vulnerabilities are listed in the top 3 of the OWASP top 10, Injection being the server-side vulnerability and Cross-Site Scripting(XSS) being the client-side vulnerability.
As per OWASP, an injection vulnerability or flaw is one that encompasses SQL, OS, and LDAP where untrusted data is sent to an interpreter through a command or query that goes unsanitized by the web application. The interpreter will then execute the code as though it was part of the developer's original code.
In order to understand an injection type vulnerability, you must first understand the basics of how a web application interacts with other server side systems.
For example, let's say you have a web application with a login form. That login form is tied to some sort of database on the backend. That database may or may not be located on the same server as the web application, to keep this straightforward we will assume that the database is on the same server (A big no no for PCI compliance). The login form interacts with the database when a user enters data into the form fields and then clicks the submit button. The data entered is passed through a script that runs queries on the data in the database. Those queries are used to look for a record matching the data entered by the user. If a matching record is found, the user is allowed access to another portion of the application, possibly providing them with access to secured data.
An injection vulnerability exists when there are no mechanisms in place to validate or sanitize the data being submitted into the form fields by the user. If the data being submitted is not sanitized, the user may be able to send code that the database could interpret in a way that it was not intended to. A common way of doing this is to break out of the intended code by first closing the hard coded string and then beginning an entirely new string. This new string is then executed by the database. This new string could be used to pull, delete, or modify data that is in the database. By injecting different strings, the user may even be able to gain control of the entire system.
Obviously, injection vulnerabilities can be extremely dangerous, but what happens when the same failure to sanitize data is found on forms, and within requests, that don't directly interact with a backend system? Instead, what happens when this data is simply redisplayed to the requester? This is when you have the possibility of a client-side vulnerability called Cross-Site Scripting.
As per OWASP, a Cross-Site scripting vulnerability occurs when data submitted to an application is re-displayed in the browser without sanitization. This means, instead of an attacker injecting code to cause harm on the server side, the code is instead used to cause harm on the user side. But, rather than the attacker passing the code to the application, the attacker tricks the user into passing the code. This code is then passed back to the user in a way that causes their browser to parse it as though it were part of the page to begin with.
To understand this we can use a contact form as an example. Across the internet, many companies and organizations wish to provide their user base with a method of communication that doesn't involve picking up the phone. To do this, they create contact forms on their website. These forms are intended to allow for quick and simple communication from the user without the need for mail clients and the like. Contact forms most often include a field for the user's name, E-mail address, and a small message. Often, little thought goes into properly securing contact forms. Because those forms are not directly accessing a database or other pieces of secure data, there is often little concern for how they function on a secure level. These forms lack validation and sanitization.
What does that mean? First what does it mean to validate a form field? Validating a form field means determining what data is and is not allowed to exist in the field before allowing it to go any further and be processed by the application. One of the simplest ways to validate the data in a form field is to compare each character submitted against a list of allowed and not allowed characters. This is the best filtration method as it works well to prevent XSS and Injection vulnerabilities alike.
There are other methods besides validation that can be used to prevent XSS vulnerabilities as well, such as output sanitization. Output sanitization is the act of filtering the submitted data after the fact and before it is re-displayed in the output. This allows for less constraints on user input, letting the user enter whatever they want while having the server do the work of encoding the data on output to prevent the browser from interpreting it as HTML code.
And that is the long and short of XSS, XSS is submitting data to the application that is then re-displayed just as it was submitted without any interference of security mechanisms. If HTML code is submitted, that same HTML code is re-displayed, only this time the browser parses the data.
But why is this a client-side risk. Obviously, the only user that sees the re-displayed HTML being parsed by the browser, is the user that submits the data to begin with. Essentially, the attacker would be attacking themselves. But that is the beauty behind XSS, it is one part developer coding flaw and one part social engineering. To attack the user, the attacker must trick the user into passing the malicious code to the application from their own browser. This is often easier than it sounds. The most common method is by tricking the user into clicking on a premade link that includes the malicious code. Clicking the link sends the data to the application, causing the data to be re-displayed in the users browser. As far as the user is concerned, what they are seeing is coming directly from the organization they believe they are accessing data from.
What makes this even more dangerous is the fact that the "Injected" code is not a permanent addition to the site involved in the attack. Instead, the code is there only for the moment that the user submits the request and receives the response. Once the user leaves the page, that code is gone. Many developers don't see this as an issue because it does not modify the code on their backend, and no data that is stored on their servers is being accessed. But, XSS is still an issue; instead of stealing data that is already stored on the server, data can be stolen before it is even sent to the server.
My favorite example to help explain this is an XSS attack utilizing an iframe. An iframe can be used to load data from anywhere on the web, having it show up inside of a frame on the vulnerable website. Imagine that you are an avid shopper on a certain organizations electronics website. It is nearing black Friday and you are looking for the best deals. Now, lets say that an attacker finds an XSS vulnerability on the electronics companies website that allows them to inject an iframe. First, the attacker spends a little bit of time grabbing images and CSS and other pieces of content from their site. Using this data, the attacker builds an identical website (or at least a few important pages) and hosts them on a different server. These pages that the attacker is hosting just happen to mimic the way the login page functions, and how some of the product pages and the checkout page works. Before black Friday, the attacker sends out an email claiming to be from the electronics company to hundreds and thousands of people with contents explaining that they are having a huge sale with a link to the special secret sale page. The electronics company is huge and its the right time of year, someone is going to be interested for sure. The interested users run through the email and look at the link they are provided. The link is definitely pointing to the correct companies website, so all looks safe (they don't notice the malicious iframe code in the URL, or the code is embedded within flash or something similar). Upon clicking the link they are taken to the companies website, but the iframe loads with the data that the attacker is hosting. The attacker does a great job of hiding the iframe by disabling the scroll bars and removing the frame borders. The attacker also makes sure that the iframe size is large enough to cover most of the real webpage. At this point, all the users are seeing is a replica of the companies page that is actually the attackers page. The users then attempt to login to their accounts. Before this, the attacker had a number of choices to make; they could have simply stored the data coming from the users and provided nothing of use to the user in return, or they could be even more devious and actually submit the data to the real company's website while then forwarding them to the real page while also storing the data on their end. At this point the user would have no idea that anything out of the ordinary had happened, but the attacker now has their login data. The same methods can be used for checkout pages to steal credit card information, social security numbers, and other types of sensitive information.
So, you can see how XSS, even though it is not a permanent exploit, can be just as dangerous as injection if not worse.
There is definitely more to each of these exploit types, but I hope this general overview has given you a clearer understanding of the consequences and differences between the two of them.
In short, Injection vulnerabilities put server-side data at risk of exploit, while XSS type vulnerabilities put client-side data at risk.