Merge branch 'xss_and_redir_patch' of git://github.com/PercussiveElbow/BookStack into xss_and_redirect
This commit is contained in:
		
						commit
						6d8b0605a0
					
				| 
						 | 
					@ -296,6 +296,24 @@ class PageContent
 | 
				
			||||||
            $scriptElem->parentNode->removeChild($scriptElem);
 | 
					            $scriptElem->parentNode->removeChild($scriptElem);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Remove clickable links to JavaScript URI
 | 
				
			||||||
 | 
					        $badLinks = $xPath->query('//*[contains(@href, \'javascript:\')]');
 | 
				
			||||||
 | 
					        foreach ($badLinks as $badLink) {
 | 
				
			||||||
 | 
					            $badLink->parentNode->removeChild($badLink);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Remove forms with calls to JavaScript URI
 | 
				
			||||||
 | 
					        $badForms = $xPath->query('//*[contains(@action, \'javascript:\')] | //*[contains(@formaction, \'javascript:\')]');
 | 
				
			||||||
 | 
					        foreach ($badForms as $badForm) {
 | 
				
			||||||
 | 
					            $badForm->parentNode->removeChild($badForm);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Remove meta tag to prevent external redirects
 | 
				
			||||||
 | 
					        $metaTags = $xPath->query('//meta[contains(@content, \'url\')]');
 | 
				
			||||||
 | 
					        foreach ($metaTags as $metaTag) {
 | 
				
			||||||
 | 
					            $metaTag->parentNode->removeChild($metaTag);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Remove data or JavaScript iFrames
 | 
					        // Remove data or JavaScript iFrames
 | 
				
			||||||
        $badIframes = $xPath->query('//*[contains(@src, \'data:\')] | //*[contains(@src, \'javascript:\')] | //*[@srcdoc]');
 | 
					        $badIframes = $xPath->query('//*[contains(@src, \'data:\')] | //*[contains(@src, \'javascript:\')] | //*[@srcdoc]');
 | 
				
			||||||
        foreach ($badIframes as $badIframe) {
 | 
					        foreach ($badIframes as $badIframe) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,4 +5,4 @@ set -e
 | 
				
			||||||
npm install
 | 
					npm install
 | 
				
			||||||
npm rebuild node-sass
 | 
					npm rebuild node-sass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
exec npm run watch
 | 
					SHELL=/bin/sh exec npm run watch
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,7 +5,7 @@
 | 
				
			||||||
    "build:css:watch": "sass ./resources/sass:./public/dist --watch",
 | 
					    "build:css:watch": "sass ./resources/sass:./public/dist --watch",
 | 
				
			||||||
    "build:css:production": "sass ./resources/sass:./public/dist -s compressed",
 | 
					    "build:css:production": "sass ./resources/sass:./public/dist -s compressed",
 | 
				
			||||||
    "build:js:dev": "esbuild --bundle ./resources/js/index.js --outfile=public/dist/app.js --sourcemap --target=es2019 --main-fields=module,main",
 | 
					    "build:js:dev": "esbuild --bundle ./resources/js/index.js --outfile=public/dist/app.js --sourcemap --target=es2019 --main-fields=module,main",
 | 
				
			||||||
    "build:js:watch": "chokidar \"./resources/**/*.js\" -c \"npm run build:js:dev\"",
 | 
					    "build:js:watch": "chokidar --initial \"./resources/**/*.js\" -c \"npm run build:js:dev\"",
 | 
				
			||||||
    "build:js:production": "NODE_ENV=production esbuild --bundle ./resources/js/index.js --outfile=public/dist/app.js --sourcemap --target=es2019 --main-fields=module,main --minify",
 | 
					    "build:js:production": "NODE_ENV=production esbuild --bundle ./resources/js/index.js --outfile=public/dist/app.js --sourcemap --target=es2019 --main-fields=module,main --minify",
 | 
				
			||||||
    "build": "npm-run-all --parallel build:*:dev",
 | 
					    "build": "npm-run-all --parallel build:*:dev",
 | 
				
			||||||
    "production": "npm-run-all --parallel build:*:production",
 | 
					    "production": "npm-run-all --parallel build:*:production",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -159,6 +159,72 @@ class PageContentTest extends TestCase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_javascript_uri_links_are_removed()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $checks = [
 | 
				
			||||||
 | 
					            '<a id="xss" href="javascript:alert(document.cookie)>Click me</a>',
 | 
				
			||||||
 | 
					            '<a id="xss" href="javascript: alert(document.cookie)>Click me</a>'
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->asEditor();
 | 
				
			||||||
 | 
					        $page = Page::first();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        foreach ($checks as $check) {
 | 
				
			||||||
 | 
					            $page->html = $check;
 | 
				
			||||||
 | 
					            $page->save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $pageView = $this->get($page->getUrl());
 | 
				
			||||||
 | 
					            $pageView->assertStatus(200);
 | 
				
			||||||
 | 
					            $pageView->assertElementNotContains('.page-content', '<a id="xss">');
 | 
				
			||||||
 | 
					            $pageView->assertElementNotContains('.page-content', 'href=javascript:');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    public function test_form_actions_with_javascript_are_removed()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $checks = [
 | 
				
			||||||
 | 
					            '<form><input id="xss" type=submit formaction=javascript:alert(document.domain) value=Submit><input></form>',
 | 
				
			||||||
 | 
					            '<form ><button id="xss" formaction=javascript:alert(document.domain)>Click me</button></form>',
 | 
				
			||||||
 | 
					            '<form id="xss" action=javascript:alert(document.domain)><input type=submit value=Submit></form>'
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->asEditor();
 | 
				
			||||||
 | 
					        $page = Page::first();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        foreach ($checks as $check) {
 | 
				
			||||||
 | 
					            $page->html = $check;
 | 
				
			||||||
 | 
					            $page->save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $pageView = $this->get($page->getUrl());
 | 
				
			||||||
 | 
					            $pageView->assertStatus(200);
 | 
				
			||||||
 | 
					            $pageView->assertElementNotContains('.page-content', '<button id="xss"');
 | 
				
			||||||
 | 
					            $pageView->assertElementNotContains('.page-content', '<input id="xss"');
 | 
				
			||||||
 | 
					            $pageView->assertElementNotContains('.page-content', '<form id="xss"');
 | 
				
			||||||
 | 
					            $pageView->assertElementNotContains('.page-content', 'action=javascript:');
 | 
				
			||||||
 | 
					            $pageView->assertElementNotContains('.page-content', 'formaction=javascript:');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    public function test_metadata_redirects_are_removed()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $checks = [
 | 
				
			||||||
 | 
					            '<meta http-equiv="refresh" content="0; url=//external_url">',
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->asEditor();
 | 
				
			||||||
 | 
					        $page = Page::first();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        foreach ($checks as $check) {
 | 
				
			||||||
 | 
					            $page->html = $check;
 | 
				
			||||||
 | 
					            $page->save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $pageView = $this->get($page->getUrl());
 | 
				
			||||||
 | 
					            $pageView->assertStatus(200);
 | 
				
			||||||
 | 
					            $pageView->assertElementNotContains('.page-content', '<meta>');
 | 
				
			||||||
 | 
					            $pageView->assertElementNotContains('.page-content', '</meta>');
 | 
				
			||||||
 | 
					            $pageView->assertElementNotContains('.page-content', 'content=');
 | 
				
			||||||
 | 
					            $pageView->assertElementNotContains('.page-content', 'external_url');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    public function test_page_inline_on_attributes_removed_by_default()
 | 
					    public function test_page_inline_on_attributes_removed_by_default()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->asEditor();
 | 
					        $this->asEditor();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue