A baby step to secure your web application from XSS (Cross Site Scripting)
Currently it’s very easy to create a web application. It took only under 10 lines of code to create a NodeJS server and a full functional discord bot, because a lot of people around the world collaborate to build easy-to-use frameworks for it. Our works as a developer become much more easier from time to time. But, this situation is usually making us forget about securing our web application. Even though, I’m not an expert in web security and only started my career as a software engineer a year ago. I would like to share to you on how I secure my web application from cross site scripting issues. Before we begin, better for us to know what is cross site scripting or XSS.
The Story of XSS (Cross Site Scripting)
First of all, we have to deep dive a little bit to the history of the cross site scripting or usually known as XSS. Microsoft introduced the term “cross-site scripting” in January 2000. It referred to an attack using a script that injected to the client side code. In term of frequency, these kind of attack provided roughly 84% of all security vulnerabilities documented by Symantec up until 2007¹.
How is common cases of cross site scripting for user? A lot of internet user doesn’t aware with these kind of vulnerability, including me. But luckily for us, there are a lot of articles about web security and vulnerability for us to read. One of them explain this common case with a nice infographic and we can see it in figure below².
The attacker is sending an injected link to the victim via email. That’s why we should aware if there are email that suspicious with a random link. But again luckily for us email provider like Gmail or Outlook have their own machine learning classification model to classify email scam. So what if we accidentally get bait with that email and click it. The script that injected to the link will be executed and send your private data in your browser cookies.
After I explain it from user perspective, I think it’s also much better to explain it from developer perspective. When we are building a web application, we usually divide our system into three different simple layer: frontend — backend — database. The script can be injected to our db through input form in our frontend or through API in our backend. If we don’t have any validation before we send our data to the backend and the backend don’t have any mechanisms to validate it, the malicious script can be saved to database and harm the other users. It can be prevented by implementing
How can we secure our web app from XSS?
After we know how the cross site scripting attack work, then we can move into what are the steps that can be used to prevent it as a developer. There are a lot of action that we can do to prevent the cross site scripting in our web application. But the basic idea is to prevent the script that injected by the user to be executed by the browser. I will give you simple examples from my personal experience and other references.
Escaping your input
We are usually not aware that we pass the params into our view. Maybe modern client side render frameworks like React are escaping your params by default and it’s not become a problem. But, we should know how it works. For example, in react we can use JSX data binding for it. It works by preventing any embedded value to be rendered by escaping it and convert it to string³.
- Client Side Render (React)
function App() {
const userInput = "Hi, <img src='' onerror='alert(0)' />"; return (
<div>
{userInput}
</div>
);
}
Instead of rendering the view in the client side, framework like rails use server side render to built the view for the user. Rails has a couple ways to avoid the cross site scripting and also these ways usually is included out of the box by the framework. So we shouldn’t install any gem for it. Here I give you examples how we prevent it for rendering a html or rendering a json based on this reference⁴.
- Server Side Render (Rails)
html_escape('is a > 0 & a < 10?')<script>
var currentUser = <%= raw json_escape(current_user.to_json) %>;
</script>
Making friend with regex (Regular Expression)
Personally, I was not a big fans of regex, because it hard to master. There are several combination and ways to achieve one thing in regex. A lot of developers are not always confident in using the regular expression and convenient to read⁵. But after I know that regex can be a useful tools to strip a string, I started to love it. Below is very basic ways in ruby to sanitise your input string before you save it to the database. So it will not include the source tag of javascript.
- Sanitise the string using regex
our_friend_regex = /<(.|\\\\n)*?>/
sanitised_string = your_input_string.gsub( our_friend_regex, '' )
Configuring your HTTP Headers to prevent cookies stealing
If the attackers already injected a script to steal cookies, we can prevent it by set the HTTP header with ‘HttpOnly’ flag. As mention before, the attacker could inject malicious script in Javascript on a page. The ‘HttpOnly’ flag blocks the access of the cookie from the client-side script. So here is an example of the Set-Cookie HTTP header that contain ‘HttpOnly’ flag.
- HTTP Header
Set-Cookie: <name>=<value>[; <Max-Age>=<age>] [; expires=<date>]
[; domain=<domain_name>] [; path=<some_path>][; secure][; HttpOnly]
Summing Up
Those are the simplest things or baby step that we can do as a developer to secure our web application from my experience as a software engineer in the last twelve months. I believe that the technology will always change and improve, and there will always be a way for attacker to finding security hole inside it. As a developer we need to remember these four baby steps, when dealing with cross site scripting.
- Avoid direct data injection into the DOM
- Always escape user input
- Sanitise the user input data
- Keep yourself with current technology and security update
References
[1]: en.wikipedia.org/wiki/Cross-site_scripting.
[2]: https://www.cloudflare.com/learning/security/threats/cross-site-scripting/.
[3]: https://dev.to/spukas/preventing-xss-in-react-applications-5f5j.
[4]: https://api.rubyonrails.org/classes/ERB/Util.html#method-i-html_escape
[5] — https://medium.com/ase-conference/regexes-are-hard-e7933ae3122d