From 0a9947e42cc571ad12ab4249facc9453420a5cfd Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 27 Dec 2022 14:16:40 +0900 Subject: [PATCH 01/11] refactor: remove / before > in input tag --- app/Config/Honeypot.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Config/Honeypot.php b/app/Config/Honeypot.php index 179b01546902..f865f1c44ea6 100644 --- a/app/Config/Honeypot.php +++ b/app/Config/Honeypot.php @@ -24,7 +24,7 @@ class Honeypot extends BaseConfig /** * Honeypot HTML Template */ - public string $template = ''; + public string $template = ''; /** * Honeypot container From b7ef46c8505214df58eb9c42fde05f357e98dddc Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 27 Dec 2022 14:24:57 +0900 Subject: [PATCH 02/11] fix: inline style "display:none" for honeypot field does not work with CSP --- app/Config/Honeypot.php | 9 +++++++++ system/Honeypot/Honeypot.php | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/app/Config/Honeypot.php b/app/Config/Honeypot.php index f865f1c44ea6..019b48acf9de 100644 --- a/app/Config/Honeypot.php +++ b/app/Config/Honeypot.php @@ -28,6 +28,15 @@ class Honeypot extends BaseConfig /** * Honeypot container + * + * If you enables CSP, you can remove `style="display:none"`. */ public string $container = '
{template}
'; + + /** + * The id attribute for Honeypot container tag + * + * Used when CSP is enabled. + */ + public string $containerId = 'hpc'; } diff --git a/system/Honeypot/Honeypot.php b/system/Honeypot/Honeypot.php index fdd8fe95168b..7ab0cd36737e 100644 --- a/system/Honeypot/Honeypot.php +++ b/system/Honeypot/Honeypot.php @@ -46,6 +46,8 @@ public function __construct(HoneypotConfig $config) $this->config->container = '
{template}
'; } + $this->config->containerId ??= 'hpc'; + if ($this->config->template === '') { throw HoneypotException::forNoTemplate(); } @@ -70,10 +72,26 @@ public function hasContent(RequestInterface $request) */ public function attachHoneypot(ResponseInterface $response) { + if ($response->getCSP()->enabled()) { + // Add id attribute to the container tag. + $this->config->container = str_ireplace( + '>{template}', + ' id="' . $this->config->containerId . '">{template}', + $this->config->container + ); + } + $prepField = $this->prepareTemplate($this->config->template); $body = $response->getBody(); $body = str_ireplace('', $prepField . '', $body); + + if ($response->getCSP()->enabled()) { + // Add style tag for the container tag in the head tag. + $style = ''; + $body = str_ireplace('', $style . '', $body); + } + $response->setBody($body); } From 87a677efd950d9cce7902254de9d21c18820d722 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 27 Dec 2022 14:28:01 +0900 Subject: [PATCH 03/11] docs: fix section level --- user_guide_src/source/libraries/honeypot.rst | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/user_guide_src/source/libraries/honeypot.rst b/user_guide_src/source/libraries/honeypot.rst index cdaa4eb1eb52..4b49e4c85b19 100644 --- a/user_guide_src/source/libraries/honeypot.rst +++ b/user_guide_src/source/libraries/honeypot.rst @@ -1,6 +1,6 @@ -===================== +############## Honeypot Class -===================== +############## The Honeypot Class makes it possible to determine when a Bot makes a request to a CodeIgniter4 application, if it's enabled in ``Application\Config\Filters.php`` file. This is done by attaching form fields to any form, @@ -11,8 +11,9 @@ assumed the request is coming from a Bot, and you can throw a ``HoneypotExceptio :local: :depth: 2 +***************** Enabling Honeypot -===================== +***************** To enable a Honeypot, changes have to be made to the **app/Config/Filters.php**. Just uncomment honeypot from the ``$globals`` array, like: @@ -23,8 +24,9 @@ A sample Honeypot filter is bundled, as ``system/Filters/Honeypot.php``. If it is not suitable, make your own at ``app/Filters/Honeypot.php``, and modify the ``$aliases`` in the configuration appropriately. +******************** Customizing Honeypot -===================== +******************** Honeypot can be customized. The fields below can be set either in **app/Config/Honeypot.php** or in **.env**. From 53380f4ba830e98096dc9dc9585617db17bf43fb Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 27 Dec 2022 14:28:48 +0900 Subject: [PATCH 04/11] docs: fix text decoration --- user_guide_src/source/libraries/honeypot.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/user_guide_src/source/libraries/honeypot.rst b/user_guide_src/source/libraries/honeypot.rst index 4b49e4c85b19..643c7044282d 100644 --- a/user_guide_src/source/libraries/honeypot.rst +++ b/user_guide_src/source/libraries/honeypot.rst @@ -3,7 +3,7 @@ Honeypot Class ############## The Honeypot Class makes it possible to determine when a Bot makes a request to a CodeIgniter4 application, -if it's enabled in ``Application\Config\Filters.php`` file. This is done by attaching form fields to any form, +if it's enabled in **app\Config\Filters.php** file. This is done by attaching form fields to any form, and this form field is hidden from a human but accessible to a Bot. When data is entered into the field, it's assumed the request is coming from a Bot, and you can throw a ``HoneypotException``. @@ -20,8 +20,8 @@ from the ``$globals`` array, like: .. literalinclude:: honeypot/001.php -A sample Honeypot filter is bundled, as ``system/Filters/Honeypot.php``. -If it is not suitable, make your own at ``app/Filters/Honeypot.php``, +A sample Honeypot filter is bundled, as **system/Filters/Honeypot.php**. +If it is not suitable, make your own at **app/Filters/Honeypot.php**, and modify the ``$aliases`` in the configuration appropriately. ******************** @@ -31,7 +31,7 @@ Customizing Honeypot Honeypot can be customized. The fields below can be set either in **app/Config/Honeypot.php** or in **.env**. -* ``hidden`` - true|false to control visibility of the honeypot field; default is ``true`` -* ``label`` - HTML label for the honeypot field, default is 'Fill This Field' -* ``name`` - name of the HTML form field used for the template; default is 'honeypot' -* ``template`` - form field template used for the honeypot; default is '' +* ``$hidden`` - ``true`` or ``false`` to control visibility of the honeypot field; default is ``true`` +* ``$label`` - HTML label for the honeypot field, default is ``'Fill This Field'`` +* ``$name`` - name of the HTML form field used for the template; default is ``'honeypot'`` +* ``$template`` - form field template used for the honeypot; default is ``''`` From 0c25173cb119c20d2752600ea4f55c3f1432efab Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 27 Dec 2022 14:38:51 +0900 Subject: [PATCH 05/11] docs: update sample Config file --- user_guide_src/source/libraries/honeypot/001.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/user_guide_src/source/libraries/honeypot/001.php b/user_guide_src/source/libraries/honeypot/001.php index f0dbf7e64d57..573010145976 100644 --- a/user_guide_src/source/libraries/honeypot/001.php +++ b/user_guide_src/source/libraries/honeypot/001.php @@ -6,14 +6,18 @@ class Filters extends BaseConfig { + // ... + public $globals = [ 'before' => [ 'honeypot', // 'csrf', + // 'invalidchars', ], 'after' => [ 'toolbar', 'honeypot', + // 'secureheaders', ], ]; From 184dd467955453c4f92006889c83f4cdeceb8c74 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 27 Dec 2022 14:34:01 +0900 Subject: [PATCH 06/11] docs: add config items --- user_guide_src/source/libraries/honeypot.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/user_guide_src/source/libraries/honeypot.rst b/user_guide_src/source/libraries/honeypot.rst index 643c7044282d..e034e0dc08db 100644 --- a/user_guide_src/source/libraries/honeypot.rst +++ b/user_guide_src/source/libraries/honeypot.rst @@ -35,3 +35,6 @@ Honeypot can be customized. The fields below can be set either in * ``$label`` - HTML label for the honeypot field, default is ``'Fill This Field'`` * ``$name`` - name of the HTML form field used for the template; default is ``'honeypot'`` * ``$template`` - form field template used for the honeypot; default is ``''`` +* ``$container`` - container tag for the template; default is ``'
{template}
'``. + If you enables CSP, you can remove ``style="display:none"``. +* ``$containerId`` - [Since v4.3.0] this setting is used only when you enables CSP. You can change the id attribute for the container tag; default is ``'hpc'`` From ee49833c035cc36c2e076bdbc630de75c711afc9 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 27 Dec 2022 15:15:29 +0900 Subject: [PATCH 07/11] docs: add changelog and upgrading guide --- user_guide_src/source/changelogs/v4.3.0.rst | 2 ++ user_guide_src/source/installation/upgrade_430.rst | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/user_guide_src/source/changelogs/v4.3.0.rst b/user_guide_src/source/changelogs/v4.3.0.rst index 7fdb8038d6d4..4ea3b567cf68 100644 --- a/user_guide_src/source/changelogs/v4.3.0.rst +++ b/user_guide_src/source/changelogs/v4.3.0.rst @@ -291,6 +291,7 @@ The following items are affected: - Typography class: Creation of ``br`` tag - View Parser: The ``nl2br`` filter +- Honeypot: ``input`` tag - Form helper - HTML helper - Common Functions @@ -364,3 +365,4 @@ Bugs Fixed - Fixed a bug when all types of ``Prepared Queries`` were returning a ``Result`` object instead of a bool value for write-type queries. - Fixed a bug with variable filtering in JSON requests using with ``IncomingRequest::getVar()`` or ``IncomingRequest::getJsonVar()`` methods. - Fixed a bug when variable type may be changed when using a specified index with ``IncomingRequest::getVar()`` or ``IncomingRequest::getJsonVar()`` methods. +- Fixed a bug that Honeypot field appears when CSP is enabled. See also :ref:`upgrade-430-honeypot-and-csp`. diff --git a/user_guide_src/source/installation/upgrade_430.rst b/user_guide_src/source/installation/upgrade_430.rst index 5d7192822c31..04f44a03f4b4 100644 --- a/user_guide_src/source/installation/upgrade_430.rst +++ b/user_guide_src/source/installation/upgrade_430.rst @@ -216,6 +216,16 @@ Database - The ``Model::update()`` method now raises a ``DatabaseException`` if it generates an SQL statement without a WHERE clause. If you need to update all records in a table, use Query Builder instead. E.g., ``$model->builder()->update($data)``. +.. _upgrade-430-honeypot-and-csp: + +Honeypot and CSP +================ + +When CSP is enabled, id attribute ``id="hpc"`` will be injected into the container tag +for the Honeypot field to hide the field. If the id is already used in your views, you need to change it +with ``Config\Honeypot::$containerId``. +And you can remove ``style="display:none"`` in ``Config\Honeypot::$container``. + Others ====== @@ -260,6 +270,10 @@ Config - app/Config/Exceptions.php - Two additional public properties were added: ``$logDeprecations`` and ``$deprecationLogLevel``. See See :ref:`logging_deprecation_warnings` for details. +- app/Config/Honeypot.php + - The new property ``$containerId`` is added to set id attribute value for the container tag + when CSP is enabled. + - The ``input`` tag in the property ``$template`` value has been changed to HTML5 compatible. - app/Config/Logger.php - The property ``$threshold`` has been changed to ``9`` in other than ``production`` environment. From 221b9ac1df24a045b3140035eadf3cccbb73f6f4 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 27 Dec 2022 15:18:44 +0900 Subject: [PATCH 08/11] test: use aliasing with use operator --- tests/system/Honeypot/HoneypotTest.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/system/Honeypot/HoneypotTest.php b/tests/system/Honeypot/HoneypotTest.php index 5b9c0c0073d8..7a6f2341dd1c 100644 --- a/tests/system/Honeypot/HoneypotTest.php +++ b/tests/system/Honeypot/HoneypotTest.php @@ -18,6 +18,7 @@ use CodeIgniter\HTTP\IncomingRequest; use CodeIgniter\HTTP\Response; use CodeIgniter\Test\CIUnitTestCase; +use Config\Honeypot as HoneypotConfig; /** * @backupGlobals enabled @@ -28,7 +29,7 @@ */ final class HoneypotTest extends CIUnitTestCase { - private \Config\Honeypot $config; + private HoneypotConfig $config; private Honeypot $honeypot; /** @@ -41,7 +42,7 @@ final class HoneypotTest extends CIUnitTestCase protected function setUp(): void { parent::setUp(); - $this->config = new \Config\Honeypot(); + $this->config = new HoneypotConfig(); $this->honeypot = new Honeypot($this->config); unset($_POST[$this->config->name]); @@ -147,7 +148,7 @@ public function testHoneypotFilterAfter() public function testEmptyConfigContainer() { - $config = new \Config\Honeypot(); + $config = new HoneypotConfig(); $config->container = ''; $honeypot = new Honeypot($config); @@ -159,7 +160,7 @@ public function testEmptyConfigContainer() public function testNoTemplateConfigContainer() { - $config = new \Config\Honeypot(); + $config = new HoneypotConfig(); $config->container = '
'; $honeypot = new Honeypot($config); From 3c339cd045c027ced37002cac7b43056c24153d2 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 27 Dec 2022 15:20:42 +0900 Subject: [PATCH 09/11] test: update expected --- tests/system/Honeypot/HoneypotTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/system/Honeypot/HoneypotTest.php b/tests/system/Honeypot/HoneypotTest.php index 7a6f2341dd1c..167d41e080d3 100644 --- a/tests/system/Honeypot/HoneypotTest.php +++ b/tests/system/Honeypot/HoneypotTest.php @@ -67,13 +67,13 @@ public function testAttachHoneypotAndContainer() { $this->response->setBody('
'); $this->honeypot->attachHoneypot($this->response); - $expected = '
'; + $expected = '
'; $this->assertSame($expected, $this->response->getBody()); $this->config->container = ''; $this->response->setBody('
'); $this->honeypot->attachHoneypot($this->response); - $expected = '
'; + $expected = '
'; $this->assertSame($expected, $this->response->getBody()); } From 4643580f5b9c821b6337feba499c2abf7fdde609 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 27 Dec 2022 15:48:52 +0900 Subject: [PATCH 10/11] test: add test --- tests/system/Honeypot/HoneypotTest.php | 27 ++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/tests/system/Honeypot/HoneypotTest.php b/tests/system/Honeypot/HoneypotTest.php index 167d41e080d3..b87ce3fe3c48 100644 --- a/tests/system/Honeypot/HoneypotTest.php +++ b/tests/system/Honeypot/HoneypotTest.php @@ -11,6 +11,7 @@ namespace CodeIgniter\Honeypot; +use CodeIgniter\Config\Factories; use CodeIgniter\Config\Services; use CodeIgniter\Filters\Filters; use CodeIgniter\Honeypot\Exceptions\HoneypotException; @@ -18,6 +19,7 @@ use CodeIgniter\HTTP\IncomingRequest; use CodeIgniter\HTTP\Response; use CodeIgniter\Test\CIUnitTestCase; +use Config\App; use Config\Honeypot as HoneypotConfig; /** @@ -42,14 +44,16 @@ final class HoneypotTest extends CIUnitTestCase protected function setUp(): void { parent::setUp(); + $this->config = new HoneypotConfig(); $this->honeypot = new Honeypot($this->config); unset($_POST[$this->config->name]); $_SERVER['REQUEST_METHOD'] = 'POST'; $_POST[$this->config->name] = 'hey'; - $this->request = Services::request(null, false); - $this->response = Services::response(); + + $this->request = Services::request(null, false); + $this->response = Services::response(); } public function testAttachHoneypot() @@ -77,6 +81,25 @@ public function testAttachHoneypotAndContainer() $this->assertSame($expected, $this->response->getBody()); } + public function testAttachHoneypotAndContainerWithCSP() + { + $this->resetServices(); + + $config = new App(); + $config->CSPEnabled = true; + Factories::injectMock('config', 'App', $config); + $this->response = Services::response($config, false); + + $this->config = new HoneypotConfig(); + $this->honeypot = new Honeypot($this->config); + + $this->response->setBody('
'); + $this->honeypot->attachHoneypot($this->response); + + $regex = '!
!u'; + $this->assertMatchesRegularExpression($regex, $this->response->getBody()); + } + public function testHasntContent() { unset($_POST[$this->config->name]); From 4a1d91e956f86dfe650764966a598420adbdc361 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 28 Dec 2022 09:10:59 +0900 Subject: [PATCH 11/11] docs: fix typo Co-authored-by: MGatner --- app/Config/Honeypot.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Config/Honeypot.php b/app/Config/Honeypot.php index 019b48acf9de..67ebcb0ee74c 100644 --- a/app/Config/Honeypot.php +++ b/app/Config/Honeypot.php @@ -29,7 +29,7 @@ class Honeypot extends BaseConfig /** * Honeypot container * - * If you enables CSP, you can remove `style="display:none"`. + * If you enabled CSP, you can remove `style="display:none"`. */ public string $container = '
{template}
';