|
| 1 | +NoSuspiciousCharacters |
| 2 | +====================== |
| 3 | + |
| 4 | +.. versionadded:: 6.3 |
| 5 | + |
| 6 | + The ``NoSuspiciousCharacters`` constraint was introduced in Symfony 6.3. |
| 7 | + |
| 8 | +.. |
| 9 | +
|
| 10 | + Because Unicode contains such a large number of characters and incorporates |
| 11 | + the varied writing systems of the world, incorrect usage can expose programs |
| 12 | + or systems to possible security attacks. |
| 13 | + |
| 14 | + `Unicode® Technical Standard #39`_ |
| 15 | + |
| 16 | +"symfony.com" and "ѕymfony.com" look similar, but the latter actually starts with a |
| 17 | +`cyrillic small letter dze`_. It could make a user think they'll navigate to Symfony's |
| 18 | +website, whereas it would be somewhere else. |
| 19 | +This is a kind of `spoofing attack`_ (called "IDN homograph attack"). It tries to |
| 20 | +identify something as something else to exploit the resulting confusion. |
| 21 | +This is why it is recommended to check user-submitted, public-facing identifiers for |
| 22 | +suspicious characters in order to prevent such attacks. |
| 23 | + |
| 24 | +This constraint ensures strings or :phpclass:`Stringable`s do not include any |
| 25 | +suspicious characters. As it leverages PHP's :phpclass:`Spoofchecker`, the intl |
| 26 | +extension must be enabled to use it. |
| 27 | + |
| 28 | +========== =================================================================== |
| 29 | +Applies to :ref:`property or method <validation-property-target>` |
| 30 | +Class :class:`Symfony\\Component\\Validator\\Constraints\\NoSuspiciousCharacters` |
| 31 | +Validator :class:`Symfony\\Component\\Validator\\Constraints\\NoSuspiciousCharactersValidator` |
| 32 | +========== =================================================================== |
| 33 | + |
| 34 | +Basic Usage |
| 35 | +----------- |
| 36 | + |
| 37 | +The following constraint will ensures a username cannot be spoofed by using many |
| 38 | +detection mechanisms: |
| 39 | + |
| 40 | +.. configuration-block:: |
| 41 | + |
| 42 | + .. code-block:: php-attributes |
| 43 | +
|
| 44 | + // src/Entity/User.php |
| 45 | + namespace App\Entity; |
| 46 | +
|
| 47 | + use Symfony\Component\Validator\Constraints as Assert; |
| 48 | +
|
| 49 | + class User |
| 50 | + { |
| 51 | + #[Assert\NoSuspiciousCharacters] |
| 52 | + private string $username; |
| 53 | + } |
| 54 | +
|
| 55 | + .. code-block:: yaml |
| 56 | +
|
| 57 | + # config/validator/validation.yaml |
| 58 | + App\Entity\User: |
| 59 | + properties: |
| 60 | + username: |
| 61 | + - NoSuspiciousCharacters: ~ |
| 62 | +
|
| 63 | + .. code-block:: xml |
| 64 | +
|
| 65 | + <!-- config/validator/validation.xml --> |
| 66 | + <?xml version="1.0" encoding="UTF-8" ?> |
| 67 | + <constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping" |
| 68 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| 69 | + xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping https://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd"> |
| 70 | +
|
| 71 | + <class name="App\Entity\User"> |
| 72 | + <property name="username"> |
| 73 | + <constraint name="NoSuspiciousCharacters"/> |
| 74 | + </property> |
| 75 | + </class> |
| 76 | + </constraint-mapping> |
| 77 | +
|
| 78 | + .. code-block:: php |
| 79 | +
|
| 80 | + // src/Entity/User.php |
| 81 | + namespace App\Entity; |
| 82 | +
|
| 83 | + use Symfony\Component\Validator\Constraints as Assert; |
| 84 | + use Symfony\Component\Validator\Mapping\ClassMetadata; |
| 85 | +
|
| 86 | + class User |
| 87 | + { |
| 88 | + public static function loadValidatorMetadata(ClassMetadata $metadata) |
| 89 | + { |
| 90 | + $metadata->addPropertyConstraint('username', new Assert\NoSuspiciousCharacters()); |
| 91 | + } |
| 92 | + } |
| 93 | +
|
| 94 | +.. include:: /reference/constraints/_empty-values-are-valid.rst.inc |
| 95 | + |
| 96 | +Options |
| 97 | +------- |
| 98 | + |
| 99 | +``checks`` |
| 100 | +~~~~~~~~~~ |
| 101 | + |
| 102 | +**type**: ``integer`` **default**: all |
| 103 | + |
| 104 | +This option is a bitmask of the checks you want to perform on the string: |
| 105 | + |
| 106 | +* ``NoSuspiciousCharacters::CHECK_INVISIBLE`` checks for the presence of invisible characters such as zero-width spaces, or character sequences that are likely not to display, such as multiple occurrences of the same non-spacing mark. |
| 107 | +* ``NoSuspiciousCharacters::CHECK_MIXED_NUMBERS`` (usable with ICU 58 or higher) checks for numbers from different numbering systems. |
| 108 | +* ``NoSuspiciousCharacters::CHECK_HIDDEN_OVERLAY`` (usable with ICU 62 or higher) checks for combining characters hidden in their preceding one. |
| 109 | + |
| 110 | +You can also configure additional requirements using :ref:`locales <locales>` and |
| 111 | +:ref:`restrictionLevel <restrictionlevel>`. |
| 112 | + |
| 113 | +``locales`` |
| 114 | +~~~~~~~~~~~ |
| 115 | + |
| 116 | +**type**: ``array`` **default**: :ref:`framework.enabled_locales <reference-enabled-locales>` |
| 117 | + |
| 118 | +Restrict the string's characters to those normally used with the associated languages. |
| 119 | + |
| 120 | +For example, the character "π" would be considered suspicious if you restricted the |
| 121 | +locale to "English", because the Greek script is not associated with it. |
| 122 | + |
| 123 | +Passing an empty array, or configuring :ref:`restrictionLevel <restrictionlevel>` to |
| 124 | +``NoSuspiciousCharacters::RESTRICTION_LEVEL_NONE`` will disable this requirement. |
| 125 | + |
| 126 | +``restrictionLevel`` |
| 127 | +~~~~~~~~~~~~~~~~~~~~ |
| 128 | + |
| 129 | +**type**: ``integer`` **default**: ``NoSuspiciousCharacters::RESTRICTION_LEVEL_MODERATE`` on ICU >= 58, otherwise ``NoSuspiciousCharacters::RESTRICTION_LEVEL_SINGLE_SCRIPT`` |
| 130 | + |
| 131 | +Configures the set of acceptable characters for the validated string through a |
| 132 | +specified "level": |
| 133 | + |
| 134 | +* ``NoSuspiciousCharacters::RESTRICTION_LEVEL_MINIMAL`` requires the string's characters to match :ref:`the configured locales <locales>`'. |
| 135 | +* ``NoSuspiciousCharacters::RESTRICTION_LEVEL_MODERATE`` also requires the string to be `covered`_ by Latin and any one other `Recommended`_ or `Limited Use`_ script, except Cyrillic, Greek, and Cherokee. |
| 136 | +* ``NoSuspiciousCharacters::RESTRICTION_LEVEL_HIGH`` (usable with ICU 58 or higher) also requires the string to be `covered`_ by any of the following sets of scripts: |
| 137 | + |
| 138 | + * Latin + Han + Bopomofo (or equivalently: Latn + Hanb) |
| 139 | + * Latin + Han + Hiragana + Katakana (or equivalently: Latn + Jpan) |
| 140 | + * Latin + Han + Hangul (or equivalently: Latn + Kore) |
| 141 | +* ``NoSuspiciousCharacters::RESTRICTION_LEVEL_SINGLE_SCRIPT`` also requires the string to be `single-script`_. |
| 142 | +* ``NoSuspiciousCharacters::RESTRICTION_LEVEL_ASCII`` (usable with ICU 58 or higher) also requires the string's characters to be in the ASCII range. |
| 143 | + |
| 144 | +You can accept all characters by setting this option to |
| 145 | +``NoSuspiciousCharacters::RESTRICTION_LEVEL_NONE``. |
| 146 | + |
| 147 | +.. include:: /reference/constraints/_groups-option.rst.inc |
| 148 | + |
| 149 | +.. include:: /reference/constraints/_payload-option.rst.inc |
| 150 | + |
| 151 | +.. _`Unicode® Technical Standard #39`: https://unicode.org/reports/tr39/ |
| 152 | +.. _`cyrillic small letter dze`: https://graphemica.com/%D1%95 |
| 153 | +.. _`spoofing attack`: https://en.wikipedia.org/wiki/Spoofing_attack |
| 154 | +.. _`single-script`: https://unicode.org/reports/tr39/#def-single-script |
| 155 | +.. _`covered`: https://unicode.org/reports/tr39/#def-cover |
| 156 | +.. _`Recommended`: https://www.unicode.org/reports/tr31/#Table_Recommended_Scripts |
| 157 | +.. _`Limited Use`: https://www.unicode.org/reports/tr31/#Table_Limited_Use_Scripts |
0 commit comments