Перейти до вмісту

WebAuthn

Матеріал з K2 ERP Wiki Ukraine — База знань з автоматизації та санкцій в Україні


SEO title: WebAuthn для ERP SEO description: Стаття про WebAuthn для ERP-систем: що таке WebAuthn, як працює реєстрація та вхід, RP ID, origin, challenge, credential, passkeys, security keys, FIDO2, модель даних, API, безпека, dashboard та Acceptance Criteria. SEO keywords: WebAuthn, FIDO2, passkeys, security key, K2 ERP, ERP security, MFA, 2FA, phishing-resistant MFA, PublicKeyCredential, CTAP2, Web Authentication API Alternative to:


Критично важливо: WebAuthn — це не просто ще один спосіб 2FA. Це основа сучасної phishing-resistant автентифікації, яка дозволяє K2 ERP захищати адміністраторів, фінанси, бухгалтерію, HR, керівників і критичні операції краще, ніж SMS, email-коди або звичайні OTP.

Правильне рішення для K2 ERP: реалізувати WebAuthn як технічну основу для FIDO2, passkeys і hardware security keys, щоб забезпечити безпечний вхід, step-up підтвердження критичних дій і захист від phishing.

Орієнтир стандарту: WebAuthn — це W3C Web Authentication API для доступу до public key credentials. FIDO Alliance описує WebAuthn як стандартний web API, вбудований у браузери та платформи для підтримки FIDO Authentication, а CTAP2 дозволяє використовувати зовнішні автентифікатори через USB, NFC або BLE.

1. Що таке WebAuthn

WebAuthn — це стандартний web API, який дозволяє сайту або web-додатку виконувати автентифікацію користувача за допомогою криптографічних ключів замість або на додаток до пароля.

У контексті K2 ERP WebAuthn дозволяє:

  • реєструвати passkeys;
  • реєструвати hardware security keys;
  • входити без пароля або з сильним другим фактором;
  • виконувати step-up підтвердження критичних дій;
  • захищати користувачів від phishing;
  • зберігати в ERP тільки публічний ключ, а не секрет користувача.

WebAuthn працює через об’єкт `PublicKeyCredential`. MDN описує `PublicKeyCredential` як credential для входу в сервіс через стійку до phishing і витоків пару асиметричних ключів — public/private key pair — замість пароля.

2. WebAuthn, FIDO2, CTAP2 і passkeys

Термін Що означає Роль у K2 ERP
WebAuthn Browser API для створення та використання public key credentials. Дозволяє K2 ERP реєструвати ключі та перевіряти вхід.
FIDO2 Набір стандартів для сильної автентифікації. Загальна технологічна основа WebAuthn + CTAP2.
CTAP2 Протокол взаємодії браузера / ОС із зовнішнім автентифікатором. Дозволяє використовувати USB/NFC/BLE security key.
Passkey FIDO credential, прив’язаний до акаунта користувача. Зручний вхід у K2 ERP через пристрій, біометрію або PIN.
Security key Фізичний FIDO2-ключ. Найкращий варіант для адміністраторів і фінансів.
Platform authenticator Автентифікатор, вбудований у пристрій. Windows Hello, Touch ID, Face ID, Android passkey.
Roaming authenticator Переносний автентифікатор. YubiKey, Feitian, Titan Key або інший FIDO2-ключ.

Passkey — це FIDO-облікові дані, які дозволяють входити в застосунки та сайти так само, як користувач розблоковує пристрій: біометрією, PIN або pattern. Такі credentials прив’язані до акаунта користувача на сайті чи в застосунку.

3. Чому WebAuthn важливий саме для ERP

ERP — це система, де викрадений доступ може призвести не тільки до витоку даних, а й до прямої фінансової шкоди.

У K2 ERP можуть бути:

  • фінансові документи;
  • банківські виписки;
  • платежі;
  • зарплати;
  • податкові дані;
  • договори;
  • контрагенти;
  • реквізити;
  • ціни;
  • знижки;
  • залишки;
  • виробництво;
  • управлінська звітність;
  • інтеграції з банками, ПРРО, маркетплейсами, доставкою та електронним підписом.

Ризик без WebAuthn: SMS, email-код або TOTP можуть бути введені на фальшивому сайті. WebAuthn перевіряє прив’язку credential до правильного домену, тому фішинговий сайт не зможе використати ключ для входу в справжню K2 ERP.

4. Основні поняття WebAuthn

Поняття Опис Приклад
Relying Party Сервіс, який виконує автентифікацію користувача. K2 ERP.
RP ID Домен, до якого прив’язаний credential. erp.example.com або example.com.
Origin Повний origin web-додатку. https://erp.example.com.
Challenge Випадкові дані, які сервер створює для реєстрації або входу. Base64url random bytes.
Credential ID Ідентифікатор зареєстрованого ключа. Унікальний ID credential.
Public key Публічний ключ, який зберігається на сервері. Зберігається в K2 ERP.
Private key Приватний ключ, який залишається в автентифікаторі. Не передається в K2 ERP.
Attestation Дані про створення credential і автентифікатор. Опційно використовується під час реєстрації.
Assertion Підпис challenge під час входу. Перевіряється сервером.
User verification Перевірка користувача на пристрої. PIN, Touch ID, Face ID, Windows Hello.

Критично важливо: приватний ключ ніколи не повинен потрапляти на сервер K2 ERP. У K2 ERP зберігаються тільки public key, credential_id, sign_count, metadata і статус credential.

5. Як працює реєстрація WebAuthn

5.1. Бізнес-процес

1. Користувач входить у K2 ERP.
2. Відкриває «Налаштування безпеки».
3. Натискає «Додати passkey / security key».
4. K2 ERP створює registration challenge.
5. Frontend викликає navigator.credentials.create().
6. Браузер звертається до автентифікатора.
7. Користувач підтверджує дію PIN, біометрією або дотиком до ключа.
8. Автентифікатор створює public/private key pair.
9. Frontend передає attestation response на backend.
10. Backend перевіряє challenge, origin, RP ID і зберігає credential.

5.2. Важливі перевірки під час реєстрації

Backend K2 ERP повинен перевірити:

  • challenge збігається з тим, який був створений сервером;
  • challenge не прострочений;
  • origin дозволений;
  • RP ID правильний;
  • credential ще не зареєстрований;
  • user_id відповідає активному користувачу;
  • user verification виконано, якщо це вимагається політикою;
  • алгоритм підпису підтримується;
  • public key коректно витягнуто та збережено;
  • credential_id унікальний.

6. Як працює вхід через WebAuthn

6.1. Бізнес-процес

1. Користувач відкриває K2 ERP.
2. Вводить email або обирає passkey-вхід.
3. K2 ERP створює authentication challenge.
4. Frontend викликає navigator.credentials.get().
5. Браузер звертається до passkey або security key.
6. Користувач підтверджує вхід на пристрої.
7. Автентифікатор підписує challenge приватним ключем.
8. Frontend передає assertion response на backend.
9. Backend знаходить credential_id і public key.
10. Backend перевіряє підпис, origin, RP ID, challenge і sign_count.
11. Якщо все коректно — створюється сесія K2 ERP.

6.2. Важливі перевірки під час входу

Backend K2 ERP повинен перевірити:

  • credential_id існує;
  • credential активний;
  • credential не відкликаний;
  • challenge збігається;
  • challenge не прострочений;
  • origin дозволений;
  • RP ID hash правильний;
  • підпис assertion валідний;
  • user verification відповідає політиці;
  • sign_count не зменшився, якщо автентифікатор його підтримує;
  • користувач не заблокований;
  • політика ролі дозволяє цей метод входу.

7. RP ID та Origin

RP ID і Origin — критичні для безпеки WebAuthn.

Параметр Приклад Значення
RP ID erp.example.com Домен, до якого прив’язується credential.
Origin https://erp.example.com Конкретний origin web-додатку.
Неправильний origin https://fake-erp.example.net Повинен бути відхилений.
Dev origin https://dev-erp.example.com Має бути окремо дозволений тільки для dev/test.

MDN зазначає, що public key credential може використовуватись для автентифікації тільки з тим самим relying party, з яким він був зареєстрований, і RP ID має збігатися під час `navigator.credentials.get()`.

Критично важливо: не можна дозволяти wildcard origin або приймати будь-який домен. Для production K2 ERP список дозволених origin має бути жорстко визначений.

8. Де WebAuthn має бути обов’язковим у K2 ERP

Роль / зона Чому потрібен WebAuthn Рівень
Super Admin Повний контроль над ERP. Обов’язково
Адміністратор Ролі, права, налаштування, API token, інтеграції. Обов’язково
Фінансовий директор Банки, платежі, бюджети, управлінська звітність. Обов’язково
Головний бухгалтер Податки, зарплати, фінанси, документи. Обов’язково
HR / зарплата Персональні та зарплатні дані. Рекомендовано
Керівники Управлінська звітність, фінансові показники. Рекомендовано
Віддалений доступ Вищий ризик phishing і компрометації. Рекомендовано
Масовий експорт Ризик витоку даних. Step-up WebAuthn

9. Step-up WebAuthn для критичних дій

WebAuthn можна використовувати не тільки для входу, а й для повторного підтвердження небезпечних операцій.

Операція Ризик Контроль
Зміна банківських реквізитів Підміна рахунку. Step-up WebAuthn + погодження.
Створення API token Прихований доступ до ERP. Step-up WebAuthn + audit log.
Зміна ролі користувача Розширення доступу. Step-up WebAuthn адміністратора.
Масовий експорт клієнтів Витік бази. Step-up WebAuthn + alert.
Підтвердження платежу Фінансова втрата. Step-up WebAuthn + двоетапне погодження.
Вимкнення інтеграції Зупинка бізнес-процесу. Step-up WebAuthn.

10. Архітектура WebAuthn у K2 ERP

K2 ERP Frontend
        |
        | navigator.credentials.create()
        | navigator.credentials.get()
        v
Browser WebAuthn API
        |
        v
Platform Authenticator / Security Key
        |
        v
K2 ERP Backend
        |
        | verify challenge, origin, rpId, signature
        v
Credential Storage + Audit Log
        |
        v
Session Service / Step-up Action Service

11. API K2 ERP для WebAuthn

11.1. Почати реєстрацію credential

POST /api/v1/security/webauthn/registration/options

11.2. Завершити реєстрацію credential

POST /api/v1/security/webauthn/registration/verify

11.3. Почати автентифікацію

POST /api/v1/security/webauthn/authentication/options

11.4. Завершити автентифікацію

POST /api/v1/security/webauthn/authentication/verify

11.5. Список credential користувача

GET /api/v1/security/webauthn/credentials

11.6. Відкликати credential

POST /api/v1/security/webauthn/credentials/{credential_id}/revoke

11.7. Позначити credential як втрачений

POST /api/v1/security/webauthn/credentials/{credential_id}/mark-lost

11.8. Step-up WebAuthn

POST /api/v1/security/webauthn/step-up/options
POST /api/v1/security/webauthn/step-up/verify

12. Модель даних WebAuthn

12.1. webauthn_credentials

Поле Тип Опис
id uuid ID запису.
user_id uuid Користувач.
credential_id text WebAuthn credential ID.
public_key text Публічний ключ.
sign_count integer Лічильник підписів, якщо підтримується.
rp_id varchar RP ID.
origin varchar Origin реєстрації.
authenticator_type varchar PLATFORM або ROAMING.
transport varchar USB, NFC, BLE, INTERNAL.
device_name varchar Назва пристрою або ключа.
aaguid varchar Ідентифікатор моделі автентифікатора.
backup_eligible boolean Чи може credential бути синхронізованим.
backup_state boolean Чи credential зараз у backup-синхронізації.
user_verified_required boolean Чи вимагалась user verification.
status varchar ACTIVE, LOST, DISABLED, REVOKED.
last_used_at timestamp Останнє використання.
created_at timestamp Дата створення.

12.2. webauthn_challenges

Поле Тип Опис
id uuid ID challenge.
user_id uuid Користувач.
challenge_type varchar REGISTRATION, LOGIN, STEP_UP, RECOVERY.
challenge text Випадковий challenge.
rp_id varchar RP ID.
origin varchar Дозволений origin.
status varchar PENDING, PASSED, FAILED, EXPIRED.
expires_at timestamp Строк дії.
created_at timestamp Дата створення.

12.3. webauthn_events

Поле Тип Опис
id uuid ID події.
user_id uuid Користувач.
credential_record_id uuid Credential, якщо є.
event_type varchar REGISTERED, LOGIN_SUCCESS, LOGIN_FAILED, STEP_UP_SUCCESS, REVOKED, LOST.
ip_address varchar IP.
user_agent text Браузер / пристрій.
risk_score integer Оцінка ризику.
payload jsonb Технічні дані без секретів.
created_at timestamp Дата.

13. Приклад frontend-логіки

13.1. Реєстрація passkey / security key

async function registerWebAuthnCredential() {
  const optionsResponse = await fetch("/api/v1/security/webauthn/registration/options", {
    method: "POST",
    headers: { "Content-Type": "application/json" }
  });

  const options = await optionsResponse.json();

  const credential = await navigator.credentials.create({
    publicKey: options.publicKey
  });

  const verifyResponse = await fetch("/api/v1/security/webauthn/registration/verify", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(credential)
  });

  return await verifyResponse.json();
}

13.2. Вхід через WebAuthn

async function loginWithWebAuthn(email) {
  const optionsResponse = await fetch("/api/v1/security/webauthn/authentication/options", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ email })
  });

  const options = await optionsResponse.json();

  const assertion = await navigator.credentials.get({
    publicKey: options.publicKey
  });

  const verifyResponse = await fetch("/api/v1/security/webauthn/authentication/verify", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(assertion)
  });

  return await verifyResponse.json();
}

14. Приклад Python-логіки

14.1. Перевірка, чи потрібен WebAuthn

def is_webauthn_required(user: "User", action: str | None = None, context: dict | None = None) -> bool:
    if user.role in ["SUPER_ADMIN", "ADMIN", "CFO", "CHIEF_ACCOUNTANT"]:
        return True

    if action in [
        "CHANGE_BANK_DETAILS",
        "CREATE_API_TOKEN",
        "CHANGE_USER_ROLE",
        "MASS_EXPORT",
        "APPROVE_PAYMENT",
    ]:
        return True

    if context and context.get("remote_access") is True:
        return user.security_policy.require_webauthn_for_remote_access

    return False

14.2. Створення registration options

def create_webauthn_registration_options(user: "User", db: "Session") -> dict:
    challenge = webauthn_service.generate_challenge()

    webauthn_challenge_repository.create(
        db=db,
        data={
            "user_id": user.id,
            "challenge_type": "REGISTRATION",
            "challenge": challenge,
            "rp_id": "erp.example.com",
            "origin": "https://erp.example.com",
            "status": "PENDING",
            "expires_at": utc_now_plus_minutes(5),
        },
    )

    return {
        "publicKey": {
            "rp": {
                "name": "K2 ERP",
                "id": "erp.example.com",
            },
            "user": {
                "id": str(user.id),
                "name": user.email,
                "displayName": user.full_name,
            },
            "challenge": challenge,
            "pubKeyCredParams": [
                {"type": "public-key", "alg": -7},
                {"type": "public-key", "alg": -257}
            ],
            "authenticatorSelection": {
                "userVerification": "required",
                "residentKey": "preferred"
            },
            "timeout": 300000,
            "attestation": "none"
        }
    }

14.3. Збереження credential

def save_webauthn_credential(user_id: str, verification_result: dict, db: "Session") -> "WebAuthnCredential":
    credential = webauthn_credential_repository.create(
        db=db,
        data={
            "user_id": user_id,
            "credential_id": verification_result["credential_id"],
            "public_key": verification_result["public_key"],
            "sign_count": verification_result.get("sign_count", 0),
            "rp_id": verification_result.get("rp_id"),
            "origin": verification_result.get("origin"),
            "authenticator_type": verification_result.get("authenticator_type"),
            "transport": verification_result.get("transport"),
            "aaguid": verification_result.get("aaguid"),
            "backup_eligible": verification_result.get("backup_eligible"),
            "backup_state": verification_result.get("backup_state"),
            "user_verified_required": True,
            "status": "ACTIVE",
        },
    )

    audit_logger.log(
        user_id=user_id,
        event_type="WEBAUTHN_CREDENTIAL_REGISTERED",
        payload={
            "credential_record_id": str(credential.id),
            "authenticator_type": credential.authenticator_type,
        },
    )

    db.commit()
    return credential

14.4. Перевірка входу

def verify_webauthn_login(user: "User", assertion_response: dict, db: "Session") -> bool:
    credential = webauthn_credential_repository.get_by_credential_id(
        db=db,
        credential_id=assertion_response["credential_id"],
    )

    if not credential or credential.status != "ACTIVE":
        return False

    is_valid = webauthn_service.verify_assertion(
        assertion_response=assertion_response,
        public_key=credential.public_key,
        expected_rp_id="erp.example.com",
        expected_origin="https://erp.example.com",
        require_user_verification=True,
    )

    if not is_valid:
        audit_logger.log(
            user_id=user.id,
            event_type="WEBAUTHN_LOGIN_FAILED",
            payload={"credential_record_id": str(credential.id)},
        )
        db.commit()
        return False

    credential.last_used_at = utc_now()

    audit_logger.log(
        user_id=user.id,
        event_type="WEBAUTHN_LOGIN_SUCCESS",
        payload={"credential_record_id": str(credential.id)},
    )

    db.commit()
    return True

15. Recovery та втрата credential

Користувач може втратити пристрій, security key або доступ до passkey. Тому recovery має бути контрольованим.

Потрібно передбачити:

  • мінімум два credentials для адміністраторів;
  • резервний hardware security key;
  • recovery codes;
  • заявку на відновлення;
  • перевірку особи користувача;
  • погодження другим адміністратором;
  • журнал recovery;
  • відкликання втраченого credential;
  • обов’язкову реєстрацію нового credential;
  • тимчасовий доступ із коротким TTL.

Критично важливо: recovery-процедура не повинна обходити WebAuthn без контролю. Якщо адміністратор може просто вимкнути WebAuthn для себе без погодження, це критична вразливість.

16. Dashboard WebAuthn

16.1. KPI адміністратора безпеки

Показник Значення Стан
Super Admin із WebAuthn 100% Норма
Адміністраторів із WebAuthn 100% Норма
Фінансових ролей із WebAuthn 82% Потрібна дія
Бухгалтерів із WebAuthn 76% Потрібна дія
Користувачів тільки з SMS 18 Замінити
Втрачених credentials 2 Контроль
Credentials без використання понад 90 днів 11 Перевірити
Підозрілих WebAuthn-помилок 3 Критично

16.2. Проблемні користувачі

Користувач Роль Поточний метод Ризик Дія
admin2 Адміністратор TOTP без WebAuthn Критично Видати security key
buh_olena Бухгалтер SMS Високий Перевести на WebAuthn або TOTP
cfo Фіндиректор WebAuthn security key Добре Без дії
director Керівник Passkey Добре Без дії

17. План впровадження WebAuthn у K2 ERP

Етап 1. Аудит доступів

  • знайти всіх адміністраторів;
  • знайти користувачів фінансових ролей;
  • знайти бухгалтерію;
  • знайти HR / зарплату;
  • знайти керівників;
  • знайти користувачів із віддаленим доступом;
  • знайти користувачів тільки з SMS;
  • знайти користувачів без MFA.

Етап 2. Політика WebAuthn

  • визначити ролі, для яких WebAuthn обов’язковий;
  • визначити дозволені типи credential;
  • визначити, чи дозволені synced passkeys;
  • визначити, чи потрібні hardware keys для admin;
  • визначити recovery-процедуру;
  • визначити step-up WebAuthn для критичних дій.

Етап 3. Технічна реалізація

  • WebAuthn registration;
  • WebAuthn authentication;
  • credential storage;
  • challenge storage;
  • RP ID validation;
  • origin validation;
  • sign_count validation;
  • credential revocation;
  • lost credential flow;
  • WebAuthn events;
  • dashboard.

Етап 4. Пілот

  • super admin;
  • адміністратори;
  • фінансовий директор;
  • головний бухгалтер;
  • 5–10 power users;
  • перевірка recovery;
  • перевірка step-up дій.

Етап 5. Масове впровадження

  • бухгалтерія;
  • фінанси;
  • HR;
  • керівники;
  • віддалені користувачі;
  • поступова відмова від SMS.

18. Acceptance Criteria

18.1. Реєстрація WebAuthn

Критерій Очікуваний результат
AC-1 Користувач додає passkey. Credential реєструється, public key зберігається.
AC-2 Користувач додає hardware security key. Credential реєструється як roaming authenticator.
AC-3 Challenge прострочений. Реєстрація не приймається.
AC-4 Origin неправильний. Реєстрація відхиляється.
AC-5 RP ID неправильний. Реєстрація відхиляється.

18.2. Вхід через WebAuthn

Критерій Очікуваний результат
AC-6 Користувач входить через passkey. Сесія створюється після успішної перевірки assertion.
AC-7 Користувач використовує невідомий credential. Вхід відхиляється.
AC-8 Credential відкликаний. Вхід відхиляється.
AC-9 Admin не має WebAuthn. Вхід блокується або вимагається реєстрація WebAuthn.

18.3. Step-up WebAuthn

Критерій Очікуваний результат
AC-10 Користувач змінює банківські реквізити. Система вимагає step-up WebAuthn.
AC-11 Адміністратор створює API token. Система вимагає step-up WebAuthn.
AC-12 Користувач запускає масовий експорт. Система вимагає step-up WebAuthn і логування.

18.4. Recovery

Критерій Очікуваний результат
AC-13 Користувач повідомляє про втрату ключа. Credential позначається LOST або REVOKED.
AC-14 Admin recovery. Потрібне погодження другим адміністратором.
AC-15 Recovery завершено. Подія логуються, користувач реєструє новий credential.

18.5. Dashboard

Критерій Очікуваний результат
AC-16 Адміністратор відкриває dashboard WebAuthn. Він бачить покриття WebAuthn по ролях.
AC-17 Є admin без WebAuthn. Він підсвічується червоним.
AC-18 Є користувач тільки з SMS. Він підсвічується червоним або помаранчевим.
AC-19 Є втрачений credential. Він показується в контрольному списку.

19. Висновок

WebAuthn — це технічна основа сучасного безпечного входу в ERP.

Червона зона: адміністратори, фінанси, бухгалтерія або керівники входять у ERP через пароль, SMS або email-код без WebAuthn.

Зелена зона: K2 ERP використовує WebAuthn / passkeys / security keys для критичних ролей, step-up WebAuthn для небезпечних операцій, dashboard покриття credentials, журнал подій і контроль recovery.

Головне правило: для ERP, яка керує фінансами, зарплатами, договорами, складом і управлінською звітністю, WebAuthn має стати стандартом для критичних ролей.

20. Джерела

  • W3C WebAuthn Level 3.
  • W3C WebAuthn Level 2.
  • FIDO Alliance: User Authentication Specifications Overview.
  • FIDO Alliance: Passkeys.
  • MDN WebAuthn API.
  • MDN PublicKeyCredential.
  • Внутрішні вимоги K2 ERP до доступів, MFA, WebAuthn, журналювання та критичних дій.

21. Див. також