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

Inline JavaScript cannot run in secure CSP environment #592

Open
2 tasks done
sxp-dalibor opened this issue Dec 18, 2024 · 2 comments
Open
2 tasks done

Inline JavaScript cannot run in secure CSP environment #592

sxp-dalibor opened this issue Dec 18, 2024 · 2 comments
Assignees

Comments

@sxp-dalibor
Copy link

  • I've read and understood the contribution guidelines.
  • I've searched for any related issues and avoided creating a duplicate issue.

Please give us a description of what happened.

  1. When clicking the "This page is cornerstone content" checkbox in page properties, the "onclick" event is blocked by browser
  2. When opening the "Dashboard" view of Yoast SEO, inline script execution is blocked by browser

Please describe what you expected to happen and why.

Inline javascript should load even when "unsafe-inline" keyword is not used for "script-src" CSP directive.

How can we reproduce this behavior?

  1. Set CSP of your website to "script-src 'self' 'nonce-xxxxxx' 'report-sample';" - important is to avoid using "unsafe-inline" keyword
    e.g. by new Mutation(MutationMode::Extend, Directive::ScriptSrc, SourceKeyword::nonceProxy);
  2. Open page properties
  3. Click the SEO tab
  4. Click "This page is cornerstone content" checkbox
  5. Check the browser console for errors
  6. Open Dashboard module of Yoast SEO
  7. Check the browser console for errors

Screenshots

Cornerstone:
image
Dashboard:
image

Logs

  • cornerstone error:
    Refused to execute inline event handler because it violates the following Content Security Policy directive: "script-src 'self' 'nonce-xxxxxx' 'report-sample'". Either the 'unsafe-inline' keyword, a hash ('sha256-...'), or a nonce ('nonce-...') is required to enable inline execution. Note that hashes do not apply to event handlers, style attributes and javascript: navigations unless the 'unsafe-hashes' keyword is present.
  • dashboard error:
    Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self' 'nonce-xxxxxx' 'report-sample'". Either the 'unsafe-inline' keyword, a hash ('sha256-gEzJUB0p/Xhcm6iFYd0HSLC+0pk6EYlbyYEfrtTGaNI='), or a nonce ('nonce-...') is required to enable inline execution.

How to fix

Cornerstone:

  • File: /Resources/Private/Templates/TCA/Cornerstone.html
  • Replace:
    <input id="{data.elementBaseName}" type="checkbox" data-formengine-input-name="data{data.elementBaseName}" value="1" {f:if(condition: data.databaseRow.tx_yoastseo_cornerstone, then: 'checked="checked"')} onclick="document.editform['data{data.elementBaseName}'].value=this.checked?(document.editform['data{data.elementBaseName}'].value|1):(document.editform['data{data.elementBaseName}'].value&0);TBE_EDITOR.fieldChanged('{data.tableName}','{data.vanillaUid}','{data.fieldName}','data{data.elementBaseName}');">
  • With:
    <input id="{data.elementBaseName}" type="checkbox" data-formengine-input-name="data{data.elementBaseName}" value="1" {f:if(condition: data.databaseRow.tx_yoastseo_cornerstone, then: 'checked="checked"')}> <f:asset.script identifier="cornerstone_checkbox_handler" useNonce="true"> document.getElementById("{data.elementBaseName}").addEventListener("click", function(event) { const checkBoxElement = event.target; document.editform['data{data.elementBaseName}'].value=checkBoxElement.checked?(document.editform['data{data.elementBaseName}'].value|1):(document.editform['data{data.elementBaseName}'].value&0); checkBoxElement.dispatchEvent(new Event('change', {bubbles: true, cancelable: true})); }); </f:asset.script>

Dashboard:

  • File: /Resources/Private/Partials/Dashboard/View.html
  • Replace
    <script type="text/javascript">(function($) {window.fnames = new Array(); window.ftypes = new Array();fnames[0]=‘EMAIL’;ftypes[0]=‘email’;fnames[1]=‘LBTITLE’;ftypes[1]=‘text’;fnames[2]=‘LBADTEXT’;ftypes[2]=‘text’;fnames[3]=‘LBADLINK’;ftypes[3]=‘text’;fnames[4]=‘LBIMAGEURL’;ftypes[4]=‘text’;fnames[5]=‘LBPIXEL’;ftypes[5]=‘text’;fnames[6]=‘LAUNCHBIT’;ftypes[6]=‘text’;fnames[7]=‘NAME’;ftypes[7]=‘text’;fnames[8]=‘FIRST_TIME’;ftypes[8]=‘text’;}(jQuery));var $mcj = jQuery.noConflict(true);</script>
  • With
    <f:asset.script identifier="yoast-dashboard-view" useNonce="true"> (function($) {window.fnames = new Array(); window.ftypes = new Array();fnames[0]='EMAIL';ftypes[0]='email';fnames[1]='LBTITLE';ftypes[1]='text';fnames[2]='LBADTEXT';ftypes[2]='text';fnames[3]='LBADLINK';ftypes[3]='text';fnames[4]='LBIMAGEURL';ftypes[4]='text';fnames[5]='LBPIXEL';ftypes[5]='text';fnames[6]='LAUNCHBIT';ftypes[6]='text';fnames[7]='NAME';ftypes[7]='text';fnames[8]='FIRST_TIME';ftypes[8]='text';}(jQuery));var $mcj = jQuery.noConflict(true); </f:asset.script>

Technical info

  • TYPO3 version: 13.4.0
  • Yoast SEO version: 10.0.0
  • Relevant extensions in case of a bug: headless
@schliesser
Copy link
Contributor

schliesser commented Jan 27, 2025

Heyho @RinyVT

The dashboard is not working in my instance also. Fresh TYPO3 13 installations enforce CSP headers in the backend by default.

I've tried to simply add the dashboard hash with a policy (see code below), to not to touch any of your extension files.
But the inline JS itself fails?!?:

Image

Image

Configuration/ContentSecurityPolicies.php

<?php

declare(strict_types=1);

use TYPO3\CMS\Core\Security\ContentSecurityPolicy\Directive;
use TYPO3\CMS\Core\Security\ContentSecurityPolicy\HashValue;
use TYPO3\CMS\Core\Security\ContentSecurityPolicy\Mutation;
use TYPO3\CMS\Core\Security\ContentSecurityPolicy\MutationCollection;
use TYPO3\CMS\Core\Security\ContentSecurityPolicy\MutationMode;
use TYPO3\CMS\Core\Security\ContentSecurityPolicy\Scope;
use TYPO3\CMS\Core\Type\Map;

return Map::fromEntries([
    Scope::backend(),
    new MutationCollection(
        new Mutation(
            MutationMode::Extend,
            Directive::ScriptSrc,
            new HashValue('gEzJUB0p/Xhcm6iFYd0HSLC+0pk6EYlbyYEfrtTGaNI='),
        ),
    ),
]);

I think nonces are the best way to use with inline JS like @sxp-dalibor suggested.

@RinyVT
Copy link
Collaborator

RinyVT commented Jan 29, 2025

Hi,

Thanks for raising this issue!
I have fixed these issues in my feature branch for the next release, I hope to release it soon.

The solution was a bit different as mentioned since the useNonce attribute in the f:asset.script viewhelper is not available in v11 (which we still support) but it's working now.

@RinyVT RinyVT self-assigned this Jan 29, 2025
@RinyVT RinyVT mentioned this issue Feb 4, 2025
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants