Modules will likely need to specify additional domains that don't appear in a *.libraries.yml file.

E.g.
- A local JavaScript file that makes calls to a remote API
- A third party widget that calls a separate domain than the one it is loaded from for data
- Web fonts that may only be specified within a CSS file

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

gapple created an issue. See original summary.

gapple’s picture

Issue summary: View changes
gapple’s picture

Version: » 8.x-1.x-dev

Maybe it is possible to just add another attribute to the library info in *.libraries.yml, and hook_library_info_alter can be used where dynamic values are required.

e.g.

testlib:
  version: 1.x
  js:
    https://cdn.example.com/js/libtest.js: {}
  content-security-policy:
    connect-src: https://api.example.com

would result in Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; connect-src 'self' https://api.example.com

gapple’s picture

Due to CKEditor's reliance on 'unsafe-inline' (#2942401: CKEditor is broken without 'unsafe-inlne'), I think there may be a need for both global and request-specific alterations, though request-specific alterations should probably be discouraged.
This would allow only adding 'unsafe-inline' to pages which include the core/ckeditor library.

gapple’s picture

Title: API for modules to add dynamic properties » API for modules to add additional global properties
gapple’s picture

Status: Active » Needs review
FileSize
3.95 KB

This patch parses an additional content-security-policy key in the library info, and uses hook_library_info_alter to add the necessary directives to core libraries (ckeditor and umami).

gapple’s picture

For some directives, a module may also want to add sources without modifying a library.
e.g. child-src, img-src, object-src, media-src, prefetch-src, frame-ancestors, form-action, navigate-to

Ambient.Impact’s picture

Hi there. Any chance of this making it into a stable release sometime soon?

gapple’s picture

Category: Task » Feature request
Status: Needs review » Needs work

Since I think an event will be necessary to control non-library based sources anyways, I currently prefer that approach and not duplicating the same functionality with the current patch's library-based declaration.

Ambient.Impact’s picture

Yeah, generalizing it via an event and not hard-coding the libraries in that way makes a lot of sense.

gapple’s picture

Status: Needs work » Needs review
FileSize
4.15 KB

Here's an initial patch to add a csp.alter event. The event is called for each policy, so a page that implements both a report-only and enforced policy will have the event called twice.

I would like to also implement a default listener for the Umami profile before committing.

Ambient.Impact’s picture

Let me know if you'd like me to test it or contribute anything.

gapple’s picture

Title: API for modules to add additional global properties » API for modules to alter policy

If you have any particular use-cases for this API you could share, that would be helpful to determine if it will sufficiently meet real-world needs.

And general testing / feedback is always welcome.

gapple’s picture

The current use-cases I'm trying to cover:

- Adding script-src 'unsafe-inline'; script-src-attr 'unsafe-inline' when ckeditor is added to a page
- Adding font-src https://fonts.gstatic.com when umami adds Google fonts onto the page (CSS is automatically allowed by library parsing)
- Attach Inline module #3095521: Provide Content Security Policy hashes

gapple’s picture

Changes in this patch

- Make event's name a little move verbose.
- The event object now contains the relevant response object, which allows inspecting the response's attached libraries.
- Csp previously wasn't introspectable - add methods to retrieve directive values. This may be important in cases such as using hashes, which override 'unsafe-inline', so an alter may need to skip adding hashes if the policy already includes 'unsafe-inline'.
- When a page's policy is initially generated, directives configured with the base value n/a are added with an empty value. Directives which don't have any values after being altered are removed from the output header value. This will allow an alter implementation to differentiate which directives have been enabled in configuration.

----

Some thoughts so far:

In the case of Umami, the domain for Google Font API's CSS is added to every page's style-src (even if not used on the page), but the font domain is only added when a font library is actually attached to the page. This gives the alter event two possibilities:
1. Always add the font-src directive, even if not enabled in config. If the site expects font-src to not be enabled, this could break functionality until enabled in config with sufficient defaults.
2. Only add the domain if font-src (or default-src) is enabled in config. In this case it may not be clear to the user why font-src is not being applied.
There is no indication in the configuration page that font-src should be enabled with a reasonable default for theses dynamic properties to be applied.

If Inline Attach blindly adds hashes, it could break ckeditor since adding any hash or nonce overrides the script-src 'unsafe-inline' that ckeditor requires. In this case I think the only option is to skip adding hashes if 'unsafe-inline' is already present in the policy. (hashes could still be added to script-src-elem and be compatible with ckeditor).

As noted in a comment in the patch, the Response object's attached libraries list does not include any dependencies. This causes a bit of a problem for ckeditor because the root library that requires the alter is core.ckeditor but it's only a dependency of other libraries that are included on the page (e.g. ckeditor/drupal.ckeditor).
I'm hoping the method core uses to resolve those dependencies is publicly accessible. Maybe the fully resolved set of libraries should be added as a property on the event so that each alter implementation doesn't have to repeat the resolution.

This per-response event is not mutually exclusive with the previous library definition property, or another event to collect defaults which should appear in the "Auto Sources" on the configuration page and are applied to all responses. It may be better to use one of these for things like Umami's use of Google Font API where per-response changes aren't really beneficial.

gapple’s picture

FileSize
9.32 KB

Oops, forgot the patch

Ambient.Impact’s picture

If you have any particular use-cases for this API you could share, that would be helpful to determine if it will sufficiently meet real-world needs.

My use case for the time being is the CKEditor requirement of script-src 'unsafe-inline'. I'd love to not have that on pages where CKEditor is not present, at least until core updates to CKEditor 5, which apparently does away with this requirement.

I'll give the patch a try when I get a chance and will let you know.

Ambient.Impact’s picture

First thoughts: while implementing the event subscriber, I noticed that the documentation in the patch refers to an AlterEvent class but the actual class name is PolicyAlterEvent.

I've got a subscriber set up now, but I'm wondering what the best way to check if CKEditor is attached would be? I've found \Drupal\Core\Asset\AttachedAssetsInterface::getLibraries(), but I'm having trouble figuring what service I need to inject into the event subscriber to query what libraries are attached.

gapple’s picture

CoreCspSubscriber::onCspPolicyAlter() handles alterations for core modules (including CKEditor), and is a good example implementation.
Drupal's HtmlResponse class implements Drupal\Core\Render\AttachmentsInterface, which provides the getAttachments() method for retrieving an array of all libraries / drupalSettings added to the response. As I noted in a previous comment, the list of libraries does not include any dependencies, so the list may need to be passed to LibraryDependencyResolver::getLibrariesWithDependencies().

gapple’s picture

FileSize
6.77 KB
12.38 KB

Some smaller changes in this patch:

- Configuration form previously wouldn't save a directive as enabled without any values (except for script/style, due to values retrieved from libraries), preventing alter implementations from being able to tell the difference between a disabled and enabled but empty directive.
- Add LibraryDependencyResolver service to CoreCspSubscriber to allow checking against full list of libraries included in response.
- CoreCspSubscriber handles case where default-src is defined, but script-src is not, by duplicating the default policy, making any necessary additions, and then applying it to script-src
- #2952390: Off-canvas styles override CKEditor's reset and theme Introduced the need for style-src-elem 'unsafe-inline' when CKEditor is included on the page, so this is also handled.

Ambient.Impact’s picture

🤦‍♀ Of course you already took care of the core CKEditor stuff. For some reason I assumed I'd have to implement that myself. :P

On first glance, this seems to be working correctly for the CKEditor stuff, at least in my local dev copy of my site.

gapple’s picture

FileSize
18.79 KB
7.57 KB

Mostly code style fixes, but also:
- Remove script-src 'unsafe-inline' from the default config on module install. An update should not be applied to existing sites since something other than ckeditor may also rely on it.
- Fix ResponseCspSubscriber tests, which weren't injecting the now required event dispatcher service

gapple’s picture

I think this is the last patch

- Refactor setting directives for CKEditor if fallback directive is defined (e.g. duplicate and modify default-src to script-src)
- Added test class for CoreCspSubscriber
- Added test to ResponseCspSubscriberTest that alter event is dispatched with expected configuration.

gapple’s picture

FileSize
31.42 KB
15.18 KB

🤦‍♂️

gapple’s picture

I think the IE9 compatibility code should also be moved to an alter implementation - this will clean up the response subscriber a little bit.

Drupal 8.8 is schedule for release on Dec 4, and 8.6 (the last version of core to include the IE9 CSS workaround) will also then lose security support. CSP could:
- Keep check for Drupal version, but remove corresponding tests (that never get executed in Drupal CI)
- Remove Drupal version check and rely on presence of IE9 module for enabling compatibility.
- Move compatibility alter event to IE9 module

I've created #3098049: Move IE9 Compatibility code as a followup to this issue.

Ambient.Impact’s picture

#24 seems to be working for me at first glance!

Ambient.Impact’s picture

Hmm. Seems I'm getting an Ajax error now whenever I try to save a link in the CKEditor link dialogue. Are you getting this as well, or could it be something unrelated on my end?

gapple’s picture

FileSize
32.1 KB
2.2 KB

Thanks for catching that. Looks like AjaxResponse implements AttachmentsInterface, but in this case returns an empty array.

Ambient.Impact’s picture

The updated patch seems to have fixed it, thanks!

  • gapple committed 8e5ebe7 on 8.x-1.x
    Issue #2895245: Implement event for modules to alter policy
    
gapple’s picture

Status: Needs review » Fixed
Ambient.Impact’s picture

Thanks for your awesome work! Just installing the new stable release now.

Ambient.Impact’s picture

Upon further testing, I'm unable to open any any dialogs in the Views UI if I have script-src disabled, and am getting CSP errors in the console that inline JavaScript was blocked. Am I doing something wrong, or is the policy not accounting for Views UI pages? This is under 8.8.0 core and CSP 8.x-1.6, by the way.

gapple’s picture

I've opened #3100068: Script/style included in AJAX responses blocked without 'unsafe-inline' - so far it looks like this may be an issue with an AJAX response trying to inject a script element into the page.

Ambient.Impact’s picture

Excellent, thanks!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.