Homework 4 Reflection
-
Authentication
- Setting up authorization on the backend was fairly simple as we completed a similar activity in the previous week. I was able to reference my code for the activity to configure cookie options and create request handlers for login and logout functionality. The only challenge was changing my database schema to track user IDs of book owners in the Books table, which led to changes in type definitions for the front and backend.
- When adding authorization to the backend, I ran into a number of request errors as my client responded to changes I had made to the backend. I needed to update all references to BookDB to process user_id as well, since this is now being tracked by the respective table and is expected by the request handler. When editing or deleting books, I kept seeing a 403 error because authorization was not detecting any cookies being sent over to the backend thus the request never even reached the handler. I decided to manually specify "withCredentials: true" on these requests to ensure that my login credentials were being transported via the existing cookie.
-
Deployment
- During deployment, I encountered a number of different issues. Some of them were smaller, such as not being able to connect to the subdomain because I had not reloaded Caddy upon adding the new configuration for home.helloistiak.mom. I also faced issues regarding path, as my relative paths to index.html and database.db, which I was using during development, were not translating well in production as the system could not identify where those files are located. In this scenario, I decided to use import.meta.dirname to root all relative paths to absolutes, which prevented further ENOENT issues, especially when opening the URL to the app from a different machine. This issue also made me realize that my production code on the server-side is slightly different from what I am doing in development, since I do not utilize a public folder for running in Vite locally.
-
Security Audit
- My app does not appear to be vulnerable to XSS attacks. This is because I am preventing in-line scripting via the Content Security Policy I enabled through Helmet JS. To test, I supplied "alert("Hello")" wrapped in a script tag as a response to some of the forms, such as login and add book. I noticed that the application processed these inputs as text and displayed the information as such, and no alerts were generated based on my monitoring of the client-side and server-side logs.
- My app does not appear to be vulnerable to CSRF attacks. Although authentication is cookie-based, I do not have any request handlers for account deletion, so the app's backend would not be able to reach any such endpoint via a malicious link. I also have SameSite cookie options set to 'lax', which ensures that cookies are only sent when the requests are being made from the same site, so any external site would not be able to send a request using cookies that it does not have access to.
- I added rate-limiting via application code, which is indicated by comments at the top of my server.ts file. The rate limits are saved to a constant variable, limiter.
- I used Helmet to set all my HTTP headers automatically, rather than enable each one manually. The main header was the Content Security Policy (CSP), and Helmet applied the default version of CSP to my project to block in-line scripts and third-party resources (non-NPM). Helmet also enabled the X-Forwarded-For (XFF) header, which identifies the actual IP of the client for threat detection and is useful for reverse proxies like what Caddy is doing with localhost. The third important header that Helmet set was X-Content-Type-Options, which essentially tells the browser to strictly adhere to the content type that was specified for a certain page. This is useful in cases where the browser attempts to guess a file's content type and an attacker uses the opportunity to inject a script to run as HTML when the file itself was not intended to be executable.
- Other than the security measures mentioned above, I ensured that my server-side code checked for valid authorization and used conditional rendering on my frontend. Overall, my main security features were implemented via rate-limiting and Helmet HTTP header configurations.