Название пакета: globus-studio/fingerprint
Назначение: серверная PHP-библиотека для построения вероятностного отпечатка пользователя, устройства или клиента по данным HTTP-запроса, окружения сервера и сетевого контекста.
Разработчик: Yevhen Leonidov
Организация: GLOBUS.studio
Целевая публикация: Packagist, установка через Composer.
Основная идея: библиотека не должна обещать абсолютную идентификацию. Она должна вычислять стабильный, объяснимый и настраиваемый fingerprint на основе доступных серверу сигналов, присваивать каждому сигналу вес, оценивать уверенность результата и позволять разработчику управлять приватностью, нормализацией, хранением и сравнением отпечатков.
- Создать современную PHP-библиотеку для идентификации клиента по серверным данным без JavaScript-зависимости.
- Поддержать разные серверные окружения: Nginx, Apache, IIS, Caddy, LiteSpeed, OpenResty, FrankenPHP, RoadRunner, Swoole, PHP-FPM, FastCGI, CGI, Apache module, CLI server для разработки.
- Обеспечить поддержку PHP 8.5 и актуальных PHP-практик: строгая типизация, readonly-объекты, enum, value objects, PSR-стандарты, статический анализ, тесты.
- Дать разработчику готовый API для:
- сбора сигналов из запроса;
- нормализации и фильтрации данных;
- вычисления стабильного хеша;
- сравнения отпечатков;
- оценки уверенности и риска;
- безопасного хранения;
- интеграции с PSR-7, Symfony, Laravel, Laminas, Slim и обычным PHP.
- Реализовать расширяемую архитектуру, чтобы можно было добавлять новые источники сигналов без изменения ядра.
- Сразу заложить требования приватности и соответствия GDPR, ePrivacy, CCPA/CPRA и локальным политикам сайта.
- Библиотека не должна использовать скрытый клиентский трекинг или обходить настройки приватности пользователя.
- Библиотека не должна позиционироваться как замена аутентификации, 2FA, сессиям или антифрод-системам.
- Библиотека не должна хранить персональные данные без явного решения приложения-потребителя.
- Библиотека не должна выполнять сетевые запросы к внешним GeoIP, threat-intelligence или proxy-detection API по умолчанию.
- Библиотека не должна зависеть от конкретного фреймворка.
- Библиотека не должна считать один IP-адрес надежным уникальным идентификатором пользователя.
- Защита аккаунта: обнаружение подозрительной смены устройства, сети, прокси или окружения.
- Антифрод: дополнительный сигнал для скоринга заказов, регистраций, платежей, форм обратной связи.
- Защита от злоупотреблений: ограничение массовых регистраций, спама, brute force, password spraying.
- Стабильные пользовательские сессии: мягкая проверка, что текущая сессия похожа на ранее подтвержденную.
- Аналитика безопасности: агрегированные отчеты по типам клиентов, прокси, CDN, аномальным заголовкам.
- Rate limiting: вспомогательный ключ рядом с IP, user id, session id и device id.
- Forensic logging: сохранение объяснимого снимка сигналов для расследования инцидентов.
- В README и документации явно указать, что fingerprint является персональными или псевдонимизированными данными в ряде юрисдикций.
- Предусмотреть режимы приватности:
strict: минимум сигналов, только низкорисковые данные, агрессивное усечение IP;balanced: рекомендованный режим, достаточный для безопасности без чрезмерного сбора;maximum: максимальное количество серверных сигналов, только при наличии правового основания;custom: явная настройка источников и весов.
- По умолчанию не сохранять сырые значения чувствительных заголовков.
- По умолчанию хешировать итоговый fingerprint с секретной солью приложения.
- Поддержать ротацию соли через версионирование hash context.
- Предусмотреть TTL для сохраненных отпечатков.
- Предусмотреть удаление, экспорт и объяснение сохраненных данных на стороне приложения.
- Документировать необходимость consent banner или legitimate interest assessment там, где это требуется.
- Добавить предупреждение: fingerprint нельзя использовать для дискриминации, скрытого слежения или обхода пользовательских настроек приватности.
- Минимальная версия:
php >= 8.3. - Обязательная поддержка и тестовая матрица: PHP 8.3, 8.4, 8.5.
- Подготовленность к PHP 9: отсутствие deprecated API, явные типы, строгие сигнатуры.
- Файл
composer.jsonдолжен содержать:"name": "globus-studio/fingerprint";"type": "library";"license": "MIT"или другая выбранная лицензия;"minimum-stability": "stable";"prefer-stable": true;- PSR-4 autoload namespace
GlobusStudio\\Fingerprint\\.
Обязательные:
json.hash.filter.mbstring, если используется нормализация Unicode.
Опциональные:
intlдля расширенной нормализации локалей и Unicode.sodiumдля keyed hashing, если выбранsodium_crypto_generichash.gmpилиbcmathне требуются.geoipне требуется, интеграции должны быть отдельными адаптерами.
Библиотека должна корректно работать в окружениях:
- Nginx + PHP-FPM.
- Apache + mod_php.
- Apache + PHP-FPM/FastCGI.
- IIS + FastCGI.
- Caddy + PHP-FPM.
- LiteSpeed/OpenLiteSpeed.
- OpenResty.
- FrankenPHP.
- RoadRunner.
- Swoole.
- ReactPHP/Amp через PSR-7 адаптер.
- Built-in PHP server для локальной разработки.
- CLI в режиме тестов через synthetic request objects.
- Framework-agnostic core: ядро не зависит от Symfony, Laravel, Laminas или PSR-7 реализаций.
- PSR-first integration: отдельные адаптеры для PSR-7
ServerRequestInterfaceи PSR-15 middleware. - Immutable DTO: собранные данные представлены неизменяемыми value objects.
- Deterministic normalization: одинаковые входные данные дают одинаковый canonical representation.
- Configurable entropy: каждый сигнал имеет вес, стабильность и чувствительность.
- Explainability: результат содержит список использованных сигналов, их normalized value hash, вес и вклад.
- Privacy by default: безопасные настройки по умолчанию.
- No hidden globals: работа с
$_SERVER,$_COOKIE,$_GET,$_POSTтолько через отдельный request adapter. - Testability: любой источник данных можно заменить synthetic fixture.
- Extensibility: новые collectors и normalizers подключаются через интерфейсы.
src/
Fingerprint.php
FingerprintBuilder.php
FingerprintResult.php
Configuration/
FingerprintConfig.php
PrivacyMode.php
HashingConfig.php
SignalConfig.php
Request/
RequestContext.php
RequestContextFactory.php
NativeServerRequestFactory.php
HeaderBag.php
ServerBag.php
CookieBag.php
Collector/
SignalCollectorInterface.php
HeaderSignalCollector.php
NetworkSignalCollector.php
TlsSignalCollector.php
CookieSignalCollector.php
ServerSignalCollector.php
ProxySignalCollector.php
FrameworkSignalCollector.php
Signal/
Signal.php
SignalName.php
SignalType.php
SignalSensitivity.php
SignalStability.php
SignalSet.php
Normalizer/
NormalizerInterface.php
HeaderNormalizer.php
IpNormalizer.php
UserAgentNormalizer.php
AcceptLanguageNormalizer.php
EncodingNormalizer.php
TimezoneNormalizer.php
Hasher/
FingerprintHasherInterface.php
HmacSha256Hasher.php
SodiumHasher.php
CanonicalJsonEncoder.php
Matcher/
FingerprintMatcher.php
MatchResult.php
MatchLevel.php
Storage/
FingerprintStorageInterface.php
InMemoryFingerprintStorage.php
Integration/
Psr7/
Psr15/
Symfony/
Laravel/
Exception/
FingerprintException.php
ConfigurationException.php
UnsupportedEnvironmentException.php
use GlobusStudio\Fingerprint\FingerprintBuilder;
use GlobusStudio\Fingerprint\Configuration\FingerprintConfig;
$config = FingerprintConfig::balanced(
secret: $_ENV['APP_FINGERPRINT_SECRET']
);
$result = FingerprintBuilder::fromGlobals($config)->build();
$fingerprintId = $result->id();
$confidence = $result->confidence();
$signals = $result->signals();$result = $fingerprinter->fromPsr7Request($request)->build();$result = $fingerprinter->fromSymfonyRequest($request)->build();$result = app(Fingerprinter::class)->fromIlluminateRequest($request)->build();$match = $matcher->compare($current, $known);
if ($match->level()->isSuspicious()) {
// trigger step-up authentication
}FingerprintResult должен содержать:
id: итоговый стабильный fingerprint hash.version: версия алгоритма.profile: имя профиля конфигурации.createdAt: время создания.confidence: число от 0 до 100.entropyScore: оценка уникальности сигналов.stabilityScore: оценка ожидаемой стабильности во времени.riskScore: дополнительный риск, если включены risk collectors.signals: список нормализованных сигналов.usedSignalNames: имена сигналов, которые вошли в итоговый hash.ignoredSignalNames: имена сигналов, отброшенные конфигурацией или пустыми значениями.environment: краткие сведения о SAPI и сервере.debug: опциональная диагностическая информация, выключена по умолчанию.
Каждый Signal должен иметь:
name: стабильное машинное имя, напримерheader.user_agent.type:header,network,tls,cookie,server,proxy,framework,derived.rawValue: исходное значение, доступно только в debug-режиме и может быть скрыто.normalizedValue: нормализованное значение или canonical representation.hashedValue: hash normalized value для безопасного объяснения.weight: вес в итоговом fingerprint.stability:volatile,medium,stable.sensitivity:low,medium,high,special.source: откуда получен сигнал, например$_SERVER.HTTP_USER_AGENT.included: попал ли сигнал в итоговый fingerprint.reason: почему сигнал включен или исключен.
Библиотека должна собирать и нормализовать следующие заголовки, если они доступны:
User-Agent.Accept.Accept-Language.Accept-Encoding.Accept-Charset, устаревший, но иногда полезный.DNT.Sec-GPC.Upgrade-Insecure-Requests.Sec-CH-UA.Sec-CH-UA-Mobile.Sec-CH-UA-Platform.Sec-CH-UA-Platform-Version.Sec-CH-UA-Arch.Sec-CH-UA-Bitness.Sec-CH-UA-Full-Version.Sec-CH-UA-Full-Version-List.Sec-CH-UA-Model.Sec-CH-UA-WoW64.Sec-Fetch-Site.Sec-Fetch-Mode.Sec-Fetch-Dest.Sec-Fetch-User.Cache-Control.Pragma.Connection, если сервер не удалил hop-by-hop headers.TE, если доступен.Via.Forwarded.X-Forwarded-For.X-Forwarded-Host.X-Forwarded-Proto.X-Forwarded-Port.X-Real-IP.True-Client-IP.CF-Connecting-IP.CF-IPCountry.CF-Ray.CF-Visitor.CDN-Loop.Fastly-Client-IP.X-Akamai-Edgescape.X-Client-IP.Client-IP.X-Cluster-Client-IP.X-Original-Forwarded-For.X-Request-IDи аналоги не должны входить в fingerprint по умолчанию, так как они request-scoped.Authorizationникогда не должен входить в fingerprint.Cookieне должен входить целиком, только явно разрешенные cookie names.Refererне должен входить по умолчанию, так как он нестабилен и чувствителен.Originможет использоваться только как request-context/risk signal, не как стабильный identity signal.
Порядок заголовков может быть полезным сигналом, но в PHP он часто недоступен или искажен сервером.
Требования:
- Реализовать
HeaderOrderSignalCollector, но сделать его опциональным. - Для PHP-FPM через Nginx и IIS считать порядок заголовков ненадежным, потому что сервер передает PHP нормализованные переменные окружения.
- Для Apache
apache_request_headers()может сохранить порядок в некоторых окружениях, но это не гарантируется стандартом. - Для PSR-7 порядок заголовков обычно зависит от реализации и может не соответствовать wire order.
- Для RoadRunner, Swoole, ReactPHP и Amp возможно получить порядок ближе к исходному, если runtime предоставляет raw request.
- В итоговом результате сигнал должен содержать
reliability: low|medium|high. - По умолчанию использовать не сырой порядок всех заголовков, а canonical sequence только безопасных header names.
- Исключить из sequence request-specific headers:
Host,Content-Length,Content-Typeдля multipart,Cookie,Authorization,X-Request-ID,Traceparent,Tracestate. - Поддержать отдельный hash
header_order_hash, если порядок действительно доступен. - В документации честно указать, что для большинства классических PHP-развертываний порядок заголовков не является надежным fingerprint-сигналом.
Для каждого заголовка нужно задать правила нормализации:
- Trim пробелов по краям.
- Collapse последовательностей whitespace там, где это безопасно.
- Header names приводить к lowercase canonical form.
- Multi-value headers сортировать только там, где порядок значения не имеет смысла.
- Для
Accept,Accept-Language,Accept-Encodingсохранять q-values, но нормализовать формат чисел. - Для
User-Agentсохранять значимые токены, но уметь строить derived profile: browser family, major version, engine, OS family, device class. - Для Client Hints парсить structured headers согласно RFC 8941 там, где применимо.
- Для
Forwardedпарсить RFC 7239. - Для
X-Forwarded-Forхранить цепочку IP только после trust proxy validation. - Для
Cookieиспользовать allowlist имен, а не все cookies. - Для заголовков с потенциальными секретами использовать denylist.
Сигналы:
remote_addr:$_SERVER['REMOTE_ADDR'].client_ip: вычисленный IP с учетом доверенных прокси.ip_version: IPv4 или IPv6.ip_prefix: усеченная сеть, например IPv4/24, IPv6/48или/56.ip_is_private.ip_is_reserved.ip_is_loopback.ip_is_link_local.ip_is_proxy_header_present.proxy_chain_length.trusted_proxy_match.asn,organization,country,region,cityтолько через опциональные провайдеры и не по умолчанию.connection_port:REMOTE_PORT, низкая стабильность, по умолчанию не включать.
Правила:
- Не использовать полный IP в режиме
strict. - В режиме
balancedиспользовать IP prefix, а не полный IP. - В режиме
maximumразрешить полный IP только еслиallowFullIpAddress(true). - Для IPv6 не использовать весь адрес как стабильный идентификатор, так как privacy extensions часто меняют interface identifier.
- Trust proxy должен быть явно настроен. Нельзя доверять
X-Forwarded-Forот любого клиента.
В PHP доступны не всегда. Поддержать как best-effort:
HTTPSflag.REQUEST_SCHEME.SERVER_PORT.SSL_PROTOCOL, если сервер передал.SSL_CIPHER, если сервер передал.SSL_CLIENT_VERIFY, если используется client certificate.SSL_CLIENT_S_DN,SSL_CLIENT_I_DN,SSL_CLIENT_M_SERIAL, только если явно разрешено и с высокой чувствительностью.HTTP2/HTTP3признаки, если сервер передаетSERVER_PROTOCOLили runtime API.
Ограничения:
- JA3/JA4 fingerprint обычно недоступен в обычном PHP за Nginx/Apache/IIS.
- Если нужен JA3/JA4, библиотека должна поддерживать внешний collector через reverse proxy, WAF, Envoy, Nginx module, OpenResty, CDN или отдельный header от доверенного инфраструктурного слоя.
- Любые TLS client certificate данные считаются sensitive/high и выключены по умолчанию.
Сигналы окружения не идентифицируют пользователя напрямую, но помогают диагностике:
server_software.server_protocol.gateway_interface.request_method.request_uri_shape, без query string по умолчанию.sapi_name.host, если разрешено.is_https.http_version.
Не включать по умолчанию в стабильный fingerprint:
REQUEST_TIME.REQUEST_TIME_FLOAT.UNIQUE_ID.REQUEST_ID.SCRIPT_FILENAME.DOCUMENT_ROOT.- Любые filesystem paths.
Подход:
- Не fingerprint-ить весь заголовок
Cookie. - Поддержать allowlist cookie names.
- Для каждой cookie можно выбрать режим:
- presence only;
- hash value;
- normalized value;
- ignored.
- Сессионные cookie вроде
PHPSESSID,laravel_session,symfony_sessionпо умолчанию использовать только как auxiliary/session signal, не как device fingerprint. - Cookie consent state можно включать как risk/context signal.
- Значения cookies считать high sensitivity.
Из User-Agent и Client Hints вычислять:
- Browser family.
- Browser major version.
- Browser full version, если доступно и разрешено.
- Rendering engine.
- OS family.
- OS major version.
- Device class: desktop, mobile, tablet, bot, tv, console, unknown.
- Bot likelihood.
- Client hints consistency: совпадают ли UA и CH.
- Frozen UA detection.
Рекомендация: использовать ua-parser/uap-php или отдельный lightweight parser как optional dependency. Ядро не должно жестко зависеть от тяжелого парсера.
Опциональные риск-сигналы:
- Несогласованность
User-AgentиSec-CH-UA. - Отсутствие типичных browser headers.
- Подозрительный порядок или набор заголовков.
- Наличие
Via,Forwarded, CDN headers. - Много IP в
X-Forwarded-For. - Private IP в forwarded chain.
- Несоответствие
HostиX-Forwarded-Host. - Несоответствие
X-Forwarded-Protoи HTTPS. - Headless/browser automation признаки только по server-side headers, без JS.
- CLI/library user agents: curl, wget, python-requests, Guzzle, Go-http-client, Java, okhttp, httpx.
- Empty или слишком короткий
Accept-Language. - Нестандартный
Accept-Encoding. - Нестандартные
Sec-Fetch-*.
Эти сигналы должны влиять на riskScore, но не обязательно на стабильный fingerprintId.
Критически важное требование: корректная работа за reverse proxy, CDN и load balancer.
trustedProxies: CIDR list, IP list или preset.trustedHeaders: список разрешенных proxy headers.cloudflare: preset для Cloudflare.fastly: preset для Fastly.akamai: preset для Akamai.awsAlb: preset для AWS ALB/ELB.nginxProxy: generic preset.symfonyTrustedProxiesBridge: интеграция с настройками Symfony.laravelTrustedProxyBridge: интеграция с trustedproxy Laravel.
- Начать с
REMOTE_ADDR. - Проверить, является ли
REMOTE_ADDRдоверенным прокси. - Если нет, игнорировать все forwarded headers.
- Если да, разобрать разрешенные headers в порядке приоритета.
- Валидировать каждый IP через
filter_var(..., FILTER_VALIDATE_IP). - Удалить private/reserved IP из публичной цепочки, если это настроено.
- Определить первый недоверенный upstream client IP.
- Сохранить объяснение выбора.
Итоговый hash должен строиться не из произвольного массива, а из стабильного canonical JSON:
- Сортировка signal names по алфавиту.
- Стабильное кодирование JSON без неявного изменения типов.
- Явная версия схемы.
- Явная версия алгоритма.
- Явная версия профиля нормализации.
- Исключение
null, пустых и недоступных сигналов по заданному правилу. - Отдельное поле
saltVersionилиkeyVersion, но не сама соль.
Пример canonical payload:
{
"algorithm": "gsfp-v1",
"profile": "balanced",
"signals": {
"browser.family": "Chrome",
"browser.major": "124",
"header.accept_language": "en-US,en;q=0.9",
"ip.prefix": "203.0.113.0/24"
}
}- Основной алгоритм: HMAC-SHA-256.
- Секрет обязателен для production.
- Без секрета разрешить только dev mode с явным предупреждением.
- Опционально поддержать BLAKE2b через Sodium.
- Итоговый ID кодировать как lowercase hex или base64url.
- Добавить prefix версии:
gsfp_v1_.... - Не использовать MD5, SHA-1 и несоленые хеши.
confidence должен учитывать:
- Количество доступных сигналов.
- Их веса.
- Стабильность сигналов.
- Чувствительность сигналов.
- Противоречия между сигналами.
- Наличие доверенного proxy context.
- Долю сигналов, которые были недоступны.
Пример уровней:
0-30: low confidence.31-60: medium confidence.61-80: high confidence.81-100: very high confidence.
Оценивать не как криптографическую энтропию, а как практическую редкость набора сигналов:
- Generic browser UA имеет низкую энтропию.
- Полный набор UA + Accept-Language + Client Hints + IP prefix имеет среднюю энтропию.
- Дополнительные trusted TLS/proxy/ASN сигналы повышают энтропию.
- Request-scoped значения не должны повышать стабильный entropy score.
User-Agentmajor version: medium.- Full browser version: volatile.
- Accept-Language: stable/medium.
- Accept-Encoding: medium.
- IP full: volatile/medium.
- IP prefix: medium.
- Client Hints platform: medium/stable.
- Header order: low/medium, зависит от SAPI.
- Cookies: зависит от cookie type.
Помимо точного совпадения hash, библиотека должна уметь сравнивать два FingerprintResult.
exactMatch: совпал итоговый hash.partialMatch: совпала часть сигналов.distance: числовое расстояние 0-100.changedSignals: список изменившихся сигналов.stableSignalsMatched: количество совпавших стабильных сигналов.volatileSignalsChanged: количество изменившихся нестабильных сигналов.riskReasons: объяснение подозрительных отличий.
same: высокая вероятность того же клиента.similar: вероятно тот же клиент, но часть сигналов изменилась.changed: существенное изменение окружения.suspicious: изменение затрагивает стабильные или риск-сигналы.unknown: недостаточно данных.
- Изменился IP внутри того же
/24, UA и language совпали:similar. - Изменился UA major, IP prefix совпал, language совпал:
similarилиchanged. - Изменились UA family, OS, Accept-Language и IP ASN:
suspicious. - Появился proxy chain при прежнем аккаунте: повысить
riskScore. - Пропали Client Hints, но UA похож: не считать автоматическим fraud.
$config = FingerprintConfig::create()
->withPrivacyMode(PrivacyMode::Balanced)
->withSecret($_ENV['APP_FINGERPRINT_SECRET'])
->withTrustedProxies(['10.0.0.0/8', '172.16.0.0/12'])
->withTrustedHeaders(['x-forwarded-for', 'x-forwarded-proto'])
->withIpPrefixing(ipv4: 24, ipv6: 56)
->includeClientHints(true)
->includeHeaderOrder(false)
->includeCookies(['device_consent' => 'presence'])
->excludeHeaders(['authorization', 'cookie'])
->build();secret.privacyMode.algorithmVersion.trustedProxies.ipStrategy.enabledCollectors.disabledSignals.cookieAllowlist.debug.rawValuePolicy.
strict:
- No full IP.
- IP prefix only.
- No cookie values.
- No TLS certificate data.
- No full UA version.
- No header order by default.
- No raw values in result.
balanced:
- IP prefix.
- UA derived values.
- Accept-Language normalized.
- Accept-Encoding normalized.
- Client Hints if present.
- Cookie presence only for allowlist.
- Header order off by default.
maximum:
- Full IP allowed only by explicit flag.
- Header order allowed if reliable.
- Selected cookie value hashes allowed.
- TLS signals allowed if exposed by server.
- External enrichment adapters allowed.
- Keep raw hash, not raw value, unless debug explicitly enabled.
- Normalize whitespace.
- Parse family, major, minor, patch where possible.
- Extract OS family and version.
- Detect bots and libraries.
- Avoid relying on full UA as stable identity because modern browsers freeze or reduce UA.
- Lowercase language tags except region if canonicalizer supports it.
- Normalize separators.
- Normalize q-values:
q=1.0toq=1,q=.9toq=0.9. - Preserve order because preference order matters.
- Optionally produce reduced version: top language only.
- Lowercase tokens.
- Normalize q-values.
- Preserve order by default.
- Recognize common tokens: gzip, br, deflate, zstd.
- Unknown encodings keep as token hash if configured.
- Parse media ranges.
- Normalize whitespace.
- Preserve order and q-values.
- Optionally collapse to coarse profile: html/json/image/api/unknown.
- Parse structured values safely.
- Treat missing hints as normal behavior.
- Support reduced UA world.
- Do not send
Accept-CHheaders from core library automatically; this is responsibility приложения. - Provide helper documentation for enabling Client Hints via server/framework.
- Headers are exposed as
$_SERVER['HTTP_*']. - Header names are uppercased and hyphens become underscores.
- Header order is generally lost.
REMOTE_ADDRis address of direct peer, often load balancer/proxy.- Need explicit
fastcgi_paramдля нестандартных headers, если они не передаются. - For TLS info, Nginx must pass variables through
fastcgi_param SSL_PROTOCOL $ssl_protocol;etc.
apache_request_headers()may be available.getallheaders()may be available outside Apache in newer PHP, but behavior depends on SAPI.REMOTE_ADDRmay be client or proxy depending on deployment.mod_remoteipcan rewrite client IP. Library must record whether rewritten headers exist if possible.- TLS vars require Apache SSL environment export.
- Headers are exposed through server variables.
- Header order is not reliable.
- Some names may differ or be absent depending on FastCGI settings.
- Client IP can be affected by ARR and proxy settings.
- Need support for
X-Original-For,X-Forwarded-For,X-ARR-LOG-IDas context only.
- Treat as generic reverse proxy/FastCGI unless runtime provides richer data.
- Document known header behavior.
- Encourage explicit trusted proxy configuration.
- Prefer PSR-7/request object integration.
- Do not read global state in long-running workers.
- Avoid static mutable cache tied to one request.
- Ensure collectors are stateless or reset per request.
- All secrets must be injected through config, not hardcoded.
- Use constant-time comparison for fingerprint IDs where security-relevant.
- Never include
Authorization, bearer tokens, API keys, CSRF tokens, passwords, request bodies or full query strings in fingerprint. - Provide header denylist by default:
authorization;proxy-authorization;cookie, unless explicitly parsed by allowlist;set-cookie;x-api-key;x-auth-token;x-csrf-token;csrf-token;x-xsrf-token.
- Validate all IPs strictly.
- Protect against header spoofing by trust proxy model.
- Handle malformed headers without exceptions in normal mode.
- Add max header length limits to avoid memory abuse.
- Add max header count limits.
- Avoid logging raw sensitive values.
- Provide
RedactorInterfacefor safe debug logs. - Support algorithm/key versioning for rotation.
- Raw values disabled by default.
- Debug mode must be explicit and documented as unsafe for production logs.
- Allow per-signal sensitivity policy.
- Allow disabling high-sensitivity collectors globally.
- Provide data minimization profile.
- Provide
FingerprintResult::toSafeArray(). - Provide
FingerprintResult::toDebugArray()only when allowed. - Support retention metadata:
ttl,createdAt,expiresAt. - Document lawful basis and consent requirements.
- Provide examples of privacy-friendly deployment.
- Invalid configuration throws
ConfigurationException. - Unsupported runtime feature throws only when feature is required; otherwise collector returns unavailable signal.
- Malformed input should produce ignored signal with reason, not fatal error.
- Missing secret in production throws exception.
- Missing optional extension should disable related feature with warning object.
- Public API should not emit PHP notices/warnings on malformed server arrays.
- PSR-3 logger optional.
- Log levels:
debug: collector details, without raw sensitive values;info: algorithm version/profile;warning: misconfigured trusted proxy, missing secret in dev;error: unexpected collector failure.
- Provide diagnostics object:
- unavailable collectors;
- ignored signals;
- suspicious proxy configuration;
- SAPI limitations;
- privacy mode warnings.
- No logging by default unless logger injected.
- Middleware computes fingerprint and attaches result as request attribute.
- Attribute name configurable, default
globus_fingerprint. - No response mutation by default.
- Optional response header disabled by default.
- Service definition.
- Request listener или argument resolver.
- Config package recipe optional.
- Bridge to trusted proxies.
- ServiceProvider.
- Facade optional.
- Middleware.
- Config publish command.
- Bridge to trusted proxies and request object.
FingerprintBuilder::fromGlobals().- Minimal bootstrap example.
- No framework dependency.
Ядро не должно требовать базу данных. Предусмотреть интерфейс:
interface FingerprintStorageInterface
{
public function save(string $subjectId, FingerprintResult $result): void;
public function findLatestBySubject(string $subjectId): ?FingerprintResult;
/** @return list<FingerprintResult> */
public function findBySubject(string $subjectId, int $limit = 10): array;
public function deleteBySubject(string $subjectId): void;
}Реализации:
InMemoryFingerprintStorageдля тестов.- Документированные примеры для PDO.
- Optional packages в будущем:
globus-studio/fingerprint-laravel;globus-studio/fingerprint-symfony;globus-studio/fingerprint-doctrine.
Ядро должно иметь минимум зависимостей:
psr/http-messageoptional или вsuggest, если PSR-7 адаптер вынесен.psr/logoptional.psr/clockoptional или собственный clock interface.symfony/polyfill-*только если реально нужно.
phpunit/phpunitилиpestphp/pest.phpstan/phpstan.vimeo/psalmопционально.friendsofphp/php-cs-fixerилиsquizlabs/php_codesniffer.infection/infectionдля mutation testing.rector/rectorдля upgrade safety.composer-normalize.phpbench/phpbenchдля benchmark.
declare(strict_types=1);во всех PHP-файлах.- PSR-12 или PER-CS.
- Typed properties, return types, parameter types.
- Readonly classes/value objects где применимо.
- Enum для режимов, уровней и типов сигналов.
- Запрет one-letter variable names.
- Маленькие классы с одной ответственностью.
- Composer scripts:
test;test:coverage;analyse;cs;cs:fix;infection;bench.
- PHPStan level 9 или максимальный доступный.
- Покрытие тестами не ниже 85% для core.
- Mutation score целевой: 70%+ для алгоритмов нормализации и matching.
- Header normalization.
- IP parsing.
- Trusted proxy resolution.
- Canonical JSON encoding.
- Hashing.
- Signal weighting.
- Confidence scoring.
- Matching.
- Privacy profiles.
- Redaction.
- Native globals request.
- PSR-7 request.
- Symfony request.
- Laravel request, если интеграция в ядре или отдельном пакете.
- Nginx-like server variables fixture.
- Apache-like fixture.
- IIS-like fixture.
- Cloudflare fixture.
- AWS ALB fixture.
- Malformed headers.
- PHP 8.3.
- PHP 8.4.
- PHP 8.5.
- Lowest dependencies.
- Highest dependencies.
- Windows.
- Linux.
- macOS optional.
- Authorization header excluded.
- Cookie not included unless allowlisted.
- Full IP excluded in strict/balanced profiles.
- Spoofed
X-Forwarded-Forignored when proxy untrusted. - Header length limits.
- Malformed Client Hints do not crash.
- Constant-time comparison used where needed.
Создать fixtures с ожидаемыми fingerprint IDs для стабильности алгоритма:
fixtures/nginx-chrome.json.fixtures/apache-firefox.json.fixtures/iis-edge.json.fixtures/cloudflare-safari.json.fixtures/mobile-chrome.json.fixtures/curl-client.json.fixtures/bot-client.json.
При изменении алгоритма требуется новая версия gsfp-v2, а не тихое изменение gsfp-v1.
GitHub Actions workflows:
ci.yml:- checkout;
- setup PHP 8.3, 8.4, 8.5;
- composer validate;
- composer install;
- code style check;
- static analysis;
- tests.
lowest-deps.yml:composer update --prefer-lowest --prefer-stable;- tests.
mutation.ymloptional/manual.release.yml:- validate tag;
- generate changelog;
- create GitHub release.
packagist.ymloptional, if using webhook usually not needed.
Обязательные файлы:
README.md.CHANGELOG.md.LICENSE.SECURITY.md.CONTRIBUTING.md.CODE_OF_CONDUCT.mdoptional.docs/privacy.md.docs/configuration.md.docs/signals.md.docs/trusted-proxies.md.docs/frameworks/laravel.md.docs/frameworks/symfony.md.docs/frameworks/psr-7.md.docs/server/nginx.md.docs/server/apache.md.docs/server/iis.md.docs/algorithm-versioning.md.docs/testing.md.
README должен содержать:
- Короткое описание.
- Установку.
- Быстрый старт.
- Важное предупреждение о приватности.
- Пример balanced config.
- Пример trusted proxies.
- Пример matching.
- Поддерживаемые версии PHP.
- Ссылки на подробные docs.
- Валидный
composer.json. - Семантическое версионирование.
- Git tags:
v0.1.0,v1.0.0. - README на английском желательно, можно дополнительно русский вариант.
- Keywords:
fingerprint;device-fingerprint;browser-fingerprint;php;security;fraud-detection;risk-scoring;psr-7;laravel;symfony.
- Composer extra для branch alias optional.
- GitHub repository linked to Packagist.
- Auto-update через Packagist GitHub hook.
- Любое изменение canonical payload, набора default signals или hashing меняет
algorithmVersion. - Патч-релизы не должны менять fingerprint output для той же версии алгоритма.
- Minor-релиз может добавить новый алгоритм, но старый остается доступным.
- Major-релиз может менять default algorithm.
- Результат должен явно хранить
algorithmVersion. - Provide migration guide for
gsfp-v1togsfp-v2.
Требования:
- Core fingerprint build target: менее 1 мс на обычном запросе без внешних enrichers.
- Memory overhead target: менее 1 MB на request для balanced profile.
- No network IO in core.
- Lazy optional parsers.
- Cache compiled config.
- Avoid regex backtracking risks.
- Benchmarks for:
- simple request;
- request with many headers;
- proxy chain;
- Client Hints parsing;
- matching 100 known fingerprints.
Интерфейсы:
interface SignalCollectorInterface
{
public function collect(RequestContext $request, FingerprintConfig $config): SignalSet;
}
interface NormalizerInterface
{
public function normalize(mixed $value, NormalizationContext $context): NormalizedValue;
}
interface FingerprintHasherInterface
{
public function hash(CanonicalPayload $payload, HashingConfig $config): string;
}Плагины должны иметь возможность:
- Добавлять collector.
- Добавлять normalizer.
- Добавлять signal weight policy.
- Добавлять risk rule.
- Добавлять storage adapter.
- Добавлять framework integration.
Отдельно от fingerprint identity реализовать risk scoring.
Примеры причин риска:
untrusted_forwarded_header.proxy_chain_changed.ua_ch_mismatch.missing_browser_headers.automation_user_agent.impossible_header_combination.ip_prefix_changed.asn_changed.language_changed.tls_profile_changed, если доступно.
RiskResult должен содержать:
score: 0-100.level: low, medium, high, critical.reasons.recommendedAction: allow, monitor, step_up, block, manual_review.
Важно: библиотека не должна самостоятельно блокировать пользователей. Она только возвращает результат.
rawValueпо умолчаниюnull.safeValueможет быть:- full для low sensitivity;
- truncated для medium;
- hashed для high;
- omitted для special.
toArray()должен иметь режимы:safe;storage;debug.
- Debug mode требует
allowRawValues: true. - В логах всегда использовать
safe.
browser.family: 8
browser.major: 6
browser.engine: 4
os.family: 6
os.major: 4
device.class: 4
header.accept_language: 7
header.accept_encoding: 5
header.accept: 4
client_hints.platform: 6
client_hints.mobile: 4
client_hints.brands: 5
ip.prefix: 8
proxy.chain_shape: 3
tls.protocol: 3
header.order_hash: 2
cookie.allowlisted_presence: 3
Default weights должны быть конфигурируемыми.
- Серверный fingerprint слабее гибридного fingerprint с клиентскими сигналами.
- NAT, VPN, corporate proxy и mobile networks снижают точность.
- Современные браузеры уменьшают entropy через privacy protections.
- IP-адрес часто меняется и не должен быть главным идентификатором.
- Header order в PHP чаще всего недоступен в исходном виде.
- Client Hints требуют политики браузера и могут отсутствовать.
- CDN и reverse proxy могут переписывать заголовки.
- Fingerprint collision возможен.
- Fingerprint drift неизбежен после обновлений браузера, ОС, смены сети.
- Любое решение по блокировке должно использовать несколько факторов.
- Composer package skeleton.
- Core config.
- Native request context.
- Header collector.
- Network collector.
- Basic normalizers.
- HMAC-SHA-256 hasher.
- FingerprintResult.
- Balanced profile.
- Unit tests.
- README quick start.
- Trust proxy model.
- IP prefix strategies.
- Privacy profiles.
- Redaction.
- Safe array export.
- Security tests.
- Nginx/Apache/IIS docs.
- FingerprintMatcher.
- MatchResult.
- Confidence score.
- Risk score.
- Bot/proxy anomaly rules.
- Golden tests.
- PSR-7 adapter.
- PSR-15 middleware.
- Symfony bridge.
- Laravel bridge.
- Integration docs.
- Algorithm freeze for
gsfp-v1. - Full CI matrix.
- Static analysis level max.
- Performance benchmarks.
- Security review.
- Documentation polish.
- Public API freeze.
- SemVer policy.
- Packagist publication.
- GitHub release.
- Upgrade guide.
- Production readiness checklist.
- Пакет устанавливается через Composer.
- Все public classes имеют строгие типы.
- Core не зависит от фреймворков.
- PHP 8.3, 8.4, 8.5 проходят CI.
- Windows и Linux проходят CI.
- PHPStan на максимальном уровне проходит без baseline или с минимальным documented baseline.
- Unit и integration tests проходят.
- Core coverage не ниже 85%.
- Golden tests фиксируют output
gsfp-v1. - README и docs готовы.
- Privacy warning присутствует.
- Trusted proxy docs готовы.
- Header denylist реализован.
- Raw sensitive values не попадают в safe output.
- Packagist metadata заполнена.
- Git tag
v1.0.0создан.
{
"name": "globus-studio/fingerprint",
"description": "Server-side PHP fingerprinting library for security, risk scoring, and privacy-aware client identification.",
"type": "library",
"license": "MIT",
"authors": [
{
"name": "Yevhen Leonidov",
"homepage": "https://globus.studio",
"role": "Developer"
}
],
"require": {
"php": ">=8.3 <9.0",
"ext-json": "*",
"ext-hash": "*",
"ext-filter": "*"
},
"require-dev": {
"phpunit/phpunit": "^11.0 || ^12.0",
"phpstan/phpstan": "^2.0",
"friendsofphp/php-cs-fixer": "^3.0"
},
"suggest": {
"ext-intl": "Improves Unicode and locale normalization.",
"ext-sodium": "Enables optional Sodium hashing.",
"psr/http-message": "Required for PSR-7 request integration.",
"psr/log": "Allows diagnostic logging."
},
"autoload": {
"psr-4": {
"GlobusStudio\\Fingerprint\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"GlobusStudio\\Fingerprint\\Tests\\": "tests/"
}
},
"scripts": {
"test": "phpunit",
"analyse": "phpstan analyse",
"cs": "php-cs-fixer fix --dry-run --diff",
"cs:fix": "php-cs-fixer fix"
},
"keywords": [
"fingerprint",
"device-fingerprint",
"browser-fingerprint",
"php",
"security",
"fraud-detection",
"risk-scoring",
"psr-7",
"laravel",
"symfony"
]
}- Создать Composer skeleton.
- Добавить namespace
GlobusStudio\\Fingerprint. - Реализовать
RequestContext,HeaderBag,ServerBag. - Реализовать
HeaderNormalizer. - Реализовать
IpNormalizerи CIDR utilities. - Реализовать
Signal,SignalSet,SignalCollectorInterface. - Реализовать
HeaderSignalCollector. - Реализовать
NetworkSignalCollector. - Реализовать
CanonicalJsonEncoder. - Реализовать
HmacSha256Hasher. - Реализовать
FingerprintBuilder. - Покрыть core unit tests.
- Добавить fixtures для Nginx/Apache/IIS.
- Добавить README quick start.
- Настроить CI.
Библиотека будет считаться качественной, если она:
- Честно объясняет ограничения fingerprinting.
- Не собирает лишние чувствительные данные по умолчанию.
- Дает стабильный output для одинаковых входов.
- Не ломается на разных серверах и SAPI.
- Корректно работает за reverse proxy.
- Имеет понятную систему весов и confidence.
- Позволяет сравнивать отпечатки, а не только проверять exact hash.
- Имеет сильные тесты и golden fixtures.
- Документирована для production deployment.
- Готова к Packagist и SemVer.