Skip to content

Commit edba633

Browse files
MatTheCatMathieu
authored andcommitted
Document the new NoSuspiciousCharacters constraint
1 parent 647da19 commit edba633

File tree

2 files changed

+150
-0
lines changed

2 files changed

+150
-0
lines changed
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
NoSuspiciousCharacters
2+
======================
3+
4+
A good thing with Unicode is that it allows to use (almost) every imaginable character.
5+
A bad thing is that this makes spoofing rather easy: "symfony.com" and "ѕymfony.com"
6+
look similar, but the latter actually starts with a `cyrillic small letter dze`_.
7+
This is why it is recommended to check user-submitted, public-facing identifiers for
8+
suspicious characters to prevent spoofing attempts.
9+
10+
This constraint validates that a string (or :phpclass:`Stringable`) is not suspicious
11+
because of its characters. As it leverages PHP's :phpclass:`Spoofchecker`, the intl
12+
extension must be enabled to use it.
13+
14+
========== ===================================================================
15+
Applies to :ref:`property or method <validation-property-target>`
16+
Class :class:`Symfony\\Component\\Validator\\Constraints\\NoSuspiciousCharacters`
17+
Validator :class:`Symfony\\Component\\Validator\\Constraints\\NoSuspiciousCharactersValidator`
18+
========== ===================================================================
19+
20+
Basic Usage
21+
-----------
22+
23+
The following constraint will ensures a username cannot be spoofed
24+
by using many detection mechanisms:
25+
26+
.. configuration-block::
27+
28+
.. code-block:: php-attributes
29+
30+
// src/Entity/User.php
31+
namespace App\Entity;
32+
33+
use Symfony\Component\Validator\Constraints as Assert;
34+
35+
class User
36+
{
37+
#[Assert\NoSuspiciousCharacters]
38+
private string $username;
39+
}
40+
41+
.. code-block:: yaml
42+
43+
# config/validator/validation.yaml
44+
App\Entity\User:
45+
properties:
46+
username:
47+
- NoSuspiciousCharacters: ~
48+
49+
.. code-block:: xml
50+
51+
<!-- config/validator/validation.xml -->
52+
<?xml version="1.0" encoding="UTF-8" ?>
53+
<constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping"
54+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
55+
xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping https://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd">
56+
57+
<class name="App\Entity\User">
58+
<property name="username">
59+
<constraint name="NoSuspiciousCharacters"/>
60+
</property>
61+
</class>
62+
</constraint-mapping>
63+
64+
.. code-block:: php
65+
66+
// src/Entity/User.php
67+
namespace App\Entity;
68+
69+
use Symfony\Component\Validator\Constraints as Assert;
70+
use Symfony\Component\Validator\Mapping\ClassMetadata;
71+
72+
class User
73+
{
74+
public static function loadValidatorMetadata(ClassMetadata $metadata)
75+
{
76+
$metadata->addPropertyConstraint('username', new Assert\NoSuspiciousCharacters());
77+
}
78+
}
79+
80+
.. include:: /reference/constraints/_empty-values-are-valid.rst.inc
81+
82+
Options
83+
-------
84+
85+
``checks``
86+
~~~~~~~~~~
87+
88+
**type**: ``int`` **default**: all
89+
90+
This option is a bitmask of the checks you want to perform on the string:
91+
92+
* ``NoSuspiciousCharacters::CHECK_RESTRICTION_LEVEL`` checks for the configured :ref:`restriction level <restrictionlevel>`.
93+
* ``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.
94+
* ``NoSuspiciousCharacters::CHECK_CHAR_LIMIT`` checks for characters missing from the configured set (see :ref:`locales <locales>`).
95+
* ``NoSuspiciousCharacters::CHECK_MIXED_NUMBERS`` checks for numbers from different numbering systems.
96+
* ``NoSuspiciousCharacters::CHECK_HIDDEN_OVERLAY`` checks for combining characters hidden in their preceding one.
97+
98+
``restrictionLevel``
99+
~~~~~~~~~~~~~~~~~~~~
100+
101+
**type**: ``int`` **default**: ``NoSuspiciousCharacters::RESTRICTION_LEVEL_MODERATE`` on ICU >= 58, else ``NoSuspiciousCharacters::RESTRICTION_LEVEL_SINGLE_SCRIPT``
102+
103+
Specify ``NoSuspiciousCharacters::CHECK_RESTRICTION_LEVEL``'s requirements.
104+
Note that they all require the string's characters to match the
105+
:ref:`configured locales' <locales>`, if any
106+
(like ``NoSuspiciousCharacters::CHECK_CHAR_LIMIT`` does).
107+
108+
You can configure one of the following constants, sorted by decreasing strictness
109+
(a string passing one will pass the ones below):
110+
111+
* ``NoSuspiciousCharacters::RESTRICTION_LEVEL_ASCII`` allows strings whose characters are all in the ASCII range.
112+
* ``NoSuspiciousCharacters::RESTRICTION_LEVEL_SINGLE_SCRIPT`` allows `single-script`_ strings only.
113+
* ``NoSuspiciousCharacters::RESTRICTION_LEVEL_HIGH`` allows strings `covered`_ by any of the following sets of scripts:
114+
* Latin + Han + Bopomofo (or equivalently: Latn + Hanb)
115+
* Latin + Han + Hiragana + Katakana (or equivalently: Latn + Jpan)
116+
* Latin + Han + Hangul (or equivalently: Latn + Kore)
117+
* ``NoSuspiciousCharacters::RESTRICTION_LEVEL_MODERATE`` allows strings `covered`_ by Latin and any one other `Recommended`_ or `Limited Use`_ script, except Cyrillic, Greek, and Cherokee.
118+
* ``NoSuspiciousCharacters::RESTRICTION_LEVEL_MINIMAL`` allows strings passing the ``NoSuspiciousCharacters::CHECK_CHAR_LIMIT`` check.
119+
120+
You can also configure ``NoSuspiciousCharacters::RESTRICTION_LEVEL_NONE``, which has
121+
the same effect than disabling ``NoSuspiciousCharacters::CHECK_RESTRICTION_LEVEL``.
122+
123+
.. note::
124+
125+
If the intl extension has been compiled against ICU < 58, only
126+
``NoSuspiciousCharacters::RESTRICTION_LEVEL_SINGLE_SCRIPT``
127+
will be available.
128+
129+
``locales``
130+
~~~~~~~~~~~~~~~~~~
131+
132+
**type**: ``array`` **default**: :ref:`framework.enabled_locales <reference-enabled-locales>`
133+
134+
Configures the set of locales used by ``NoSuspiciousCharacters::CHECK_RESTRICTION_LEVEL``
135+
and ``NoSuspiciousCharacters::CHECK_CHAR_LIMIT``. It will restrict the characters to
136+
those normally used with the associated languages.
137+
138+
Passing an empty array will disable this restriction.
139+
140+
141+
.. include:: /reference/constraints/_groups-option.rst.inc
142+
143+
.. include:: /reference/constraints/_payload-option.rst.inc
144+
145+
.. _`cyrillic small letter dze`: https://graphemica.com/%D1%95
146+
.. _`single-script`: https://unicode.org/reports/tr39/#def-single-script
147+
.. _`covered`: https://unicode.org/reports/tr39/#def-cover
148+
.. _`Recommended`: https://www.unicode.org/reports/tr31/#Table_Recommended_Scripts
149+
.. _`Limited Use`: https://www.unicode.org/reports/tr31/#Table_Limited_Use_Scripts

reference/constraints/map.rst.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ String Constraints
2929
* :doc:`UserPassword </reference/constraints/UserPassword>`
3030
* :doc:`NotCompromisedPassword </reference/constraints/NotCompromisedPassword>`
3131
* :doc:`CssColor </reference/constraints/CssColor>`
32+
* :doc:`NoSuspiciousCharacters </reference/constraints/NoSuspiciousCharacters>`
3233

3334
Comparison Constraints
3435
~~~~~~~~~~~~~~~~~~~~~~

0 commit comments

Comments
 (0)