Хорошо, взгляните на спецификацию Fernet . Маркер Fernet (так называется строка, о которой вы говорите) имеет следующую структуру (где ‖
означает конкатенацию):
token = urlsafe_b64encode(Version ‖ Timestamp ‖ IV ‖ Ciphertext ‖ HMAC)
HMAC, который является последней частью токена, вычисляется из начальной части (Version ‖ Timestamp ‖ IV ‖ Ciphertext
) с использованием ключа подписи (который является первой половиной ключа), как документировано спецификация.
Проблема в том, что у вас нет ключа , поэтому единственное, что вы можете сделать, это проверить начальные поля токена после его декодирования из Base64:
-
Version
должно быть 0x80
, что означает версию 1 (опять же, как указано в спецификации).
-
Timestamp
- это временная метка, связанная с токеном: вы можете проверить, находится ли этот номер в определенном диапазоне, чтобы сбросить любой просроченный или деформированный токен.
Итак, вот что вы можете сделать, чтобы «уменьшить спам»:
from base64 import urlsafe_b64decode
from struct import unpack
from datetime import datetime, timedelta
bin_token = urlsafe_b64decode(c) # <-- c is the Fernet token you received
version, timestamp = unpack('>BQ', bin_token[:9])
tok_age = datetime.now() - datetime.fromtimestamp(timestamp)
max_age = timedelta(7) # 7 days
if version != 0x80:
print 'Invalid token version!'
if tok_age > max_age:
print 'Token expired!'
elif tok_age < timedelta(0):
print 'Token timestamp in the future! Invalid token!'
БОНУС: как я уже сказал, вы не можете проверить действительность токена, если у вас нет хотя бы ключа подписи (который является первой половиной ключа). Поэтому, конечно, следующее не относится к вашему сценарию, но давайте предположим, что у вас есть ключ подписи. В таком случае, в дополнение к вышеупомянутой проверке, которую вы все равно должны делать , вы можете сделать следующее, чтобы проверить действительность токена:
from base64 import urlsafe_b64decode
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.hmac import HMAC
from cryptography.hazmat.backends import default_backend
bin_data = urlsafe_b64decode(c)
# Assuming you have this:
signing_key = "???" # should be urlsafe_b64decode(k)[:16]
client_data = bin_data[:-32]
client_hmac = bin_data[-32:]
print 'Client HMAC:', client_hmac.encode('hex')
real_hmac = HMAC(signing_key, hashes.SHA256(), default_backend())
real_hmac.update(client_data)
real_hmac = real_hmac.finalize()
print 'Real HMAC :', real_hmac.encode('hex')
if client_hmac == real_hmac:
print 'Token seems valid!'
else:
print 'Token does NOT seem valid!'