-
Notifications
You must be signed in to change notification settings - Fork 460
move away from express helmet #927
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm very excited about this. Thank you so much for taking on the task of maintaining this package. I'm looking forward to merging this. I just have a couple questions.
app/entry.server.tsx
Outdated
| @@ -1,6 +1,6 @@ | |||
| import { PassThrough } from 'node:stream' | |||
| import { contentSecurity } from '@nichtsam/helmet/rules/content/index' | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a nitpick, but is there any chance you could add exports config in your package.json so that we don't have to dive deep into your package? Instead, this could be more like this for example:
| import { contentSecurity } from '@nichtsam/helmet/rules/content/index' | |
| import { contentSecurity } from '@nichtsam/helmet/content' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also didn't like that, but didn't know how to path them better, thanks for the idea!
I will update the package to simplify the import path.
| app.use((_, res, next) => { | ||
| helmet(res) | ||
| next() | ||
| }) | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you help me understand what this does, why we need this, and what's in the entry.server.tsx?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These lines ensure that all routes are protected, not just Remix routes.
When working on CSP and other security headers, I realized that some security headers are specific to the response type. Some apply to all types of resources, such as X-Content-Type-Options, Strict-Transport-Security, and Cross-Origin-Resource-Policy. Others are content-specific, typically for text/html, some (like CSP) can also apply to application/xml, application/pdf,image/svg+xml and more (see this).
To improve clarity and control, I categorized the headers into three groups:
1. General – Applied to all resources.
2. Content – Applied to content types.
3. Resource Sharing – Related to cross-origin policies.
Here, we apply the general security headers, ensuring that assets, JS files, and other resources are covered. In entry.server.tsx, we handle content-specific headers for text/html, such as CSP.
The main helmet works on Web Fetch API's Headers, this import is essentially a wrapper on it to work with http.ServerResponse.
I hope this is clear, feel free to ask for more details!
|
Also, could you take a look at the Playwright test and make sure that those are passing? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's clear to me. Thanks so much!
|
Sorry about the merge, commit. I'll wait for you to update the paths and things, and then we'll get this merged. Thanks a ton! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome! Thank you for this. Very very cool.
|
Looks like we still need to have the playwright tests passing. I saw your issue and I’ve noticed some flakiness as well, though the CI normally passes. I would prefer to wait to merge this until we have a green CI on this PR. |
Same here. I don’t think this should cause test failures, but I’m not too familiar with Playwright. I’ll need to find some time to look into it. |
|
Hmmm... I tried re-running the playwright test for this PR and it failed again. All the playwright tests on the main branch have passed without issue. I'm worried this change may be affecting the test outcome in some way so I'm not going to merge this until we resolve the test failures (which maybe involves finally solving #931). |
No worries! The tests on the main branch are failing on my device as well. I’m not sure why they pass consistently on your side but not here—maybe I didn’t set up the environment correctly. |
|
I realized the epic-stack/app/routes/_auth+/auth_.$provider.ts Lines 13 to 34 in fdeda42
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The tests all pass locally for me, so I'm going to go ahead and merge it. Thanks a lot!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I absolutely love this, thank you so much!
previously: #924
resolves: #920
Issue
The current implementation of Express Helmet applies security headers globally, resulting in HTML-specific headers, such as Content-Security-Policy and X-Download-Options, being applied to non-HTML routes.
Solution
This PR replaces Express Helmet with a custom package I developed, @nichtsam/helmet, which more effectively distinguishes between different layers of security headers.
Test Plan
Checklist
Screenshots