Skip to content
← Tous les articles
· Delta1 Labs LicensingSécuritéGuide

Faire confiance à l'horloge : comment le licensing survit au recul de date

Les essais et les abonnements expirent à une date — mais l'horloge de l'appareil est contrôlée par l'attaquant, et la reculer est la plus vieille astuce pour ranimer une licence expirée. Voici pourquoi vous ne pouvez pas faire confiance à l'heure locale, et les techniques de point haut et d'heure serveur qui défendent l'expiration sans punir les utilisateurs honnêtes.

Presque toute licence à durée limitée se résume à une comparaison : maintenant est-il postérieur à la date d”expiration ? Le problème est le mot maintenant. Sur l”appareil de l”utilisateur, « maintenant » est ce que dit l”horloge système, et l”horloge système est entièrement sous le contrôle de l”utilisateur. La reculer au mois dernier est la façon la plus ancienne et la plus fiable de ranimer un essai expiré ou un abonnement échu — et une vérification de licence qui fait confiance à DateTime.UtcNow tombe droit dedans. Défendre l”expiration signifie traiter l”heure locale comme un indice, pas comme un fait.

Pourquoi la vérification naïve échoue

L”implémentation tentante est aussi celle qui est cassée :

// DON'T: trusts an attacker-controlled clock as the only source of time.
if (DateTime.UtcNow > license.ExpiryUtc)
    Deactivate();

Rien ici n”est faux en tant que code ; la faille est le modèle de confiance. DateTime.UtcNow lit l”horloge du système d”exploitation, et l”utilisateur peut régler l”horloge de l”OS sur ce qu”il veut. Dès que l”essai se termine, il remet la date au jour d”installation et la comparaison bascule sur « valide » pour toujours. Pire, elle échoue en silence — pas d”erreur, pas de signal d”altération, juste une licence qui tranquillement n”expire jamais. Toute logique d”expiration qui n”a que l”horloge locale en entrée a déjà perdu ; il vous faut une source de temps que l”utilisateur ne peut pas rembobiner.

Le point haut : le temps n’avance que

Vous ne pouvez pas empêcher un utilisateur de changer son horloge, mais vous pouvez remarquer quand le temps semble reculer. Tenez un point haut persisté — l”instant le plus récent que l”app ait jamais observé — et faites-le avancer, sans jamais le faire reculer. À chaque vérification, si l”horloge en direct est antérieure au point haut, l”horloge a été reculée, et vous utilisez le point haut comme le « maintenant » effectif :

DateTime HighWaterMark = LoadPersistedHighWater();   // last time we ever saw

DateTime EffectiveNow()
{
    var clock = DateTime.UtcNow;
    if (clock < HighWaterMark)
        return HighWaterMark;        // clock went backwards → don't trust it

    HighWaterMark = clock;           // advance and persist
    PersistHighWater(HighWaterMark);
    return clock;
}

// expiry check now uses EffectiveNow(), not the raw clock
if (EffectiveNow() > license.ExpiryUtc)
    Deactivate();

Désormais, reculer l”horloge ne sert à rien : le temps effectif ne descend jamais sous le point le plus éloigné que l”app a déjà atteint. Si un essai a tourné 25 de ses 30 jours, le point haut est au jour 25, et régler l”horloge au jour 1 laisse le temps effectif au jour 25. L”expiration arrive quand même à l”heure.

Quelques détails rendent cela robuste. Persistez le point haut à un endroit non évident et non lié à un seul fichier que l”utilisateur peut supprimer pour le réinitialiser — le même stockage signé et inviolable qui détient le lease de licence est un bon foyer. Faites-le avancer depuis toutes les sources de temps fiables que vous voyez, pas seulement le lancement de l”app : chaque check-in en ligne est une occasion de le pousser en avant avec une heure faisant autorité. Et autorisez une petite tolérance (quelques minutes) pour que la dérive d”horloge ordinaire et les corrections NTP ne s”enregistrent pas comme des attaques.

installationjour 25 (point haut)expirationle point haut avance →horloge reculée au jour 1…le maintenant effectif reste au jour 25

L’heure du serveur fait autorité

Le point haut défend hors ligne, mais c”est un cliquet, pas une horloge — il sait que le temps a avancé, pas la date véritable. La réponse faisant autorité vient du serveur lors du check-in. Quand l”app contacte le service de licences pour valider ou renouveler, la réponse porte l”heure du serveur, et c”est le vrai « maintenant » : elle ne peut pas être altérée sur l”appareil, et elle fait à la fois avancer le point haut et ancre la prochaine fenêtre hors ligne.

C”est pourquoi un lease signé et borné dans le temps se marie si bien avec le cliquet. Le serveur émet un lease valide pour une fenêtre limitée et estampillé de l”heure serveur ; entre les check-ins, l”app tourne hors ligne, utilisant le point haut pour rejeter les reculs ; au check-in suivant, le serveur réancre l”heure réelle et réémet le lease. Un utilisateur honnête hors ligne une semaine travaille toute la semaine — son horloge va bien, le point haut monte normalement, le lease est encore dans sa fenêtre. Seule une horloge reculée déclenche la vérification. (Pour le versant hors ligne de ce contrat, voir validation de licence hors ligne ; pour la clé qui porte la fenêtre, activation en environnement isolé.)

Ne punissez pas l’utilisateur honnête

Le mode d”échec à éviter est de traiter toute anomalie d”horloge comme une fraude. Les vraies horloges sont désordonnées : les portables sortent de veille avec une horloge périmée, les VM se restaurent depuis des instantanés, les batteries meurent et réinitialisent le RTC à 1970, et les voyageurs traversent des fuseaux horaires (bien que l”UTC rende cela sans objet si vous comparez en UTC). Si vous verrouillez sèchement au premier pas en arrière, vous exclurez des clients payants dont l”horloge a eu un hoquet.

Concevez la réponse pour qu”elle soit proportionnée. Une horloge antérieure au point haut n”est pas une preuve de malveillance — donc ne désactivez pas ; refusez simplement de faire confiance à l”horloge et repliez-vous sur le point haut, qui est déjà le comportement sûr. Réservez l”action dure au cas qui compte vraiment : la fenêtre du lease s”est réellement écoulée et l”app ne peut pas joindre le serveur pour renouveler. Même alors, préférez un rappel de grâce et une voie pour revalider à un verrouillage brutal. L”attaquant qui a reculé l”horloge n”en tire aucun bénéfice ; l”utilisateur honnête dont l”horloge a eu un raté ne voit rien du tout.

La version courte

L”heure locale est une entrée provenant d”une source non fiable, donc ne laissez jamais DateTime.UtcNow seul décider de l”expiration. Tenez un point haut en avance uniquement pour qu”une horloge reculée ne puisse rien dé-expirer hors ligne, prenez l”heure faisant autorité auprès du serveur à chaque check-in, et rendez votre réponse à l”altération proportionnée pour que le bruit d”horloge légitime ne coûte jamais son accès à un vrai utilisateur. L”expiration cesse d”être une date que l”utilisateur peut modifier et devient un fait que votre système contrôle réellement.

Essayez Nebula.NET

Renforcez votre code .NET en quelques minutes — commencez avec l'édition gratuite.