CS 478 – Homework 4 Reflection

1. Authentication

Backend

The main changes I made for authentication were adding a users table and a sessions table. Passwords are hashed using Argon2, and on successful login the server generates a random session token and stores it in the sessions table. The most challenging part on the backend was making authentication work consistently across all endpoints. To handle this, I wrote a small helper function that reads the authentication cookie, validates the token by checking the sessions table, and attaches the authenticated user to the request object. Another tricky part was handling ownership of books, since each book stores a created_by_user_id. Edit and delete routes check that the logged-in user matches this field before allowing the operation.

Frontend

On the frontend, the hardest part was working with cookies and making them work correctly with Axios. I had to enable withCredentials: true so the browser would include the authentication cookie in API requests. I also needed to ensure the UI did not offer actions that users were not authorized to perform, such as hiding edit and delete buttons when the user is not logged in or does not own a book.

2. Deployment

My biggest struggle with deployment was following the correct process to build both the backend and frontend and then serve the frontend assets in production without relying on the Vite development server. I also ran into build slowness locally while developing, especially with the frontend, due to my repository being stored in an iCloud-synced folder. Moving the project out of iCloud resolved these issues and made the build process much more reliable.

3. Security Audit

XSS

I considered XSS risks mainly around user input such as usernames, book titles, and author bios. On the frontend, React escapes content by default, and I made sure to never use dangerouslySetInnerHTML, so user-provided data is rendered as plain text rather than executable HTML or JavaScript. On the backend, all incoming data is validated using Zod schemas and returned as JSON responses. Combined with a strict Content Security Policy set using Helmet, this significantly reduces the risk of XSS attacks.

CSRF

Since my app uses cookies for authentication, CSRF was a concern. To mitigate this risk, I implemented multiple protections. Authentication cookies are set with SameSite=Lax, which prevents them from being sent with most cross-site requests. Additionally, for all non-GET API requests, the backend checks for a custom X-Requested-With header. This header is automatically added by Axios in my frontend but would not be present in a forged request from another site. Requests missing this header are rejected.

Rate Limiting

To reduce brute-force login attempts, I added application-level rate limiting using express-rate-limit. This is applied to the authentication endpoints and limits how many requests an IP address can make within a 15-minute window.

HTTP Headers

I used Helmet to automatically set security-related HTTP headers such as the Content Security Policy, X-Frame-Options, and X-Content-Type-Options. These headers provide defense-in-depth and help reduce the impact of common web-based attacks.

Additional Security

Authentication cookies are marked as HTTP-only so they cannot be accessed by JavaScript. I also restricted sensitive actions to non-GET HTTP methods and ensured that authorization checks are enforced on the backend even if the frontend hides certain UI elements. This ensures that security does not rely on client-side logic alone.