]> BookStack Code Mirror - bookstack/commitdiff
Hardened page content script escaping
authorDan Brown <redacted>
Wed, 10 Jul 2019 19:17:22 +0000 (20:17 +0100)
committerDan Brown <redacted>
Wed, 10 Jul 2019 19:17:22 +0000 (20:17 +0100)
Increased range of tests to cover.

Fixes #1531

app/Entities/Repos/EntityRepo.php
tests/Entity/PageContentTest.php

index 4edd61723a2cdc8af71f51d7eafda0b0487aa264..aad9a1205895a18bfce0b0143ae244e2d9bffd51 100644 (file)
@@ -760,13 +760,13 @@ class EntityRepo
         $xPath = new DOMXPath($doc);
 
         // Remove standard script tags
-        $scriptElems = $xPath->query('//body//*//script');
+        $scriptElems = $xPath->query('//script');
         foreach ($scriptElems as $scriptElem) {
             $scriptElem->parentNode->removeChild($scriptElem);
         }
 
         // Remove 'on*' attributes
-        $onAttributes = $xPath->query('//body//*/@*[starts-with(name(), \'on\')]');
+        $onAttributes = $xPath->query('//@*[starts-with(name(), \'on\')]');
         foreach ($onAttributes as $attr) {
             /** @var \DOMAttr $attr*/
             $attrName = $attr->nodeName;
index 6201cf5d7af005243128b80657cf347b0f5a6dcb..c80b5f1d96f1b9c85ec5bf281c42e7f0c3f17895 100644 (file)
@@ -84,6 +84,31 @@ class PageContentTest extends TestCase
         $pageView->assertSee('abc123abc123');
     }
 
+    public function test_more_complex_content_script_escaping_scenarios()
+    {
+        $checks = [
+            "<p>Some script</p><script>alert('cat')</script>",
+            "<div><div><div><div><p>Some script</p><script>alert('cat')</script></div></div></div></div>",
+            "<p>Some script<script>alert('cat')</script></p>",
+            "<p>Some script <div><script>alert('cat')</script></div></p>",
+            "<p>Some script <script><div>alert('cat')</script></div></p>",
+            "<p>Some script <script><div>alert('cat')</script><script><div>alert('cat')</script></p><script><div>alert('cat')</script>",
+        ];
+
+        $this->asEditor();
+        $page = Page::first();
+
+        foreach ($checks as $check) {
+            $page->html = $check;
+            $page->save();
+
+            $pageView = $this->get($page->getUrl());
+            $pageView->assertElementNotContains('.page-content', '<script>');
+            $pageView->assertElementNotContains('.page-content', '</script>');
+        }
+
+    }
+
     public function test_page_inline_on_attributes_removed_by_default()
     {
         $this->asEditor();
@@ -97,6 +122,29 @@ class PageContentTest extends TestCase
         $pageView->assertSee('<p>Hello</p>');
     }
 
+    public function test_more_complex_inline_on_attributes_escaping_scenarios()
+    {
+        $checks = [
+            '<p onclick="console.log(\'test\')">Hello</p>',
+            '<div>Lorem ipsum dolor sit amet.</div><p onclick="console.log(\'test\')">Hello</p>',
+            '<div>Lorem ipsum dolor sit amet.<p onclick="console.log(\'test\')">Hello</p></div>',
+            '<div><div><div><div>Lorem ipsum dolor sit amet.<p onclick="console.log(\'test\')">Hello</p></div></div></div></div>',
+            '<div onclick="console.log(\'test\')">Lorem ipsum dolor sit amet.</div><p onclick="console.log(\'test\')">Hello</p><div></div>',
+        ];
+
+        $this->asEditor();
+        $page = Page::first();
+
+        foreach ($checks as $check) {
+            $page->html = $check;
+            $page->save();
+
+            $pageView = $this->get($page->getUrl());
+            $pageView->assertElementNotContains('.page-content', 'onclick');
+        }
+
+    }
+
     public function test_page_content_scripts_show_when_configured()
     {
         $this->asEditor();