Security in web applications isn't a luxury — it's a necessity. While building apps like Tammeny, Esma3 Radio, and Eleqbal Form, I discovered that security vulnerabilities aren't theoretical; they're real and can happen to anyone. In this article, I'll share the lessons I learned the hard way so you don't have to learn them the same way.
The first lesson was about XSS (Cross-Site Scripting). In a simple project I was working on, I was displaying user comments without sanitizing the text. One day I discovered someone had inserted JavaScript code into a comment and executed it on other users' devices. Since that day, I've used DOMPurify to sanitize any HTML coming from users before displaying it. React naturally protects against XSS because it escapes text automatically, but when you use dangerouslySetInnerHTML, you lose that protection.
The second lesson was about CSRF (Cross-Site Request Forgery). Imagine you're logged into Tammeny and sharing your location, and suddenly you open a malicious website that sends a request to Tammeny under your name without you knowing. The solution was using CSRF Tokens — every form contains a secret token that the server verifies. In Eleqbal Form, every registration form includes a CSRF Token to ensure the request comes from the site itself, not from elsewhere.
The biggest mistake I made was with environment variables (.env). In one of my early projects, I put an API key directly in the code instead of in a .env file. By accident, I pushed the code to GitHub. Within hours, someone found the key and made thousands of requests on my account. Since then, I use .env.local for sensitive data and make sure .gitignore excludes these files. I also use Vercel Environment Variables for deployment so keys are never in the code at all.
Secure authentication in Eleqbal Form was an important learning experience. I used OTP via email instead of traditional passwords. The reason: passwords can be guessed and have dictionary attacks, but OTP has limited validity and changes every time. I also used Rate Limiting on OTP sending to prevent brute force attacks. Each IP address can't request more than 5 OTPs per hour.
Rate Limiting in general is an important lesson. In Esma3 Radio, I noticed bots trying to fetch thousands of stations in seconds. I added Rate Limiting on every API Endpoint, which protected against DDoS and excessive resource usage. I used a Sliding Window Rate Limiting pattern allowing 100 requests per 15 minutes per user.
Input Validation isn't a luxury — it's the first line of defense. In all my applications, I validate everything coming from the user: type, length, format. I used Zod for form validation in Next.js, which saved me from writing manual validation. In Eleqbal Form, student data must match specific patterns: email must be valid, Egyptian phone number must start with 01 and be 11 digits long.
A final important piece of advice: security is an ongoing process, not a one-time step. Every time you discover a new vulnerability, fix it and document it. Do periodic security audits of your code. Use tools like npm audit to discover vulnerabilities in the libraries you use. Security vulnerabilities aren't a flaw in you as a developer — the flaw is ignoring them.


Top comments (0)