Skip to content

[TEST] Enhanced Customer Data Validation to Mitigate Code Injection Risks #39131

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 154 commits into
base: 2.4-develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
154 commits
Select commit Hold shift + click to select a range
b81b800
Update validation.xml
in-session Aug 31, 2024
766c507
Update system.xml
in-session Aug 31, 2024
69bd507
Create CityValidator.php
in-session Aug 31, 2024
6085f20
Create EmailAddressValidator.php
in-session Aug 31, 2024
7aec8a0
Create ForbiddenValidator.php
in-session Aug 31, 2024
34078fe
Create NameValidator.php
in-session Aug 31, 2024
d852968
Create StreetValidator.php
in-session Aug 31, 2024
f385efc
Create TelephoneValidator.php
in-session Aug 31, 2024
0da78a1
Update CityTest.php
in-session Aug 31, 2024
7c0e834
Update NameTest.php
in-session Aug 31, 2024
1a99616
Update StreetTest.php
in-session Aug 31, 2024
725f570
Update TelephoneTest.php
in-session Aug 31, 2024
50ea5a7
Update City.php
in-session Aug 31, 2024
90bdb2b
Update Name.php
in-session Aug 31, 2024
e3888f7
Update Street.php
in-session Aug 31, 2024
8e4abb4
Update Telephone.php
in-session Aug 31, 2024
5d77af3
Create ForbiddenPattern.php
in-session Aug 31, 2024
c7d5611
Create Email.php
in-session Aug 31, 2024
da066b0
Update City.php
in-session Aug 31, 2024
5ef1e0e
Update Email.php
in-session Aug 31, 2024
6d0e0c1
Update Name.php
in-session Aug 31, 2024
29a3acc
Update Street.php
in-session Aug 31, 2024
48062db
Update Telephone.php
in-session Aug 31, 2024
7f88bc5
Update ForbiddenValidator.php
in-session Aug 31, 2024
f06b451
Update StreetValidator.php
in-session Aug 31, 2024
0c7194b
Update StreetValidator.php
in-session Aug 31, 2024
5108578
Update module.xml
in-session Aug 31, 2024
a4ea99d
Update TelephoneTest.php
in-session Aug 31, 2024
a4364bf
Update StreetTest.php
in-session Aug 31, 2024
10c41bc
Update NameTest.php
in-session Aug 31, 2024
5b113ab
Update CityTest.php
in-session Aug 31, 2024
90e86ec
Update TelephoneTest.php
in-session Aug 31, 2024
c427383
Update CityTest.php
in-session Aug 31, 2024
1e4755e
Update NameTest.php
in-session Sep 1, 2024
7451237
Update City.php
in-session Sep 1, 2024
5b52bb8
Update Email.php
in-session Sep 1, 2024
013e6fc
Update ForbiddenPattern.php
in-session Sep 1, 2024
86b0795
Update Name.php
in-session Sep 1, 2024
10f261c
Update Street.php
in-session Sep 1, 2024
e1529aa
Update Telephone.php
in-session Sep 1, 2024
ce30adc
Update CityValidator.php
in-session Sep 1, 2024
87d5a54
Update EmailAddressValidator.php
in-session Sep 1, 2024
6fe4aa5
Update ForbiddenValidator.php
in-session Sep 1, 2024
b619942
Update NameValidator.php
in-session Sep 1, 2024
88a2e08
Update StreetValidator.php
in-session Sep 1, 2024
26348b6
Update TelephoneValidator.php
in-session Sep 1, 2024
993dc1f
Update CityTest.php
in-session Sep 1, 2024
d8eea40
Update StreetTest.php
in-session Sep 1, 2024
0d18b39
Update CityTest.php
in-session Sep 1, 2024
b078606
Update StreetTest.php
in-session Sep 1, 2024
cc800cf
Update CityTest.php
in-session Sep 1, 2024
5f14dd3
Update StreetTest.php
in-session Sep 1, 2024
d64fe96
Update CityTest.php
in-session Sep 1, 2024
c0c8238
Update StreetTest.php
in-session Sep 3, 2024
525ed5e
Update CityTest.php
in-session Sep 3, 2024
dcf5ce8
Update City.php
in-session Sep 3, 2024
ff31362
Update Email.php
in-session Sep 3, 2024
3fc867d
Update ForbiddenPattern.php
in-session Sep 3, 2024
2431ded
Update Name.php
in-session Sep 3, 2024
39d58a6
Update Street.php
in-session Sep 3, 2024
ea79f90
Update Telephone.php
in-session Sep 3, 2024
730a857
Update CityTest.php
in-session Sep 3, 2024
3674771
Update NameTest.php
in-session Sep 3, 2024
6d888d2
Update StreetTest.php
in-session Sep 3, 2024
3221234
Update TelephoneTest.php
in-session Sep 3, 2024
3187b67
Update CityValidator.php
in-session Sep 3, 2024
395e0c4
Update EmailAddressValidator.php
in-session Sep 3, 2024
43bcc10
Update ForbiddenValidator.php
in-session Sep 3, 2024
6d96c73
Update NameValidator.php
in-session Sep 3, 2024
7349fc4
Update StreetValidator.php
in-session Sep 3, 2024
7522e2c
Update TelephoneValidator.php
in-session Sep 3, 2024
75927b0
Update ForbiddenValidator.php
in-session Sep 3, 2024
4c414cb
Update system.xml
in-session Sep 3, 2024
664d41c
Delete app/code/Magento/Customer/Model/Validator/Email.php
in-session Sep 3, 2024
21e5b2d
Delete app/code/Magento/Security/Model/Validator/Pattern/CityValidato…
in-session Sep 3, 2024
5ec5939
Delete app/code/Magento/Security/Model/Validator/Pattern/EmailAddress…
in-session Sep 3, 2024
974af51
Delete app/code/Magento/Security/Model/Validator/Pattern/ForbiddenVal…
in-session Sep 3, 2024
d083bb8
Delete app/code/Magento/Security/Model/Validator/Pattern/NameValidato…
in-session Sep 3, 2024
c591993
Delete app/code/Magento/Security/Model/Validator/Pattern/StreetValida…
in-session Sep 3, 2024
0dae394
Delete app/code/Magento/Security/Model/Validator/Pattern/TelephoneVal…
in-session Sep 3, 2024
a3db525
Create CityValidator.php
in-session Sep 3, 2024
bab0f30
Create EmailAddressValidator.php
in-session Sep 3, 2024
c72b1d2
Create ForbiddenValidator.php
in-session Sep 3, 2024
a8e4599
Create NameValidator.php
in-session Sep 3, 2024
c351366
Create StreetValidator.php
in-session Sep 3, 2024
eda0e0c
Create TelephoneValidator.php
in-session Sep 3, 2024
d66a4cb
Update system.xml
in-session Sep 3, 2024
4275bab
Create Email.php
in-session Sep 3, 2024
a87f13a
Update City.php
in-session Sep 3, 2024
3d99554
Update ForbiddenPattern.php
in-session Sep 3, 2024
da11da8
Update Name.php
in-session Sep 3, 2024
b4aeac3
Update Street.php
in-session Sep 3, 2024
dc79eb8
Update Telephone.php
in-session Sep 3, 2024
d30a060
Update SubscriptionManager.php
in-session Sep 3, 2024
69fb939
Create validation.xml
in-session Sep 3, 2024
413456e
Create Email.php
in-session Sep 3, 2024
d0b9143
Update CityTest.php
in-session Sep 3, 2024
add1b95
Update NameTest.php
in-session Sep 3, 2024
0e650e4
Update StreetTest.php
in-session Sep 3, 2024
76f0956
Update TelephoneTest.php
in-session Sep 3, 2024
8216493
Create validation.xml
in-session Sep 3, 2024
a12d0eb
Update Mail.php
in-session Sep 3, 2024
abcb9cb
Create Email.php
in-session Sep 3, 2024
b830fda
Create ForbiddenPattern.php
in-session Sep 3, 2024
e2e0e4f
Update Review.php
in-session Sep 3, 2024
4984bbc
Create validation.xml
in-session Sep 3, 2024
001a718
Create Email.php
in-session Sep 3, 2024
2832a80
Create ForbiddenPattern.php
in-session Sep 3, 2024
c32ec77
Update module.xml
in-session Sep 3, 2024
ad35181
Update CityValidator.php
in-session Sep 3, 2024
3254daa
Update CityValidator.php
in-session Sep 3, 2024
8eaabb4
Update NameValidator.php
in-session Sep 3, 2024
2862bdd
Update Name.php
in-session Sep 9, 2024
591020c
Merge branch '2.4-develop' into patch-23
in-session Sep 9, 2024
28eca91
Update NameTest.php
in-session Sep 12, 2024
25caa34
Merge branch '2.4-develop' into patch-23
in-session Sep 12, 2024
fc3bf8a
Update Name.php
in-session Sep 12, 2024
bd00a9f
Update NameTest.php
in-session Sep 12, 2024
5bf3e12
Merge branch '2.4-develop' into patch-23
in-session Sep 13, 2024
2994442
Update NameValidator.php
in-session Sep 13, 2024
5270e46
Update Name.php
in-session Sep 13, 2024
18f4cd1
Merge branch '2.4-develop' into patch-23
in-session Sep 13, 2024
3220efb
Update CityTest.php
in-session Oct 31, 2024
8c15779
Update StreetTest.php
in-session Oct 31, 2024
2eab326
Update TelephoneTest.php
in-session Oct 31, 2024
c64a3e2
Update TelephoneTest.php
in-session Oct 31, 2024
8e9e589
Update NameTest.php
in-session Oct 31, 2024
0cdde96
Update Mail.php
in-session Oct 31, 2024
ff6790d
Update Email.php
in-session Oct 31, 2024
e5d53de
Update ForbiddenPattern.php
in-session Oct 31, 2024
4805551
Update validation.xml
in-session Oct 31, 2024
b03042e
Update City.php
in-session Oct 31, 2024
e360650
Update Email.php
in-session Oct 31, 2024
04ce3a1
Update ForbiddenPattern.php
in-session Oct 31, 2024
058b34d
Update Name.php
in-session Oct 31, 2024
77fb50e
Update CityValidator.php
in-session Oct 31, 2024
23b9d7d
Update EmailAddressValidator.php
in-session Oct 31, 2024
fa35240
Update ForbiddenValidator.php
in-session Oct 31, 2024
fc5ad51
Update NameValidator.php
in-session Oct 31, 2024
27a238b
Update StreetValidator.php
in-session Oct 31, 2024
5b1262c
Update TelephoneValidator.php
in-session Oct 31, 2024
dcd22d0
Update Street.php
in-session Oct 31, 2024
fa676fd
Update Telephone.php
in-session Oct 31, 2024
31a7f66
Update system.xml
in-session Oct 31, 2024
c7e77d2
Update validation.xml
in-session Oct 31, 2024
bd3503a
Update SubscriptionManager.php
in-session Oct 31, 2024
07db6b7
Update Email.php
in-session Oct 31, 2024
f532aa6
Update validation.xml
in-session Oct 31, 2024
a75c31e
Update Review.php
in-session Oct 31, 2024
9467bf8
Update Email.php
in-session Oct 31, 2024
13c51da
Update ForbiddenPattern.php
in-session Oct 31, 2024
54014f9
Update validation.xml
in-session Oct 31, 2024
ef29eb4
Merge branch '2.4-develop' into patch-23
in-session Oct 31, 2024
fe610df
Merge branch '2.4-develop' into patch-23
in-session Nov 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 37 additions & 3 deletions app/code/Magento/Contact/Model/Mail.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
* Copyright 2024 Adobe
* All Rights Reserved.
*/
namespace Magento\Contact\Model;

Expand All @@ -10,6 +10,9 @@
use Magento\Store\Model\StoreManagerInterface;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\App\Area;
use Magento\Framework\Validator\Factory as ValidatorFactory;
use Magento\Framework\Validator\Exception as ValidatorException;
use Magento\Framework\DataObject;

class Mail implements MailInterface
{
Expand All @@ -33,24 +36,32 @@ class Mail implements MailInterface
*/
private $storeManager;

/**
* @var ValidatorFactory
*/
private $validatorFactory;

/**
* Initialize dependencies.
*
* @param ConfigInterface $contactsConfig
* @param TransportBuilder $transportBuilder
* @param StateInterface $inlineTranslation
* @param StoreManagerInterface|null $storeManager
* @param ValidatorFactory $validatorFactory
*/
public function __construct(
ConfigInterface $contactsConfig,
TransportBuilder $transportBuilder,
StateInterface $inlineTranslation,
StoreManagerInterface $storeManager = null
StoreManagerInterface $storeManager = null,
ValidatorFactory $validatorFactory
) {
$this->contactsConfig = $contactsConfig;
$this->transportBuilder = $transportBuilder;
$this->inlineTranslation = $inlineTranslation;
$this->storeManager = $storeManager ?: ObjectManager::getInstance()->get(StoreManagerInterface::class);
$this->validatorFactory = $validatorFactory;
}

/**
Expand All @@ -59,9 +70,13 @@ public function __construct(
* @param string $replyTo
* @param array $variables
* @return void
* @throws ValidatorException
*/
public function send($replyTo, array $variables)
{
// Perform validation before sending email
$this->_validate($variables['data']);

/** @see \Magento\Contact\Controller\Index\Post::validatedParams() */
$replyToName = !empty($variables['data']['name']) ? $variables['data']['name'] : null;

Expand All @@ -86,4 +101,23 @@ public function send($replyTo, array $variables)
$this->inlineTranslation->resume();
}
}

/**
* Validate the contact form data.
*
* @param DataObject $data
* @throws ValidatorException
*/
protected function _validate(DataObject $data)
{
$validator = $this->validatorFactory->createValidator('contact', 'save');

if (!$validator->isValid($data)) {
throw new ValidatorException(
null,
null,
$validator->getMessages()
);
}
}
}
98 changes: 98 additions & 0 deletions app/code/Magento/Contact/Model/Validator/Email.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<?php
/**
* Copyright 2024 Adobe
* All Rights Reserved.
*/
declare(strict_types=1);

namespace Magento\Contact\Model\Validator;

use Magento\Framework\Validator\AbstractValidator;
use Magento\Customer\Model\Validator\Pattern\EmailAddressValidator;
use Magento\Framework\DataObject;

/**
* Validator for email fields in contact form.
*/
class Email extends AbstractValidator
{
/**
* @var EmailAddressValidator
*/
protected $emailValidator;

/**
* Constructor.
*
* @param EmailAddressValidator $emailValidator
*/
public function __construct(EmailAddressValidator $emailValidator)
{
$this->emailValidator = $emailValidator;
}

/**
* Validate email fields.
*
* @param DataObject $data
* @return bool
*/
public function isValid($data): bool
{
if (!$this->emailValidator->isValidationEnabled()) {
return true;
}

$email = $data->getData('email');
if (empty($email)) {
return true;
}

if (!$this->validateEmailField($email)) {
return false;
}

return count($this->_messages) == 0;
}

/**
* Validate the email field.
*
* @param string|null $emailValue
* @return bool
*/
protected function validateEmailField(?string $emailValue): bool
{
if (!$this->emailValidator->isValid($emailValue)) {
parent::_addMessages(
[
__(
'Email address is not valid! Allowed characters: %1',
$this->emailValidator->allowedCharsDescription
),
]
);
return false;
}

if ($this->isBlacklistEmail($emailValue)) {
parent::_addMessages([
__('The email address or domain is blacklisted.')
]);
return false;
}

return true;
}

/**
* Check if email field is blacklisted using the EmailAddressValidator.
*
* @param string|null $emailValue
* @return bool
*/
protected function isBlacklistEmail(?string $emailValue): bool
{
return $this->emailValidator->isBlacklist($emailValue);
}
}
62 changes: 62 additions & 0 deletions app/code/Magento/Contact/Model/Validator/ForbiddenPattern.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php
/**
* Copyright 2024 Adobe
* All Rights Reserved.
*/
declare(strict_types=1);

namespace Magento\Contact\Model\Validator;

use Magento\Framework\Validator\AbstractValidator;
use Magento\Customer\Model\Validator\Pattern\ForbiddenValidator;
use Magento\Framework\DataObject;

/**
* Validator for forbidden patterns in contact form fields.
*/
class ForbiddenPattern extends AbstractValidator
{
/**
* @var ForbiddenValidator
*/
protected $forbiddenValidator;

/**
* Constructor.
*
* @param ForbiddenValidator $forbiddenValidator
*/
public function __construct(ForbiddenValidator $forbiddenValidator)
{
$this->forbiddenValidator = $forbiddenValidator;
}

/**
* Validate contact form data fields against forbidden patterns.
*
* @param DataObject $data
* @return bool
* @throws LocalizedException
*/
public function isValid($data): bool
{
if (!$this->forbiddenValidator->isValidationEnabled()) {
return true;
}

$dataFields = $data->getData();
if (empty($dataFields)) {
return true;
}

$isValid = $this->forbiddenValidator->validateDataRecursively($dataFields);

if (!$isValid) {
parent::_addMessages([
__('Fraud Protection: Forbidden pattern detected in contact form data')
]);
}

return count($this->_messages) == 0;
}
}
31 changes: 31 additions & 0 deletions app/code/Magento/Contact/etc/validation.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
* Copyright 2024 Adobe
* All Rights Reserved.
*/
-->
<validation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Validator/etc/validation.xsd">
<entity name="contact">
<rules>
<rule name="check_email">
<entity_constraints>
<constraint alias="email_validator" class="Magento\Contact\Model\Validator\Email" />
</entity_constraints>
</rule>
<rule name="check_pattern">
<entity_constraints>
<constraint alias="pattern_validator" class="Magento\Contact\Model\Validator\ForbiddenPattern" />
</entity_constraints>
</rule>
</rules>
<groups>
<group name="save">
<uses>
<use rule="check_email"/>
<use rule="check_pattern"/>
</uses>
</group>
</groups>
</entity>
</validation>
63 changes: 39 additions & 24 deletions app/code/Magento/Customer/Model/Validator/City.php
Original file line number Diff line number Diff line change
@@ -1,61 +1,76 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
* Copyright 2024 Adobe
* All Rights Reserved.
*/
declare(strict_types=1);

namespace Magento\Customer\Model\Validator;

use Magento\Customer\Model\Customer;
use Magento\Framework\Validator\AbstractValidator;
use Magento\Customer\Model\Validator\Pattern\CityValidator;

/**
* Customer city fields validator.
*/
class City extends AbstractValidator
{
/**
* Allowed characters:
* @var CityValidator
*/
private CityValidator $cityValidator;

/**
* Constructor.
*
* \p{L}: Unicode letters.
* \p{M}: Unicode marks (diacritic marks, accents, etc.).
* ': Apostrophe mark.
* \s: Whitespace characters (spaces, tabs, newlines, etc.).
* @param CityValidator $cityValidator
*/
private const PATTERN_CITY = '/(?:[\p{L}\p{M}\s\-\']{1,100})/u';
public function __construct(CityValidator $cityValidator)
{
$this->cityValidator = $cityValidator;
}

/**
* Validate city fields.
* Validate city field.
*
* @param Customer $customer
* @param Customer $entity
* @return bool
*/
public function isValid($customer)
public function isValid($entity): bool
{
if (!$this->isValidCity($customer->getCity())) {
parent::_addMessages([[
'city' => "Invalid City. Please use A-Z, a-z, 0-9, -, ', spaces"
]]);
if (!$this->cityValidator->isValidationEnabled()) {
return true;
}

$cityField = $entity->getCity();
if (empty($cityField)) {
return true;
}

if (!$this->validateCityField($cityField)) {
parent::_addMessages(
[
__(
'%1 is not valid! Allowed characters: %2',
'City',
$this->cityValidator->allowedCharsDescription
),
]
);
}

return count($this->_messages) == 0;
}

/**
* Check if city field is valid.
* Validate the city field.
*
* @param string|null $cityValue
* @return bool
*/
private function isValidCity($cityValue)
private function validateCityField(?string $cityValue): bool
{
if ($cityValue != null) {
if (preg_match(self::PATTERN_CITY, $cityValue, $matches)) {
return $matches[0] == $cityValue;
}
}

return true;
return $this->cityValidator->isValid($cityValue);
}
}
Loading