Skip to content

Commit 948cd3d

Browse files
authored
Merge pull request #91 from vpietri/unauthorized_csp_detection
Check unauthorized inline JS
2 parents 9bd4aeb + cd6d435 commit 948cd3d

File tree

7 files changed

+92
-16
lines changed

7 files changed

+92
-16
lines changed

Observer/CheckHtmlObserver.php

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<?php
2+
3+
namespace ADM\QuickDevBar\Observer;
4+
5+
use ADM\QuickDevBar\Service\Dumper;
6+
use Magento\Csp\Api\PolicyCollectorInterface;
7+
use Magento\Csp\Model\Policy\FetchPolicy;
8+
use Magento\Framework\Event\Observer;
9+
use Magento\Framework\Event\ObserverInterface;
10+
11+
12+
class CheckHtmlObserver implements ObserverInterface
13+
{
14+
private Dumper $dumper;
15+
16+
private PolicyCollectorInterface $collector;
17+
18+
public function __construct(Dumper $dumper,
19+
PolicyCollectorInterface $collector)
20+
{
21+
$this->dumper = $dumper;
22+
$this->collector = $collector;
23+
}
24+
25+
public function execute(Observer $observer)
26+
{
27+
28+
$block = $observer->getEvent()->getBlock();
29+
$html = $observer->getEvent()->getTransport()->getHtml();
30+
$allowedHashes = [];
31+
$policies = $this->collector->collect();
32+
foreach ($policies as $policy) {
33+
if($policy->getId() =='script-src') {
34+
if($policy->isInlineAllowed()) {
35+
//Noting to check
36+
return null;
37+
}
38+
$allowedHashes = $policy->getHashes();
39+
break;
40+
}
41+
}
42+
43+
//Without nonce
44+
$pattern = '/<script(?![^>]*\bnonce\s*=)[^>]*>(.*?)<\/script>/is';
45+
46+
//Without nonce nor x-magento-init
47+
$pattern = '/<script(?![^>]*\b(?:nonce|type\s*=\s*["\']text\/x-magento-init["\']))[^>]*>(.*?)<\/script>/is';
48+
49+
50+
if( preg_match_all($pattern, $html, $matches)) {
51+
foreach ($matches[1] as $scriptContent) {
52+
$sha256 = $this->generateHashValue($scriptContent);
53+
if(!empty($allowedHashes[$sha256])) {
54+
continue;
55+
}
56+
$this->dumper->addDump(
57+
'Script violating CSP'. '<br>' .
58+
'<pre>' . htmlspecialchars($scriptContent). '</pre>' .
59+
'(' . get_class($block) . ' :: '. $block->getTemplateFile() . ')<br>' .
60+
'To enable execution use sha256: '. $this->generateHashValue($scriptContent) . '<br><br>',
61+
[], "");
62+
}
63+
}
64+
}
65+
66+
private function generateHashValue(string $content): string
67+
{
68+
return base64_encode(hash('sha256', $content, true));
69+
}
70+
}

Plugin/Framework/Event/Invoker.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace ADM\QuickDevBar\Plugin\Framework\Event;
44

5+
use Magento\Framework\Event\Observer;
6+
57
class Invoker
68
{
79
/**
@@ -19,8 +21,11 @@ public function __construct(
1921
$this->serviceObserver = $serviceObserver;
2022
}
2123

22-
public function beforeDispatch($class, $observerConfig, $wrapper)
24+
public function beforeDispatch(\Magento\Framework\Event\InvokerInterface $class, array $configuration, Observer $observer)
2325
{
24-
$this->serviceObserver->addObserver($observerConfig, $wrapper);
26+
if (isset($configuration['disabled']) && true === $configuration['disabled']) {
27+
return;
28+
}
29+
$this->serviceObserver->addObserver($configuration, $observer);
2530
}
2631
}

Service/Observer.php

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,10 @@ public function pullData()
1919
return $this->observers;
2020
}
2121

22-
public function addObserver($observerConfig, $wrapper)
22+
public function addObserver($configuration, $observer)
2323
{
24-
$data = $observerConfig;
25-
26-
if (isset($data['disabled']) && true === $data['disabled']) {
27-
return;
28-
}
29-
30-
31-
$data['event'] = $wrapper->getEvent()->getName();
24+
$data = $configuration;
25+
$data['event'] = $observer->getEvent()->getName();
3226

3327
$key = crc32(json_encode($data));
3428
if (isset($this->observers[$key])) {
@@ -38,4 +32,4 @@ public function addObserver($observerConfig, $wrapper)
3832
$this->observers[$key] = $data;
3933
}
4034
}
41-
}
35+
}

etc/events.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,8 @@
2121
<observer name="qdb_custom_layout" instance="ADM\QuickDevBar\Observer\UpdateLayoutObserver" />
2222
</event>
2323

24+
<event name="view_block_abstract_to_html_after">
25+
<observer name="qdb_view_block_abstract_to_html_after" instance="ADM\QuickDevBar\Observer\CheckHtmlObserver" />
26+
</event>
27+
2428
</config>

view/base/layout/quickdevbar.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
<argument name="data_key" xsi:type="string">module_list</argument>
2525

2626
</arguments>
27+
<action method="setIsAjax">
28+
<argument name="is_ajax" xsi:type="string">1</argument>
29+
</action>
2730
</block>
2831
<block class="ADM\QuickDevBar\Block\Tab\Content\Config" name="qdb.tab.config" as="qdb.tab.config" template="ADM_QuickDevBar::tab/info/config.phtml">
2932
<arguments>

view/base/templates/tab/dumper.phtml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
<?php else: ?>
1313
<?php foreach ($block->getDumps() as $dump):?>
1414
<div class="qdb-dump">
15-
<?= $block->formatTrace($dump['bt']) ?>
15+
<?= !empty($dump['bt']) ? $block->formatTrace($dump['bt']) : '' ?>
1616
<?= $dump['dump'] ?>
1717
</div>
1818
<?php endforeach;?>

view/base/templates/tab/profile/observer.phtml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@
88
<table class="qdb_table striped filterable">
99
<thead>
1010
<tr>
11-
<th>Event</th>
12-
<th>Name</th>
11+
<th>Event name</th>
12+
<th>Intercepted event name</th>
1313
<th>Call Number</th>
14-
<th>Instance</th>
14+
<th>Observer class</th>
1515
</tr>
1616
</thead>
1717
<tbody>

0 commit comments

Comments
 (0)