├── README.md
└── app
└── code
└── Netalico
└── Csp
├── Helper
└── Data.php
├── Model
└── Config
│ └── Source
│ └── Mode.php
├── Observer
└── ActionPredispatch.php
├── etc
├── adminhtml
│ └── system.xml
├── frontend
│ └── events.xml
└── module.xml
└── registration.php
/README.md:
--------------------------------------------------------------------------------
1 | # Easy Magento 2 Content Security Policy (CSP) Enforcement
2 |
3 | 1. Go to https://report-uri.com/register and register for a free account.
4 | 2. Go to CSP->Wizard.
5 | 3. Click "Create your Wizard reporting address."
6 | 4. Copy your current subdomain.
7 | 5. Install the Magento module.
8 | 6. Go to Stores->Configuration->Netalico->CSP.
9 | 7. Enable the extension, paste the subdomain in the Report URI Subdomain field, and a part of your checkout URL (e.g. "onepage") and hit save.
10 | 8. Clear your Magento cache and browse around the frontend of your website. Make sure you go to an example of every type of page, including the cart and the checkout.
11 | 9. On https://report-uri.com Go back to CSP->Wizard and click allow on everything you recognize. If you see any suspcicious scripts, you should investigate and verify that they're legitimate.
12 | 10. Click on CSP-My Policies and copy the policy text to Magento in Stores->Configuration->Netalico->CSP->Policy.
13 | 11. For maximum security, go back to Magento and Stores->Configuration->Netalico->CSP change the Reporting Mode to enforce. 12. Alternatively, you can set the Reporting Mode to Reporting Only (but if you do that on your live site, you'll probably surpass the free limit of Report-Uri.com).
14 | 13. I recommend you at least enable Checkout Lockdown which enforces your CSP on the checkout, which is the most vulnerable part of the site for js infections.
15 |
--------------------------------------------------------------------------------
/app/code/Netalico/Csp/Helper/Data.php:
--------------------------------------------------------------------------------
1 | _scopeConfig = $scopeConfig;
16 | }
17 |
18 | public function getCurrentStoreInfo()
19 | {
20 | return $this->_storeManager->getStore()->getId();
21 | }
22 |
23 | public function isEnabled()
24 | {
25 | return (bool) $this->_scopeConfig->getValue('csp/general/enabled');
26 | }
27 |
28 | public function getPolicy()
29 | {
30 | if ($this->_scopeConfig->getValue('csp/general/policy')) {
31 | if ($this->_scopeConfig->getValue('csp/general/easy_policy')) {
32 | return $this->convertToEasyPolicy($this->_scopeConfig->getValue('csp/general/policy'));
33 | }
34 |
35 | return $this->_scopeConfig->getValue('csp/general/policy');
36 | } else {
37 | return "default-src 'none'; form-action 'none'; frame-ancestors 'none';";
38 | }
39 | }
40 |
41 | public function getReportUri()
42 | {
43 | return "; report-uri " . 'https://' . $this->_scopeConfig->getValue('csp/general/report_uri') . '.report-uri.com/r/d/csp/';
44 | }
45 |
46 | public function getMode()
47 | {
48 | return $this->_scopeConfig->getValue('csp/general/mode');
49 | }
50 |
51 | public function getOnlyCheckout()
52 | {
53 | return $this->_scopeConfig->getValue('csp/general/only_checkout');
54 | }
55 |
56 | public function getCheckoutUrl()
57 | {
58 | return $this->_scopeConfig->getValue('csp/general/checkout_url');
59 | }
60 |
61 | public function convertToEasyPolicy($policy) {
62 |
63 | $replacements = array(
64 | 'connect-src',
65 | 'default-src',
66 | 'font-src',
67 | 'frame-src',
68 | 'font-src',
69 | 'img-src',
70 | 'media-src',
71 | 'script-src-attr',
72 | 'script-src-elem',
73 | 'style-src-attr',
74 | 'style-src-elem',
75 | 'form-action',
76 | 'frame-ancestors',
77 | ';'
78 | );
79 | $policy = str_replace($replacements, '', $policy);
80 | $policy = 'default-src ' . $policy;
81 |
82 | return $policy;
83 |
84 | }
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/app/code/Netalico/Csp/Model/Config/Source/Mode.php:
--------------------------------------------------------------------------------
1 | 0, 'label' =>'Wizard'),
13 | array('value' => 1, 'label' => 'Report Only'),
14 | array('value' => 2, 'label' =>'Enforce'),
15 | array('value' => 3, 'label' =>'No Reporting'),
16 | );
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/code/Netalico/Csp/Observer/ActionPredispatch.php:
--------------------------------------------------------------------------------
1 | response = $response;
25 | $this->helper = $helper;
26 | $this->_urlInterface = $urlInterface;
27 | }
28 |
29 |
30 | /**
31 | * Execute observer
32 | *
33 | * @param \Magento\Framework\Event\Observer $observer
34 | * @return void
35 | */
36 |
37 |
38 | public function execute(
39 | \Magento\Framework\Event\Observer $observer
40 | ) {
41 |
42 | if (!$this->helper->isEnabled()) {
43 | return;
44 | }
45 |
46 | if (!$this->helper->getOnlyCheckout()) {
47 | $this->_enforcePolicy();
48 | return;
49 | } else {
50 | if (strpos($this->_urlInterface->getCurrentUrl(), $this->helper->getCheckoutUrl()) !== false) {
51 | $this->_enforcePolicy();
52 | return;
53 | }
54 | }
55 | }
56 | private function _enforcePolicy()
57 | {
58 |
59 | switch ($this->helper->getMode()) {
60 | case "0": // Wizard
61 | $this->response->setHeader(
62 | 'Content-Security-Policy-Report-Only',
63 | $this->helper->getPolicy() . $this->helper->getReportUri() . 'wizard', true
64 | );
65 | break;
66 | case "1": // Reporting
67 | $this->response->setHeader(
68 | 'Content-Security-Policy-Report-Only',
69 | $this->helper->getPolicy() . $this->helper->getReportUri() . 'reporting', true
70 | );
71 | break;
72 | case "2": // Enforce
73 | $this->response->setHeader(
74 | 'Content-Security-Policy',
75 | $this->helper->getPolicy() . $this->helper->getReportUri() . 'enforce', true
76 | );
77 | break;
78 | case "3": // No Reporting
79 | $this->response->setHeader(
80 | 'Content-Security-Policy',
81 | $this->helper->getPolicy(), true
82 | );
83 | break;
84 |
85 | }
86 | }
87 |
88 | }
89 |
--------------------------------------------------------------------------------
/app/code/Netalico/Csp/etc/adminhtml/system.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | separator-top
9 |
10 | netalico
11 | Netalico_Csp::csp_config
12 |
13 |
14 |
15 |
16 | Magento\Config\Model\Config\Source\Yesno
17 |
18 |
19 |
20 |
21 |
22 |
23 | Magento\Config\Model\Config\Source\Yesno
24 |
25 |
26 |
27 |
28 |
29 |
30 | Netalico\Csp\Model\Config\Source\Mode
31 |
32 |
33 |
34 |
35 | Magento\Config\Model\Config\Source\Yesno
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/app/code/Netalico/Csp/etc/frontend/events.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/code/Netalico/Csp/etc/module.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/app/code/Netalico/Csp/registration.php:
--------------------------------------------------------------------------------
1 |