public function EditorSecurityTest::testSwitchingSecurity in Drupal 9
Same name and namespace in other branches
- 8 core/modules/editor/tests/src/Functional/EditorSecurityTest.php \Drupal\Tests\editor\Functional\EditorSecurityTest::testSwitchingSecurity()
Tests administrator security: is the user safe when switching text formats?
Tests 24 scenarios. Tests only with a text editor that is not XSS-safe.
When changing from a more restrictive text format with a text editor (or a text format without a text editor) to a less restrictive text format, it is possible that a malicious user could trigger an XSS.
E.g. when switching a piece of text that uses the Restricted HTML text format and contains a <script> tag to the Full HTML text format, the <script> tag would be executed. Unless we apply appropriate filtering.
File
- core/
modules/ editor/ tests/ src/ Functional/ EditorSecurityTest.php, line 305
Class
- EditorSecurityTest
- Tests XSS protection for content creators when using text editors.
Namespace
Drupal\Tests\editor\FunctionalCode
public function testSwitchingSecurity() {
$expected = [
[
'node_id' => 1,
// No text editor => no XSS filtering.
'value' => self::$sampleContent,
'format' => 'restricted_without_editor',
'switch_to' => [
'restricted_with_editor' => self::$sampleContentSecured,
// Intersection of restrictions => most strict XSS filtering.
'restricted_plus_dangerous_tag_with_editor' => self::$sampleContentSecured,
// No text editor => no XSS filtering.
'unrestricted_without_editor' => FALSE,
'unrestricted_with_editor' => self::$sampleContentSecured,
],
],
[
'node_id' => 2,
// Text editor => XSS filtering.
'value' => self::$sampleContentSecured,
'format' => 'restricted_with_editor',
'switch_to' => [
// No text editor => no XSS filtering.
'restricted_without_editor' => FALSE,
// Intersection of restrictions => most strict XSS filtering.
'restricted_plus_dangerous_tag_with_editor' => self::$sampleContentSecured,
// No text editor => no XSS filtering.
'unrestricted_without_editor' => FALSE,
'unrestricted_with_editor' => self::$sampleContentSecured,
],
],
[
'node_id' => 3,
// Text editor => XSS filtering.
'value' => self::$sampleContentSecuredEmbedAllowed,
'format' => 'restricted_plus_dangerous_tag_with_editor',
'switch_to' => [
// No text editor => no XSS filtering.
'restricted_without_editor' => FALSE,
// Intersection of restrictions => most strict XSS filtering.
'restricted_with_editor' => self::$sampleContentSecured,
// No text editor => no XSS filtering.
'unrestricted_without_editor' => FALSE,
// Intersection of restrictions => most strict XSS filtering.
'unrestricted_with_editor' => self::$sampleContentSecured,
],
],
[
'node_id' => 4,
// No text editor => no XSS filtering.
'value' => self::$sampleContent,
'format' => 'unrestricted_without_editor',
'switch_to' => [
// No text editor => no XSS filtering.
'restricted_without_editor' => FALSE,
'restricted_with_editor' => self::$sampleContentSecured,
// Intersection of restrictions => most strict XSS filtering.
'restricted_plus_dangerous_tag_with_editor' => self::$sampleContentSecured,
// From no editor, no security filters, to editor, still no security
// filters: resulting content when viewed was already vulnerable, so
// it must be intentional.
'unrestricted_with_editor' => FALSE,
],
],
[
'node_id' => 5,
// Text editor => XSS filtering.
'value' => self::$sampleContentSecured,
'format' => 'unrestricted_with_editor',
'switch_to' => [
// From editor, no security filters to security filters, no editor: no
// risk.
'restricted_without_editor' => FALSE,
'restricted_with_editor' => self::$sampleContentSecured,
// Intersection of restrictions => most strict XSS filtering.
'restricted_plus_dangerous_tag_with_editor' => self::$sampleContentSecured,
// From no editor, no security filters, to editor, still no security
// filters: resulting content when viewed was already vulnerable, so
// it must be intentional.
'unrestricted_without_editor' => FALSE,
],
],
];
// Log in as the privileged user, and for every sample, do the following:
// - switch to every other text format/editor
// - assert the XSS-filtered values that we get from the server
$this
->drupalLogin($this->privilegedUser);
$cookies = $this
->getSessionCookies();
foreach ($expected as $case) {
$this
->drupalGet('node/' . $case['node_id'] . '/edit');
// Verify data- attributes.
$body = $this
->assertSession()
->fieldExists('edit-body-0-value');
$this
->assertSame(self::$sampleContent, $body
->getAttribute('data-editor-value-original'), 'The data-editor-value-original attribute is correctly set.');
$this
->assertSame('false', (string) $body
->getAttribute('data-editor-value-is-changed'), 'The data-editor-value-is-changed attribute is correctly set.');
// Switch to every other text format/editor and verify the results.
foreach ($case['switch_to'] as $format => $expected_filtered_value) {
$post = [
'value' => self::$sampleContent,
'original_format_id' => $case['format'],
];
$client = $this
->getHttpClient();
$response = $client
->post($this
->buildUrl('/editor/filter_xss/' . $format), [
'body' => http_build_query($post),
'cookies' => $cookies,
'headers' => [
'Accept' => 'application/json',
'Content-Type' => 'application/x-www-form-urlencoded',
],
'http_errors' => FALSE,
]);
$this
->assertEquals(200, $response
->getStatusCode());
$json = Json::decode($response
->getBody());
$this
->assertSame($expected_filtered_value, $json, 'The value was correctly filtered for XSS attack vectors.');
}
}
}