CS 478 Homework 4 Reflection

Asiful Islam

1. Authentication

What did you struggle with when adding authorization to your back end?

I struggled with adding the authorize middleware at first, making sure it validated the session token from cookies against the server's storage. I had to make sure I was handling edge cases (such as a missing token or a token no longer existing in tokenStorage) and ensuring the server returned the right status codes so the front end could redirect or show the errors properly.

What did you struggle with when adding authorization to your front end?

I struggled with managing the asynchronous state of the current user, ensuring the UI updated immediately after login or logout actions. I implemented a checkAuth function to re-verify the session with the backend on every page load with useEffect and keep the "Welcome" and "Logout" buttons in sync with the user's session state.

2. Deployment

What did you struggle with when deploying your app to the internet?

It'd probably be shorter to explain what I didn't struggle with. I had troubles with SSL certificates and DNS configuration, initially not loading because Let's Encrypt wasn't issuing a certificate (I think). I went back and saw my A DNS record was pointing to my Tailscale IP instead of my public one. After fixing that, I couldn't test immediately since I had to wait for DNS changes to propagate. I also had issues with the server, since Caddy was crashing and the server itself overloaded and crashed when I tried to run npm run build on my server. I had to run it locally and scp the build folder to my server, and then I was able to serve the website without crashing.

3. Security Audit

If your app was vulnerable to XSS attacks, explain what you did to mitigate them. If it wasn’t, explain why.

My app wasn't vulnerable to XSS attacks since I'm using React for the frontend. React automatically escapes any user-generated content before rendering it, which prevents malicious scripts entered in the input fields from executing. I also didn't use dangerouslySetInnerHTML anywhere in my code, which is a common source of XSS vulnerabilities. By relying on React's built-in protections and avoiding unsafe practices, I ensured that my app is secure against XSS attacks.

If your app was vulnerable to CSRF attacks, explain what you did to mitigate them. If it wasn’t, explain why.

My app wasn't vulnerable to CSRF attacks since I configured the session cookies with sameSite: "lax". This instructs the browser to block cookies on cross-site POST requests. If an attack tried to trigger a delete action from their own website, the browser would send the request without the authentication cookie, causing the server to block the request due to the authorize middleware. This effectively prevents CSRF attacks on my app.

If you added rate limiting with a firewall, include what commands you ran/packages you used. If you added rate limiting to your application code, indicate this.

I added rate-limiting to the application code using the express-rate-limit package, configuring a global limit of 100 requests per 15 minutes for my API routes. I also added app.set('trust proxy', 1) to identify the real client IP address since the app runs behind a Caddy reverse proxy. This helps prevent abuse and protects against brute-force attacks by limiting the number of requests a client can make in a given time frame.

Explain what HTTP headers you set, what they do, and why they’re useful.

I used the Helmet package to set secure HTTP headers, specifically Content-Security-Policy (CSP). CSP restricts the sources from which content can be loaded, helping to prevent XSS attacks by blocking malicious scripts from untrusted sources. I customized the CSP to allow 'unsafe-inline' for style-src so my Material UI library would render correctly, but maintain security for my other resource types.

If you did anything else to secure your app, explain what you did and why.

I added SQL Parameterization to prevent SQL injection attacks. In my backend code, I used parameterized queries with placeholders (e.g., db.get("SELECT * FROM users WHERE username = ?", [username])) instead of concatenating strings, ensuring that the database engine treats user input as data rather than executable code to make it impossible for an attacker to inject malicious SQL commands to dump or destroy the database. I also added input validation with Zod schemas if that counts to prevent malformed data from reaching my database or application.