Problem/Motivation

CKEditor 4 always disallows on* attributes within CKEditor 4. We should implement similar measures in CKEditor 5 to prevent self XSS.

Proposed resolution

Make Drupal\ckeditor5\HTMLRestrictions disallow on* and style attributes.

Remaining tasks

Postponed on #3231334: Global attributes (<* lang> and <* dir="ltr rtl">): validation + support (fix data loss)

  • Tests
  • Validation constraint
  • Review

User interface changes

A validation error will show up in the CKE5 admin UI if you attempt to configure Source Editing to explicitly allow one of these insecure attributes.

API changes

None.

Data model changes

None.

Issue fork drupal-3228691

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

lauriii created an issue. See original summary.

Wim Leers’s picture

Make Drupal\ckeditor5\HTMLRestrictionsUtilities disallow on* attributes.

I think there's actually two parts:

  1. Disallow configuring sourceEditing to allow on*, style or any of the tags in \Drupal\editor\EditorXssFilter\Standard. This will require just a validation constraint, nothing needs to change in HTMLRestrictionsUtilities AFAICT.
  2. Disallow it for the "arbitrary HTML" scenario by changing
    ckeditor5_htmlSupport:
      ckeditor5:
    …
        config:
          htmlSupport:
            allow:
              -
                name:
                  regexp:
                    pattern: /.*/
                attributes: true
                classes: true
      drupal:
        …
    

    to disallow style and on* and …

Or … what is more likely … I am missing something. Because what I'm saying is very different from what's the proposed resolution in the IS :P

Wim Leers’s picture

Assigned: Unassigned » lauriii
Status: Active » Postponed (maintainer needs more info)
lauriii’s picture

For feature parity with CKEditor 4, we don't have to do the second step. See Drupal\ckeditor\Plugin\CKEditorPlugin\Internal::generateACFSettings which confirms that CKEditor 4 is configured to disallow certain attributes only when HTML restrictor exists. CKEditor 4 full HTML text formats allow using both style and on* attributes. For that reason full HTML text formats are documented as unsafe in various different places including https://www.drupal.org/docs/core-modules-and-themes/core-modules/filter-....

Wim Leers’s picture

Status: Postponed (maintainer needs more info) » Active

CKEditor 4 full HTML text formats allow using both style and on* attributes. For that reason full HTML text formats are documented as unsafe in various different places including https://www.drupal.org/docs/core-modules-and-themes/core-modules/filter-....

Ah, good point!

But those special tags would still get stripped by the text editor XSS filtering… Did a deep dive, and confirmed that @lauriii's comment in #4 is accurate! See \editor_filter_xss(), which contains this:

  // If there is no filter preventing XSS attacks in the text format being used,
  // then no text editor XSS filtering is needed either. (Because then the
  // editing user can already be attacked by merely viewing the content.)
  // e.g.: an admin user creates content in Full HTML and then edits it, no text
  // format switching happens; in this case, no text editor XSS filtering is
  // desirable, because it would strip style attributes, amongst others.
  $current_filter_types = $format->getFilterTypes();
  if (!in_array(FilterInterface::TYPE_HTML_RESTRICTOR, $current_filter_types, TRUE)) {
    if ($original_format === NULL) {
      return FALSE;
    }
…

Perfect!

Wim Leers’s picture

lauriii’s picture

Assigned: lauriii » Unassigned
Wim Leers’s picture

Title: Restrict allowed additional attributes to prevent self XSS » [PP-1] Restrict allowed additional attributes to prevent self XSS
Project: CKEditor 5 » Drupal core
Version: 1.0.x-dev » 9.3.x-dev
Component: Code » ckeditor5.module
Status: Active » Postponed
Related issues: +#3228334: Refactor HTMLRestrictionsUtilities to a HtmlRestrictions value object

This should wait for #3228334: Refactor HTMLRestrictionsUtilities to a HtmlRestrictions value object to finish; that will make this simpler.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Wim Leers’s picture

Title: [PP-1] Restrict allowed additional attributes to prevent self XSS » Restrict allowed additional attributes to prevent self XSS
Issue summary: View changes
Status: Postponed » Needs review
Related issues: +#3260857: Expand SourceEditingRedundantTagsConstraintValidator to also check attributes and attribute values
FileSize
3.2 KB

#3228334: Refactor HTMLRestrictionsUtilities to a HtmlRestrictions value object is in!

Re-reading this, my analysis in #2 is kinda wrong. The second point is indeed not necessary like @lauriii pointed out in #4. Because CKEditor 5 does not able to restrict things, because it only is able to allow extra things! I see I already realized this in #5 :P

So what we need is something like this.

Related: #3260857: Expand SourceEditingRedundantTagsConstraintValidator to also check attributes and attribute values.

Wim Leers’s picture

Tests added in https://git.drupalcode.org/project/drupal/-/merge_requests/1933/diffs?co...

Logic also implemented. Tests should pass. Ready for review! 😊

Wim Leers’s picture

Issue summary: View changes
Wim Leers’s picture

Having just reviewed #3261600: Update to CKEditor5 v32.0.0, I was reminded of #3245950: [upstream] <script> tag support in GHS.

Which makes me wonder if we should make this behave differently than what the issue originally described:

  1. on formats with no HTML restrictions (FilterFormat::getHtmlRestrictions() === FALSE), don't do this validation, but instead disallow configuring anything at all — everything is already allowed anyway, so no need to configure explicit additional tags/attributes
  2. on formats with HTML restrictions, do perform this validation … but also disallow <script> and <style>. But then where does it stop — perhaps also <iframe> and <embed> should be forbidden? We should allow anything the user wants, unless it is going to be stripped by the filters, which brings me to my next point:
  3. Instead of hardcoding things (style and on*), use the restrictions that the text format itself provides! \Drupal\filter\Plugin\Filter\FilterHtml::getHTMLRestrictions() contains:
        // The 'style' and 'on*' ('onClick' etc.) attributes are always forbidden,
        // and are removed by Xss::filter().
        // The 'lang', and 'dir' attributes apply to all elements and are always
        // allowed. The list of allowed values for the 'dir' attribute is enforced
        // by self::filterAttributes(). Note that those two attributes are in the
        // short list of globally usable attributes in HTML5. They are always
        // allowed since the correct values of lang and dir may only be known to
        // the content author. Of the other global attributes, they are not usually
        // added by hand to content, and especially the class attribute can have
        // undesired visual effects by allowing content authors to apply any
        // available style, so specific values should be explicitly allowed.
        // @see http://www.w3.org/TR/html5/dom.html#global-attributes
        $restrictions['allowed']['*'] = [
          'style' => FALSE,
          'on*' => FALSE,
          'lang' => TRUE,
          'dir' => ['ltr' => TRUE, 'rtl' => TRUE],
        ];
    

    That is declaring "disallow the style and on* attributes" already! We should probably just interpret that?!

    Automatically interpreting the text format's HTML restrictions would currently result in InvalidArgumentException: "*" is not a valid HTML tag name. in Drupal\ckeditor5\HTMLRestrictions::validateAllowedRestrictionsPhase1() (line 113 of core/modules/ckeditor5/src/HTMLRestrictions.php). though, so I'd like confirmation first that we indeed want to do this. Because it requires removing this:

        // @todo Validate attributes allowed or forbidden on all elements
        //   https://www.drupal.org/project/ckeditor5/issues/3231334.
        if (isset($allowed['*'])) {
          unset($allowed['*']);
        }
    

    and hence we'd need to do #3231334: Global attributes (<* lang> and <* dir="ltr rtl">): validation + support (fix data loss) first.

lauriii’s picture

It seems like the ideal solution would be to interpret the wildcard tags. Should we mark this as postponed on #3231334: Global attributes (<* lang> and <* dir="ltr rtl">): validation + support (fix data loss) then?

Wim Leers’s picture

Title: Restrict allowed additional attributes to prevent self XSS » [PP-1] Restrict allowed additional attributes to prevent self XSS
Status: Needs review » Postponed

+1. I'll start that.

catch’s picture

Issue summary: View changes
Wim Leers’s picture

Title: [PP-1] Restrict allowed additional attributes to prevent self XSS » Restrict allowed additional attributes to prevent self XSS
Assigned: Unassigned » Wim Leers
Priority: Normal » Major
Status: Postponed » Active
Wim Leers’s picture

Assigned: Wim Leers » Unassigned
Status: Active » Needs review

#14 has now been implemented! 🤓👍 Ready for review again!

Wim Leers’s picture

And that was the very final piece, a @todo referring to #3260869: Resolve mismatch between <$block> interpretation by CKEditor 5 and Drupal, also is done — because #3260869 landed a while ago :)

nod_’s picture

Status: Needs review » Reviewed & tested by the community

Added a comment for a small detail, other than that it makes sense, test look good, and works in manual testing too.

Wim Leers’s picture

Wim Leers’s picture

(The 9.3.x failures are expected: they happen because #3231334: Global attributes (<* lang> and <* dir="ltr rtl">): validation + support (fix data loss) has not yet been cherry-picked to 9.3.x.)

bnjmnm’s picture

  • bnjmnm committed 5127c3f on 10.0.x
    Issue #3228691 by Wim Leers, lauriii, nod_: Restrict allowed additional...

  • bnjmnm committed 0388920 on 9.4.x
    Issue #3228691 by Wim Leers, lauriii, nod_: Restrict allowed additional...

  • bnjmnm committed 70095f3 on 9.3.x
    Issue #3228691 by Wim Leers, lauriii, nod_: Restrict allowed additional...
bnjmnm’s picture

Version: 9.4.x-dev » 9.3.x-dev
Status: Reviewed & tested by the community » Fixed

Committed to 10.0.x and cherry-picked to 9.4.x and 9.3.x (9.3 backport since CKEditor5 is experimental and making a module more secure oughta go anywhere it can).

Status: Fixed » Closed (fixed)

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