Security testing is a whole profession on its own, which requires knowledge of niche tools, experience with various technologies, and a bit of destructive mindset. But it doesn’t mean security testing should be left only to the experts.
Today, we will show you how you can extend your functional testing knowledge to unveil the hidden vulnerabilities in your web application using nothing but your browser!
A simple feature to test
Let’s set the stage; imagine that you are supposed to test the following feature:
Payment Confirmation ScreenAs a user, I want to be able to enter my name and address details and confirm the provided payment amount.Acceptance Criteria:
- Confirmation shall not be possible if name or address is empty.
- User shall not be able to change the payment amount.
- If the user is a premium member, no shipment fee shall be added.
- If the user is not a premium member, a 5 Euro shipment fee shall be added.Out of scope:
- Premium member registration
- Payment amount calculation
- Validation of name and address (they shall be accepted as long as they are not empty)
For testing, you will be provided with a screen where a predefined payment amount is filled, and the user is not a premium user. Calculation of the payment amount, premium member registration, and passing this data to the screen is already tested.
Now, visit the exercise page if you haven’t already, think of which tests you would execute, try them out, and see if the implementation looks correct.
If you have identified some potential security issues, congratulations! You already have a tester mindset where you don’t limit yourself with just validating the acceptance criteria. Continue reading to see if you have caught all hidden flaws.
If you think that the implementation looked good, keep reading to start a new chapter in your testing approach!
Frontend and Backend; connected but independent
When you focus on the user interface (UI), you can conclude that it satisfies all the provided acceptance criteria. You cannot submit the form with empty input, you cannot modify the payment amount, and there is no option to change the premium status. Everything is fine, right? Well, not really.
When working on a web application, a common fallacy is to consider frontend and backend as a whole, like inseparable parts of a single application. This mindset can affect testers to focus on end-to-end (E2E) tests, performing all the actions and verifications on the UI level.
However, frontend and backend are two independent components, only connected with APIs in between. While the backend is in a remote server, the frontend resides in the client’s machine (usually inside a browser). This brings up two problems:
- The user can modify the frontend (not just the UI, but also the user scripts and local data)
- The user can skip the UI altogether, and directly use the APIs.
This is why a common rule of thumb is to “ensure that the backend validates every data it receives“. And that is also why, as testers, we need to ensure that this practice is being followed.
Let’s see what this means for our example.
Modifying the frontend
Most web browsers come with a set of developer tools which lets you peek behind the curtain. These tools can be used to inspect (and modify!) all elements of the frontend that resides in your computer.
In the examples we will use Chrome’s developer tools, you can refer to your own favourite browser’s documentation to achieve a similar effect. (see Safari, Firefox, Edge). You can usually open the developer tools by right clicking on any page and selecting “Inspect” or “Inspect Element”.
Is a required field really required? Or a read-only field read-only?
If you have tried submitting the form with an empty name or an address, you have realized that the browser doesn’t allow you to do it. At first glance, the acceptance criteria appear to be satisfied. But is it really so?
Go back to the example page, and right click on the “Name” field, and click on “Inspect”. The developer tools window should open with the name field selected.
Double click on “required” attribute and just delete it. Now, you will see that you can submit the form with an empty name field.
You can do the same with the address field, and these are potential bugs for the system. On the other hand, it is not much of a security threat to be able to create an order with an invalid recipient. It would be even better if we could get some monetary gain.
For that, try inspecting the “paymentDue” field. You will see that it has a readonly attribute, which can be removed in a similar way. Or you can just update the hardcoded “value” attribute to something more affordable. In fact, you can even give negative values a try!
Frontend is more than the user interface
For this example, let’s have a look at the most (in)famous form of local storage: cookies. In the developer tools, go to the Application tab, and click on the entry under the Cookies section. It will list all the cookies from the site. Some of them might be confusing, but “isPremiumMember” looks interesting. Try setting its value to “true”, and submitting the form again.
You might be thinking that this is just a goofy little example, but I had personally come across a popular website where you could set the isAdmin flag to “true” in the cookies to have all the administrator rights!
Note that the change you make in the UI are temporary, and they will not be there after a refresh. The cookie on the other hand will be persistent until it expires, or gets overridden by the web page.
How about skipping the UI altogether?
As we have mentioned, backend and front are independent, and connected to each other via APIs. In the developer tools, you can switch to the Network tab and observe the API call made when you submit the form.
Et voilà! All the parameters we were chasing are plainly available in the API call. You can call this API using a tool like Postman, or from your terminal with commands like cURL, and play freely with the parameters!
Do we not need frontend validations then?
No! They are still important for user experience, and they should still be tested. However, they should not be the trusted to ensure security. In fact, the backend should always be responsible for validating and sanitizing the data it receives.
As you’ve seen, security testing is not just for experts. With a bit of curiosity and a willingness to explore, you can uncover vulnerabilities in web applications using nothing more than your browser and its developer tools.
So, what are you waiting for? Start practicing your security testing skills today! Visit the visit the exercise page (or in fact any other web site), experiment with the frontend and backend, and see how far you can push the boundaries.
Remember, security is an ongoing process, not a one-time event. Keep practicing, learning, and sharing your findings to help make the web a safer place for everyone.
And meanwhile, don’t hesitate to reach out to us if you want to improve your testing approach, or improve the security of your system with the help of our domain experts!