Лицензионные ключи для своего софта: как устроена проверка

· 4 мин чтения · MTB Digital

Продавать свою программу по ключу кажется простым: выдал строку XXXX-XXXX, программа проверила её на сервере — готово. На деле первая же наивная проверка ломается за вечер: ответ сервера подделывают, ключ копируют на десять компьютеров, а программа перестаёт работать у честного покупателя, когда у него пропал интернет. Расскажем, как устроена проверка лицензий в нашем каталоге и почему именно так.

Ключ, активация и токен

Ключ — то, что покупатель видит в кабинете: MTBD-7K4Q-9TXM-2HWE. В ключах нет букв и цифр, которые легко перепутать (I и 1, O и 0), — их диктуют по телефону и переписывают с экрана.

Активация — привязка ключа к конкретному устройству или установке. Сколько активаций даёт тариф, написано на странице продукта; покупатель видит в кабинете, где ключ используется, и может сбросить активацию сам — например, при переезде на новый сервер.

Отпечаток устройства (fingerprint) — стабильная строка, которую программа вычисляет сама: из идентификатора машины, домена сайта, другой характеристики, которая не меняется от запуска к запуску. Именно по нему сервер понимает, что это то же устройство.

Токен активации — то, что программа получает при первой активации и дальше использует вместо ключа. Повторная активация с тем же отпечатком выдаёт новый токен, старый перестаёт работать.

Почему ответ сервера подписан

Если программа просто спрашивает сервер «ключ рабочий?» и верит ответу {"status": "active"}, такой ответ подделывается подменой адреса сервера или перехватом трафика. Поэтому каждый ответ нашего API лицензий подписан.

Ответ выглядит так (сокращено):

{
  "payload": "{\"activationToken\":\"…\",\"expiresAt\":null,\"fingerprint\":\"pc-1\",\"issuedAt\":\"2026-10-23T12:00:00.000Z\",\"nonce\":\"…\",\"product\":\"bot\",\"status\":\"active\"}",
  "signature": "<base64, Ed25519>"
}

payload — это строка с JSON, ключи которого отсортированы и без пробелов. Подпись Ed25519 считается над байтами этой строки. Закрытый ключ хранится только на сервере, а открытый вшивается в программу. Подделать ответ, не зная закрытого ключа, нельзя.

Важная деталь: проверять подпись нужно над строкой ровно в том виде, в каком она пришла. Если сначала разобрать JSON, а потом собрать заново, порядок ключей или пробелы могут измениться — и подпись не сойдётся.

Пример проверки на Python с библиотекой cryptography:

import base64
import json

from cryptography.hazmat.primitives.serialization import load_pem_public_key

PUBLIC_KEY = load_pem_public_key(open("license-public.pem", "rb").read())

def verified_payload(answer: dict) -> dict:
    payload = answer["payload"]
    # Бросает InvalidSignature, если ответ подделан или изменён.
    PUBLIC_KEY.verify(base64.b64decode(answer["signature"]), payload.encode("utf-8"))
    return json.loads(payload)

Что проверить после подписи

Подпись гарантирует, что ответ выдал наш сервер. Но выдать его могли другому устройству или давно. Поэтому дальше программа проверяет по порядку:

  1. product совпадает с продуктом самой программы — ответ для другого продукта не подходит.
  2. fingerprint совпадает с отпечатком этого устройства — так не сработает скопированный с другого компьютера токен.
  3. nonce совпадает с отправленным. Программа посылает случайную строку, сервер возвращает её внутри подписанного ответа — это защита от повтора старого ответа.
  4. issuedAt не старше трёх суток и не из будущего (с запасом в несколько минут на неточные часы). Иначе можно сохранить ответ «active» и подсовывать его после того, как подписка приостановлена.
  5. И только потом status: active — работать; past_due — работать и предупредить, что оплата не прошла; suspended и revoked — закрыть доступ.

Когда нет связи

Честный покупатель не должен страдать из-за того, что у него пропал интернет или наш сервер недоступен. Поэтому:

  • программа проверяет лицензию раз в сутки, а последний успешный подписанный ответ хранит у себя;
  • сохранённый ответ действует до трёх суток — этого хватает, чтобы пережить сбой связи;
  • ответы с ошибками не подписаны, и по ним программа не делает ничего необратимого: не удаляет токен и не сбрасывает настройки. Она показывает сообщение и повторяет попытку позже. Иначе любой, кто может подменить ответ, отключил бы программу у пользователя.

Что делать, если связи нет дольше трёх суток, решает сам продукт: одна программа может продолжить работу в ограниченном режиме, другой без проверки лучше остановиться.

Ограничения, о которых стоит знать

Любую проверку в программе, которая работает на чужом компьютере, можно обойти, если очень постараться: исправить код и убрать проверку совсем. Лицензирование защищает не от этого, а от массового копирования ключей и подделки ответов без правки программы. Поэтому важно, чтобы честному покупателю было удобнее заплатить: обновления и плагины к программе выдаются только по действующей лицензии.

По этой схеме работают программы из нашего каталога. Если вам нужно такое же лицензирование для своего софта — опишите задачу.

Ещё статьи