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

The RCs break Turnstile with default configuration for nuxt-security #470

Closed
hermes85pl opened this issue Jun 3, 2024 · 17 comments · Fixed by #483
Closed

The RCs break Turnstile with default configuration for nuxt-security #470

hermes85pl opened this issue Jun 3, 2024 · 17 comments · Fixed by #483
Assignees
Labels
bug Something isn't working

Comments

@hermes85pl
Copy link

hermes85pl commented Jun 3, 2024

Version

nuxt-security: 2.0.0-rc.6
nuxt: 3.11.2

Reproduction Link

Steps to reproduce

What is Expected?

Any site using Turnstile should just work after adding nuxt-security with default configuration, as stated in the docs.

What is actually happening?

Refused to frame '<URL>' because it violates the following Content Security Policy directive: "frame-src 'self'".

@hermes85pl hermes85pl added the bug Something isn't working label Jun 3, 2024
@Baroshem
Copy link
Owner

Baroshem commented Jun 3, 2024

Hey, could you provide a reproduction or more details? I dont know how to help right now :(

@hermes85pl
Copy link
Author

Using Turnstile requires some configuration, including a private key, however having a demo of it, you can add nuxt-security in version 2.0.0-beta.5 (with no custom configuration) to see that it still works, and then switch to e.g. 2.0.0-rc.6 (the latest as of now, however earlier ones are broken too) to see that it no longer works, as it just hangs instead.

The browser's console says:
Refused to frame '<URL>' because it violates the following Content Security Policy directive: "frame-src 'self'".

The above error is then followed by other errors related to Turnstile Widget crashing.

@vejja
Copy link
Collaborator

vejja commented Jun 3, 2024

@hermes85pl you are right.

  • The console tells you that you need to modify Content-Security-Policy:
    Capture d’écran 2024-06-03 à 22 39 36
  • And then that you need to modify Permissions-Policy
    Capture d’écran 2024-06-03 à 22 41 31

Therefore the following security configuration:

security: {
  headers: {
    contentSecurityPolicy: {
      'frame-src': ["'self'", "https://challenges.cloudflare.com"]
    },
    permissionsPolicy: {
      'picture-in-picture': ['self', '"https://challenges.cloudflare.com"']
    }
  }
}

@Baroshem : We now have a much stricter CSP default policy. We used to allow by default, whereas we now deny by default.
I do believe this is the compliant way to secure the application, however I recognize this is tough on the average user.
What do you think? Are we too strict ?

@hermes85pl
Copy link
Author

hermes85pl commented Jun 3, 2024

@vejja, indeed, this is what I expected after looking at the error and the comments to the releases that you were making in the recent days. Still, this is not in line with the documentation that you provide, but rather against it. If this is not a bug and the change is intentional, I would expect the documentation to be updated with this and similar examples for popular use cases.

Personally I do understand that this strict approach that you have taken is safer, easier, and cleaner to implement. At the same time, one could argue that other popular Nuxt modules, including those related to security, could be recognized by the module and just work, as the domains that they need to connect to are not expected to pose threats. Or somebody could add similar dependencies on such popular external resources on their own, and that could be taken into account too for some of the most popular services. Otherwise the changes in documentation would be needed, as I explained above, and although I would be fine with this approach, I would expect some to get lost and complain, and they would have some valid reasons too.

In any case, and especially for the less popular services (even if there is some white-listing for popular services/modules), there should be a generic example and a step-by-step approach to take when the nuxt-security module breaks an app after being added to it. Hopefully easy enough to follow, not to discourage the potential audience of this module from using it.

If this change is intentional, surely it is bold and changes the developer experience from the one that you used to advertise (even after you update the docs).

Other than that, I would like to add that I appreciate your work and effort to make Nuxt apps safer for everyone 🙂

@vejja
Copy link
Collaborator

vejja commented Jun 3, 2024

@hermes85pl Thanks for your comments

although I would be fine with this approach, I would expect some to get lost and complain

I fully agree.
It's a tough call: security vs useabiity.
History shows that when security is too complex, people decide that they won't implement it. So the outcome of being too strict is usually the opposite of the initial purpose.

@hermes85pl
Copy link
Author

History shows that when security is too complex, people decide that they won't implement it.

Funny thing, as you were writing it, I was editing my last comment to reflect that 😉

@hermes85pl
Copy link
Author

So the outcome of being too strict is usually the opposite of the initial purpose.

How about an easy switch then, and the two approaches mentioned on the main page of the module, with a direct link to some docs regarding how to properly employ the strict policy, with examples? Hopefully this way the module would be both easy to adopt for those less interested in the topic of security, and useful and more approachable to those who prefer more control.

@vejja
Copy link
Collaborator

vejja commented Jun 3, 2024

That's a possible solution. We could have 2 modes, one with minimum security settings (similar to v1) which ensures that the application won't be blocked; and another one with maximum security settings (OWASP/MDN recommended values) with guidance on which options are likely to need modifications.

Although eventually we will need to define which one is the default one. So maybe we want to come back to the more relaxed settings of v1 anyways, and instead provide examples in the docs on how to increase strength from that basis.

@Baroshem
Copy link
Owner

Baroshem commented Jun 4, 2024

Hey guys,

Thanks for the discovery and research for this topic. I do agree that based on this example we should update the documentation to the latest state.

In terms of reverting the module to the previous security recommendations, I would be against it. I really love the work you did @vejja on making the application as secure as possible and I would like to keep it this way. I understand the reasoning for not pushing too much on the user but I would focus on providing guides like FAQ on what needs to be done to make a feature work rather than lowering the security by everyone and expect that they will go through the docs and implement all our recommendations by themselves.

If we consider this, then the module is not needed at all because all recomendations are available on the internet, just not in the vue/nuxt form 😉

In summary, I would update the documentation to march the current security recommendations state and provide guides in FAQ that are easily searchable for the problems found by @hermes85pl . This way we would keep the better security by default we wanted for version 2.0.0 and resolve issues with third party services (as they are not that difficult)

Would that make sense to you guys? :)

@hermes85pl
Copy link
Author

Like I mentioned previously, I would be fine with this approach too, as long as the implementation and the docs are coherent and I have a clear situation on what is going on and what to do.

On the other hand, I am afraid that there will always be a group of people who don't know (or even want to know) much about security and would consider using this module by adding it to their project given the module's promise to "just work", and if it gets cumbersome, they would just remove it.

I believe that those who care about the topic will set up the configuration anyway, and I am just a bit afraid about the rest. And I would like a safer web for everyone, even those who do not care, and I used to think that this is what this module is about.

In any case, once again thank you guys for making this great module 🙂

@Baroshem
Copy link
Owner

Baroshem commented Jun 4, 2024

We discussed it internally with @vejja and we think that we could revert this change.

From what I understood the change is not that significant if we want to be 100% owasp accurate while we will block several features like scripts, images, domains etc.

@vejja could you update @hermes85pl with your findings?

Also, thanks @hermes85pl for your input. It was really important for us :)

@vejja
Copy link
Collaborator

vejja commented Jun 4, 2024

Yes, so as you suggested @hermes85pl we could go for an opt-in switch :

  • With settingsMode: 'compatibility' (default value), the default settings would 'always work' (similar to v1)
  • With settingsMode: 'security', the default settings would prioritize higher security (OWASP/Mozilla recommendations)

This should provide maximum backwards compatibility with v1, avoiding any breaking change.

Opting-in to 'security' might require additional expert knowledge on how to modify Content Security Policy, Permissions Policy and Cross-Origin Isolation.
We would cover this in a dedicated section in the docs, together with practical examples. We could also use our own documentation codebase to illustrate how we deploy with 'security' mode.

Based on estimates, 'compatibility' mode would give a 110/100 score on the Mozilla scanner, while 'security' mode would achieve a 120/100 score. Both are rated A+.

Note: The 'settingsMode' name is only an illustrative suggestion here

@Baroshem
Copy link
Owner

Baroshem commented Jun 7, 2024

I wonder if adding this settingsMode should be done by us.

We should ship the most secure config as possible. If there is an option how to achieve the 120 score with a more secure config, I would instead provide docs on how to do it instead of providing another config option that would require us to maintain it.

So in summary, I would instead revert to the previous state of the default config so that majority of the users could still use the moduel the way it was but provide some docs on how to make it 120/100.

WDYT?

@hermes85pl
Copy link
Author

I understand "having a mode to choose from" as "having different sets of default configuration to choose from". Coming from there, I wonder how much more maintenance work would be required by having to maintain another set of documentation compared to having to maintain a part of documentation that provides information on what to change and how in order to further improve security, as @Baroshem suggested.

For the users of the module, choosing a mode would be a matter of convenience on setup (like a shortcut, or concise form of settings), but also on update (as the recommendations may change in time, along with the support for certain features across different browsers). However, this may be both beneficial (I perform an update and I know that my app follows the latest or some recent recommendations) as well as problematic at times (I perform an update and something stops working because of some restriction being added). To address the latter case, the documentation about the modes should warn about such a possibility and suggest updating the module with care in case such a restrictive mode is chosen.

Personally, as a user of the module, I would be fine with both approaches (i.e. modes or just a dedicated section in the docs), as long as the default default configuration just works™️. I wonder what other users would say though.

@moshetanzer
Copy link
Contributor

Leave as is imho. Console error is clear enough. Really not worth the effort and confusion. Another 20 PR's are going to be created with what should and shouldn't be included in each of these settings.

@vejja vejja self-assigned this Jun 26, 2024
vejja added a commit that referenced this issue Jun 26, 2024
<!--- Provide a general summary of your changes in the title above -->

Closes #470

## Types of changes
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
- [ ] Bug fix (a non-breaking change which fixes an issue)
- [x] New feature (a non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)

## Description
<!--- Describe your changes in detail -->
<!--- Why is this change required? What problem does it solve? -->
<!--- If it resolves an open issue, please link to the issue here. For example "Resolves: #137" -->

This PR adds a new `owaspDefaults` option, which can take 2 possible values:
- `compatibility` (default): OWASP default settings are chosen to minimize the possibility of breaking the app. These default values are the same as in v1.
- `security`: OWASP default settings are chosen to maximize security. These default values will usually require some additional fine-tuning to ensure the app will run smoothly.

With `security` OWASP level, the following headers are modified:
1- `contentSecurityPolicy` blocks everything by default with `default-src: 'none'`. In addition, all `'unsafe-inline'` values are removed.
2- `crossOriginEmbedderPolicy` is set to `require-corp`
3- `strictTransportSecurity` has the `preload` flag
4- 'xFrameOptions` is set to `DENY`

## Checklist:
<!--- Put an `x` in all the boxes that apply. -->
<!--- If your change requires a documentation PR, please link it appropriately -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
- [x] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly.
- [x] I have added tests to cover my changes (if not applicable, please state why)
@vejja
Copy link
Collaborator

vejja commented Jun 27, 2024

@hermes85pl implementation proposal in #483

@Baroshem
Copy link
Owner

Published in 2.0.0-rc.9 :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants