Skip to content
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

Too many header rules - Cloudflare Pages #504

Open
Vahagn-Zaqaryan opened this issue Jul 31, 2024 · 13 comments
Open

Too many header rules - Cloudflare Pages #504

Vahagn-Zaqaryan opened this issue Jul 31, 2024 · 13 comments
Labels
enhancement New feature or request question Further information is requested

Comments

@Vahagn-Zaqaryan
Copy link

Hi there,

I'm new to the nuxt-security module and started using it just yesterday. I have a blog with over 1,000 articles, and I use SSG to statically generate the pages, which I then upload to Cloudflare Pages for hosting. Initially, I was testing the configuration in my development environment without any issues. However, upon switching to production, I noticed that the security headers were not being applied.

After checking the logs, I discovered that Cloudflare Pages has a limit of 100 headers, as mentioned on their Limits page.

Here is the error message I encountered:
Error

I currently have about 1,300 header rules, which exceeds the limit.

What can I do to fix this issue?

@Vahagn-Zaqaryan Vahagn-Zaqaryan added the question Further information is requested label Jul 31, 2024
@Baroshem
Copy link
Collaborator

Baroshem commented Aug 1, 2024

Hey there, are you using the http meta equiv for CSP or do you use SSR to send generated response headers?

I honestly don't have that much experience with Cloudflare Pages nor the headers limit.

Maybe @pi0 would be able to share some light on it? :)

@vejja
Copy link
Collaborator

vejja commented Aug 3, 2024

Hi @Vahagn-Zaqaryan
You can use ssg.exportToPresets : false. This will prevent writing header rules into the Cloudflare preset. The downside is that CSP will not be transmitted via headers, but only via http equiv meta tag.
The issue here is that you have 1,000 static pages, so we generate 1,000 different headers rules and this is beyond Cloudflare's limit.

Maybe a better alternative, if you want to keep CSP in headers, is to use the nuxt-security:prerenderedHeaders hook and generate your header rules yourself. I suspect there are not 1,000 different hashes, so probably by inspecting the CSP you will find a way to regroup the policies in a much lower number of rules.
I'm happy to assist you with that task if you give me some details. We could benefit from your use case to improve the way the module generates the rules.

@Baroshem
Copy link
Collaborator

Baroshem commented Aug 9, 2024

@Vahagn-Zaqaryan have you tried the recommendation from @vejja ? :)

@vejja
Copy link
Collaborator

vejja commented Aug 9, 2024

@Vahagn-Zaqaryan have you tried the recommendation from @vejja ? :)

+1
I would be extremely interested in inspecting your rules. The way we generate rules is pretty dumb right now, as evidenced in your Cloudflare logs it’s a file with 21,470 lines…
I’m pretty sure we can largely improve this

@Vahagn-Zaqaryan
Copy link
Author

Hey @Baroshem and @vejja,

I apologize for the delayed response; I've been caught up with some releases! 🎉

I’d like to provide some additional context that might help. My current project is a Nuxt 3 application integrated with a Diectus headless CMS. The route structure mirrors the various content types I’m managing, as outlined below:

src
├── services
│   └── [id]
│       └── [type]
├── categories
│   └── [id]
├── docs
│   └── [slug]
├── articles
│   └── [slug]
├── news
│   └── [slug]
├── [slug]   # Custom pages
├── search
└── index

I used the method @vejja suggested and it worked! However, it appears that http-equiv only works for specific headers, which might limit its effectiveness as a comprehensive solution.

For reference, here is my current nuxt-security configuration:

security: {
  nonce: true,
  headers: {
    xFrameOptions: 'ALLOWALL',
    permissionsPolicy:
      'accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()',
    contentSecurityPolicy: {
      'img-src': ["'self'"],
      'script-src': ["'self'", "'nonce-{{nonce}}'", process.env.NUXT_PUBLIC_APP_URL, 'https://*.cloudflare.com'],
    },
  },
},

Additionally, I’ve taken a closer look at my _headers file this is a part of it. The differences are primarily in the script hashes, especially the first hash, while the remaining headers are the same.

I tried to find the scripts that are causing the discrepancies in the generated headers, but I couldn't, It’s possible these are inline scripts or styles with hashes calculated dynamically during browser execution.

Please let me know if there’s anything else I can provide to help you guys improve the module 🚀

@Baroshem
Copy link
Collaborator

Baroshem commented Sep 9, 2024

@vejja thanks for your great tip. Can we get anything from @Vahagn-Zaqaryan comments and improve the module based on it?

@Vahagn-Zaqaryan
Copy link
Author

@Baroshem and @vejja Thanks a lot for your support! Happy to help make the module better 🚀

For others who might find this issue... I switched to SSR using the Cloudflare Pages but this affected the load time of my website in any case, I'm eagerly waiting for the fixes to be released!

@Baroshem
Copy link
Collaborator

@vejja when you have time :)

@vejja
Copy link
Collaborator

vejja commented Sep 27, 2024

Hi guys, I'd love to find a solution for this one but it doesn't seem like there is an obvious solution.

@Vahagn-Zaqaryan I looked at your _headers file, and there is no common set between the routes that you extracted. I suppose that when you looked at the subfolders and sub-subfolders, there was no common pattern either. So in your case, the headers would be unique for each of the 1,000 pages - which at the end of the day means that we cannot reduce the number of header rules.

With hindsight I think the solution would be to introduce a new value for ssg.exportToPresets such as 'allExceptCSP' where only CSP would be excluded from headers and instead transmitted via http-equiv. This will in any case be complex to implement as we will need some kind of AST resolution algorithm to merge down all other headers into the least common denominator. Any ideas welcome @Baroshem

@Baroshem
Copy link
Collaborator

Thanks for your insight Sebastien.

Looking at the description I think this is quite a lot of work for an edge case so I would recommend not implementing it. Every new code added to the module needs to be maintained by us and maintaining a big and complex code that is used to solve an edge case is not worth for me.

I am up for your comments here as well. Please let me know :)

@vejja
Copy link
Collaborator

vejja commented Sep 27, 2024

We might not need an AST parser after all
Let me think about it again

@vejja vejja added the enhancement New feature or request label Dec 9, 2024
@IO-Fire
Copy link
Contributor

IO-Fire commented Dec 24, 2024

This issue occurred to me as well. I may have a solution, and I'll try to clean it up for release, hopefully today.

@IO-Fire
Copy link
Contributor

IO-Fire commented Dec 25, 2024

Try this proof of concept code from https://github.com/IO-Fire/nitro/compare/v2..feat/cf-gen-headers

It creates proxy Cloudflare (CF) workers at build time. Workers for large / advanced headers rules are the recommended solution from the CF Pages limits documentation.

Workers apply the headers then return the upstream response. It enables SSG on CF Pages with 100+ header rules. It prioritises the header file until it is full.

Set your package.json to include:

{
  // ... the rest of package.json
  
  "pnpm": {
    "overrides": {
      "nitropack": "github:IO-Fire/nitro#feat/cf-gen-headers"
    }
  }
}

Use pnpm install to apply the override.

See initial commit for commit message: IO-Fire/nitro@cbb89ee.

Worker code: https://github.com/IO-Fire/nitro/blob/cbb89ee4f42592451bc5817b43b91b6885164964/src/presets/cloudflare/utils.ts#L391-L433

Reproduction repo coming soon.

TODO: Parse existing _headers to be applied on to workers mentioned in CF Pages Headers. Requires improved parser of _headers. Example: rules in _headers file are not applied to workers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request question Further information is requested
Projects
None yet
Development

No branches or pull requests

4 participants