# Sceller un secret en lecture seule avec les propriétés readonly de PHP 8.1

> Un objet qui porte un identifiant sensible reste modifiable après sa création tant que rien ne l'en empêche explicitement. Les propriétés readonly de PHP 8.1 ferment cette possibilité.

- Auteur : WordPress Développement
- Publié le : 2022-07-20
- Mis à jour le : 2022-07-20
- Catégorie : Sécurité
- URL : https://www.wpmoderne.fr/securite/proprietes-readonly-php81-secret/

## L’essentiel

- Une propriété mutable peut être réécrite ailleurs dans le code sans avertissement
- readonly interdit toute modification après l'initialisation dans le constructeur
- Cette protection agit en mémoire, pas au niveau du stockage du secret

Un objet `JetonApi` qui encapsule un identifiant sensible peut, sans protection particulière, voir sa propriété réécrite n'importe où dans le code qui le manipule ensuite : un correctif hâtif, un test mal isolé, ou une bibliothèque tierce qui reçoit l'objet par référence peuvent tous modifier cette valeur après sa création, sans qu'aucune erreur ne le signale.

## Le problème : une propriété publique reste mutable partout

```
class JetonApi
{
    public string $valeur;
    public \DateTimeImmutable $expiration;

    public function __construct(string $valeur, \DateTimeImmutable $expiration)
    {
        $this->valeur = $valeur;
        $this->expiration = $expiration;
    }
}

$jeton = new JetonApi('a1b2c3d4e5f6', new \DateTimeImmutable('+1 hour'));

// Plus loin dans le code, potentiellement dans un tout autre fichier :
$jeton->valeur = 'valeur_de_test';
```

Cette dernière ligne s'exécute sans la moindre erreur. Si elle provient d'un test de développement oublié en production, ou d'un correctif temporaire jamais retiré, le jeton utilisé en production devient silencieusement une valeur de test, avec des conséquences qui dépendent entièrement de ce que cette valeur autorise réellement côté fournisseur d'API.

## Le snippet : verrouiller la propriété avec readonly

PHP 8.1 introduit le mot-clé `readonly`, applicable à une propriété typée, qui interdit toute modification de sa valeur après son initialisation dans le constructeur :

```
class JetonApi
{
    public function __construct(
        public readonly string $valeur,
        public readonly \DateTimeImmutable $expiration,
    ) {
    }
}

$jeton = new JetonApi('a1b2c3d4e5f6', new \DateTimeImmutable('+1 hour'));

// Cette ligne provoque desormais une erreur fatale :
// Error: Cannot modify readonly property JetonApi::$valeur
$jeton->valeur = 'valeur_de_test';
```

Toute tentative de modification après la construction de l'objet lève une erreur immédiate et explicite, quel que soit l'endroit du code d'où provient cette tentative. Un secret encapsulé de cette façon ne peut plus être altéré silencieusement par un fragment de code distant qui reçoit l'objet, volontairement ou par erreur d'inattention.

> L'essentiel à retenir : Une propriété mutable peut être réécrite ailleurs dans le code sans avertissement ; readonly interdit toute modification après l'initialisation dans le constructeur ; Cette protection agit en mémoire, pas au niveau du stockage du secret

## Ce que readonly protège, et ce qu'il ne protège pas

Cette protection agit exclusivement en mémoire, pendant l'exécution du script PHP. Elle n'a aucun effet sur la façon dont ce secret est stocké en base de données, transmis sur le réseau, ou journalisé par erreur dans un fichier de log. Un secret encapsulé dans une propriété `readonly` reste tout aussi exposé qu'avant si le reste du code le chiffre mal, l'affiche dans un message d'erreur, ou le transmet en clair à un service tiers non maîtrisé.

> readonly garantit qu'un secret ne change pas de valeur en cours de route ; il ne garantit jamais que ce secret a été bien protégé en amont ou en aval de cette portion de code.

## Variantes et limites à connaître

- Une propriété `readonly` ne peut être initialisée que depuis l'intérieur de la classe qui la déclare, généralement dans le constructeur, jamais depuis une méthode statique de fabrique appelée après coup sans passer par ce constructeur.
- Le clonage d'un objet contenant des propriétés `readonly` nécessite une attention particulière : la méthode magique `__clone()` ne peut pas réinitialiser librement ces propriétés sans lever la même erreur.
- Pour une propriété qui doit être modifiable dans de rares cas contrôlés, comme une rotation planifiée du secret, il est parfois plus adapté de créer une nouvelle instance de l'objet plutôt que de forcer une mutabilité partielle.

## Où l'appliquer en priorité dans une base de code existante

Les objets qui encapsulent un jeton d'authentification, une clé de chiffrement dérivée ou un identifiant de session méritent cette conversion en priorité, car ce sont précisément les objets dont une mutation accidentelle en cours d'exécution a les conséquences les plus difficiles à diagnostiquer après coup. Un objet de configuration générale, sans donnée sensible, tire un bénéfice moindre de cette protection et peut rester en fin de liste d'une migration progressive vers PHP 8.1.

## En résumé

Les propriétés `readonly` de PHP 8.1 offrent une garantie précise et limitée : un objet correctement construit ne peut plus voir ses valeurs internes modifiées après coup par un fragment de code distant. Cette garantie réduit une classe entière de bugs liés à une mutation accidentelle d'un secret en mémoire, sans dispenser d'une gestion rigoureuse de son stockage et de sa transmission.
