How I Mistakenly Introduced a Backdoor into Our Web Application
Time without number, we have been told ‘move fast, break things. We recently took this literally, and boy, did we break some things! Especially when you’re obsessed with the user journey and want to ensure they have the best experience, sometimes it comes at a cost. That cost? A security glitch or two, perhaps even an open backdoor.
Security in web development is a bit like throwing this amazing party with an open buffet; then you realize you accidentally invited the entire town, including the local ‘food critic,’ who’ll eat all your food and then complain about the lack of variety on his way out. We all know you are not the Great Gatsby but everyone with a browser can access your www.super-cool-web-application.com
.
Here’s a tale of how our well-intentioned ‘move fast, break things’ approach led us to create a backdoor in our web application.
The Delicate Balance of Security and Convenience
Striking the right balance between user convenience and robust security is akin to walking a fine line; even a slight misstep can lead to significant challenges.
We were setting up user accounts for our API, all was going well. As part of our application requirements, users needed to validate their billing information, a crucial step to ensure only legitimate folks got in. We had a partnership with a billing provider, that was healthy for our unit economics and so during development, we coupled our user on-boarding flow together with our billing provider’s integration which worked well.
The Diagram below gives an overview of what that looked liked.
Life happens
Once our app was developed and GT.FOL. We assumed everything was supposed to work as intended in production; but, life threw a curve-ball. A critical downtime had hit our billing provider and we were forced to temporarily remove their integration as part of our verification workflow, pending till they fixed their downtime — while we set up an alternative verification API endpoint in the meantime.
Simple enough, this new endpoint could verify a user’s account through the on-boarding, until our provider came back online or we implement a new integration.
The Design Flaw: A Red Carpet for Intruders
So now, all sections colored in red have been removed from our workflow, and we enabled users to call the verification endpoint without being authenticated.
Our newly-created endpoint only required the user’s ID, which was returned after a successful signup. To enhance the user experience, we provided a token that automatically logged them into the platform once they were verified, saving them from another login flow post-onboarding. It seemed like a good idea at the time.
Previously, during the verification process, our integration with the billing provider had allowed us to create an ephemeral session using a session token from them. But when we removed this integration, the session token was no longer available, leaving a significant gap in our security protocol.
Here lay our flaw: without the session token’s added layer of security, anyone possessing the user.id could call this endpoint and receive an access token, granting them unfettered access to a user’s account. Potentially dangerous, you might say? Absolutely.
You may wonder why we didn’t simply log the user in when they signed up. The reason was twofold: First, the user technically wasn’t authorized yet, a measure to combat SPAM. Second, our login workflow contained several specific interceptors that we didn’t want to entangle with this temporary fix.
Unbeknownst to us, we had unintentionally created a loophole, a veritable VIP entrance for anyone crafty enough to discover it. Anyone with a user’s ID could now waltz right into their account, bypassing the password altogether. Our well-intentioned efforts to improve the user experience had inadvertently opened a can of worms, and we were left to face the music.”
Lessons Learned and Prevention Ideas
1. Recognize the Importance of Layers: An Onion Approach:
Security is like an onion; it should have layers. Our mistake was removing an essential layer without considering that we might end up in tears.
2. Always Test for Unintended Consequences: The “Oops” Factor:
Testing should cover more than functionality. Security testing can uncover those hidden “oops” moments that might otherwise slip through.
3. Limit exposure of sensitive information:
Avoid returning sensitive information like user IDs or access tokens unless absolutely necessary. If you wouldn’t shout it in a crowded room, don’t hand it out digitally.
4. Regular Security Audits and Monitoring:
Keep an eye on the digital comings and goings with regular security audits and real-time monitoring. It’s like having a digital security camera; you can always see who’s lurking around.
5. Educate Your Team:
Make sure everyone on your team understands the importance of security and the potential risks of seemingly simple decisions. Knowledge is power, and in this case, it’s also a sturdy lock.
Wisdom from a Misstep
They say mistakes make the best teachers, and our inadvertent backdoor was a masterclass in humility. With careful planning, testing, and a good dose of skepticism towards our own code, we can build systems that are user-friendly and secure as Aso Villa.
Remember, in the digital world, a well-intentioned mistake can lead to a party in your backdoor. Don’t let uninvited guests ruin the fun!
What about you? Ever found yourself in a security pickle? Share your stories with me, and let’s learn from each other’s “oops” moments! and if you’re interested in diving deeper, you can read my answers on a similar topic over on Quora.”