This week we have released SecureWebApp. The first open-source project that I have worked on. It’s a one small step for mankind, one giant leap for me! So what is “SecureWebApp” ?
As the name suggests it’s a secure web application. End of the story, thank you for reading (haha just kidding).
It is indeed a web application offering fundamental security features out of the box. What’s also special about it is that it has been developed in a modular fashion which lets you build an app with various modules as if they were lego blocks (more on that later).
This fall term we have teamed up at my home university to get on with this meaningful project. In the age of Internet, security is the real deal. Sometimes it might be an overwhelming process to find out proper security mechanisms for your use case and easy to get lost in the thick of it, meanwhile all you want to just put on your favorite playlist and start coding.
This is where the SecureWebApp comes into rescue. It is ultimately a template which you can use for any kind of web application and directly focus on the main usecase scenarios.
At the very beginning of the journey we have taken three key requirements along with us:
A template acts as a base. It embodies the essential pieces and abstracts them to be used over and over again while preventing repetitive tasks. Furthermore, it should be easy to extend. This is the reason why we have opted for modularity.
We have implemented each functionality / usecase as a module. With this approach it is easy to plug-in or remove modules without causing any breaking changes. There are some cases where a module depends on other module(s) and in those situations all related modules should be carefully handled.
2. User friendly
We have targeted a broad group of users from beginner to expert developers as our audience and to prevent any discouragement that may arise due to a technical debt (like a pre-requisite to get familiar with a certain framework before starting with the development) we have kept the number of frameworks and technical dependencies at minimum.
The tech-stack is as follows:
- NodeJS (Backend)
- MySQL (Database)
- Apache HTTP Server (Reverse Proxy Server)
- Docker (Deployment / Infrastructure)
- npm (Package Management)
Here is a list of security mechanisms that are available:
- 2-Factor Authentication (2FA)
- Password Hashing
- Content Security Policy (CSP)
- Protection against SQL-Injection
- Protection against cross-site request forgery (CSRF)
- Protection against cross-site scripting (XSS)
- Reverse Proxy Server
Following section gives a brief introduction to each security topic. Goal is to make the reader aware of the risks in the absence of these mechanisms and how they protect a system against malicious attacks. Like in every case, it is vital to understand our WHAT, WHY, and HOW.
If you feel like exploring more about the related security topics, you can find useful resource references in the README, security features section.
“Authentication is the process of determining whether someone or something is, in fact, who or what it says it is.” In our case, authentication takes place by comparing the client-provided e-mail and password (credentials) with the values stored in the database.
If they match, client can access to the available resources, else authentication fails. Resource is a general term used for content of a system. It can be data or some functionality.
2FA is a type of multi-factor authentication. It requires the client to provide more than one type of evidence in order to authenticate. SWA requires 2FA both on registration and user log-in. This additional authentication layer makes it harder to gain unauthorized access to resources.
2FA is a mandatory authentication requirement of SWA. It’s a simple, yet effective procedure. During the registration process, the user first provides their credentials necessary for single-factor authentication. Subsequently, the server generates a random secret which is converted into a QR code and displayed on the user interface.
The user needs an authentication app (like Google Authenticator) to add an account by scanning the generated QR code. In response, server stores the generated user secret alongside other user credentials.
A registered user needs to provide a 6-digit token each time they want to log in. This token is a time-based one time password (TOTP). It gets generated by the authenticator app at a certain interval using the stored secret and current time. When user submits the TOTP, the app generates a token using kept secret and present time, then verifies submitted token with the generated one. If it’s a match user is authorized, else authentication fails.
Hashing algorithms take an arbitrary length of string and generates a cipher text with a fixed-length. They are identified as one-way function in mathematics. This property implies that it is easy to compute in one way (plan text -> cipher text) but hard to do it in reverse (cipher text -> plain text). And it looks something like this:
# Plain text: SecureWebApp
# Cipher text: 53b9402bd21533bc7ea5455def6eda900b518d9687367fc039562cfb281727f4
We hash user passwords before storing them in the database. This minimizes the risk of sensitive information being exposed if anyone gets unauthorized access to the database. Because the cipher texts are not the same as the plain texts, thus an attempt to sign in with hashed password values would be unsuccessful.
Content Security Policy
CSP is another added layer of security. You can think of it as specification of allowed resource types. This helps to mitigate certain types of attacks used for data theft to site defacement. A policy is described using policy directives, each of which describes the policy for a certain resource type.
For instance, font-src directive specifies valid resources for fonts using @font-face and the fonts that are not specified will be ignored. Here you can find an extensive list of policy directives.
Suppose the app uses the following SQL query in the backend to get some data:
WHERE username="' + userName + '" AND password="' + password + '";
Client provides the userName and password. Now imagine an attacker providing ” OR “”=” for both userName and password values (backspace after the first quotation mark is not a typo).
This would result in a valid SQL query and provide access to usernames and passwords:
WHERE username ="" OR ""="" AND password ="" OR ""="";
To protect against such attacks we have used injection-safe SQL queries in SWA.
Protection against cross-site request forgery
CSRF is a type of attack which benefits off an authorized user of a website. A common example is phishing emails. If attacker can trick the user into visiting a malicious website (by making them click to the link and navigate to “Amazon coupon reclaiming page”) which contains a request to the targeted website. If the user is authenticated by the targeted website, the request is executed.
This attack works because the user’s cookies are automatically included in the modified request. Wondering what cookies are? Right now, all you need to keep in mind is that cookies store session information of a user. It is convenient, because using cookies doesn’t require authentication for every single request.
Protection against cross-site scripting (XSS)
XSS is the act of injecting malicious script into the source code of a website. These scripts are client-side executable scripts. When the malicious code executes inside the victim’s browser, the attacker can compromise their interaction with the website.
Consider the following case:
Request body consists of a single parameter which is then rendered in the HTML page as a part of the server response.
<p>User Status: online</p>
This is an unsafe use. Because an attacker can easily inject a script as the `message` parameter:
<p>User Status: <script> /* some malicious code */ </script></p>
If the user visits the URL constructed by the attacker, then the script gets executed in the context of victim’s session with the application and can carry out any action the victim is entitled to.
HTML-escaping replaces some of special characters like &, <, > with their entity names &, <, > . In SWA, all body parameters contained within the request body go through this process. However, escaping special characters may cause unintended side effects if the exact user input is required. In such cases, unsafe request body can be used to prevent it from happening.
Reverse Proxy Server
Reverse proxy is rather a security feature of deployment architecture. Imagine you go to a bank to collect some valuable assets. On the counter you request to get some portion of your savings. Bank worker acknowledges your request, goes to the vault and brings you back the assets. You had no direct contact with the vault but still you got the requested resource.
In this scenario, bank worker on the counter acts as a proxy server. It’s a middle point eliminating direct contact to the vault (resource).
Switching back to digital world, reverse proxy typically sits behind the firewall in a private network and directs client requests to the backend. This constellation acts as an additional defense against security attacks. Besides, a reverse proxy server can also be used for load balancing, though that’s a topic for another day :)
Still processing what you have just read?
No worries, fortunately all these features are implemented and you can start playing around with one click 👾
GitHub - SecureWebApp/secure-web-app: A secure web app template
A web application template with fundamental security features out of the box. Secure Web App template is an open-source…
Oh, almost forgot! Besides all the security mechanisms, user-registration, and login functionalities; SWA supports messaging between two parties.
I had multiple take-aways from this project, so special thanks go to our supervisors and my teammates for making it happen.
Looking forward to hear your feedback.