package infosecmodules import ( "rubric/utils" ) var AuthnModule = Module{ Key: "authn", Aliases: []string{"auth", "mfa", "jwt", "oauth"}, Title: "Аутентификация и авторизация", Description: "MFA, JWT, OAuth2, OIDC, RBAC, LDAP/AD, управление доступом", Run: showAuthn, } func showAuthn() { utils.Header("InfoSec — Аутентификация и авторизация") utils.Section("Основные понятия") utils.Code(`Authentication (AuthN) — кто ты? Проверка идентичности. Authorization (AuthZ) — что тебе можно? Проверка прав. Факторы аутентификации: Something you know — пароль, PIN, секретный вопрос Something you have — токен, телефон, смарт-карта Something you are — биометрика (отпечаток, лицо) Somewhere you are — геолокация, IP (дополнительный фактор) MFA (Multi-Factor Authentication) — два и более фактора. 2FA — два фактора (подмножество MFA). Типы MFA (от слабого к сильному): SMS OTP — уязвим к SIM-swap, SS7 атакам TOTP — RFC 6238, Google Authenticator (лучше SMS) HOTP — счётчик, менее популярен Push Auth — Duo, Microsoft Authenticator FIDO2/WebAuthn — аппаратные ключи, phishing-resistant (лучший вариант)`) utils.Section("Пароли и хранение") utils.Code(`Правила паролей (NIST SP 800-63B — актуальные рекомендации): - Минимальная длина: 8+ символов (лучше 12-14+) - НЕ требовать обязательную смену (только при компрометации) - НЕ требовать сложность (но и не запрещать) - Проверять по словарю скомпрометированных паролей - Разрешать пробелы и Unicode - Показывать пароль при вводе (опционально) - Поддерживать менеджеры паролей (не ограничивать длину) Хранение паролей: ❌ Открытый текст ❌ Обратимое шифрование ❌ MD5 / SHA-1 без соли ✓ bcrypt (cost ≥ 12), Argon2id, scrypt Проверка скомпрометированных паролей: Have I Been Pwned API — проверить hashed пароль k-Anonymity: отправить первые 5 символов хэша https://api.pwnedpasswords.com/range/{hash_prefix} Account Lockout: Блокировать после N неудачных попыток (3-5) Экспоненциальная задержка между попытками Уведомлять пользователя о неудачных попытках`) utils.Section("TOTP — Time-based One-Time Password") utils.Code(`RFC 6238. Основан на HMAC-SHA1 + временном счётчике. Как работает: 1. Общий секрет (seed) обменивается один раз (QR-код) 2. Counter = floor(UnixTime / 30) # меняется каждые 30 сек 3. OTP = HOTP(secret, counter) — 6-8 цифр 4. Сервер проверяет OTP ± 1 временной шаг Уязвимости: - Фишинг в реальном времени (attacker-in-the-middle) - Не защищает от SIM-swap (только SMS) - Потеря устройства = потеря доступа # Python реализация: import pyotp secret = pyotp.random_base32() totp = pyotp.TOTP(secret) print(totp.now()) # текущий OTP print(totp.verify("123456")) # проверить # Provisioning URI для QR-кода: uri = totp.provisioning_uri("alice@example.com", issuer_name="MyApp")`) utils.Section("FIDO2 / WebAuthn — беспарольная аутентификация") utils.Code(`FIDO2 = WebAuthn (W3C) + CTAP (Client-to-Authenticator Protocol) Phishing-resistant: ключ привязан к origin (домену). Аутентификаторы: Platform — встроенный в устройство (Touch ID, Windows Hello) Roaming — внешний ключ (YubiKey, Titan Key) Как работает: Регистрация: 1. Сервер отправляет challenge 2. Аутентификатор создаёт пару ключей для этого origin 3. Публичный ключ сохраняется на сервере 4. Приватный ключ НИКОГДА не покидает устройство Аутентификация: 1. Сервер отправляет challenge 2. Аутентификатор подписывает challenge приватным ключом 3. Сервер верифицирует подпись публичным ключом Атака фишингом НЕВОЗМОЖНА: ключ не работает на evil.com Паспорты (Passkeys): = FIDO2 ключи, синхронизируемые через облако (iCloud, Google, 1Password) Удобство ключей + синхронизация устройств`) utils.Section("JWT — JSON Web Token") utils.Code(`JWT — компактный токен для передачи claims между сторонами. Используется для stateless аутентификации (API, микросервисы). Структура: header.payload.signature # Header (base64url): {"alg": "HS256", "typ": "JWT"} # Payload (base64url): { "sub": "1234567890", # subject (user ID) "name": "Alice Smith", "iat": 1516239022, # issued at "exp": 1516242622, # expiration "jti": "uuid", # JWT ID (для revocation) "iss": "https://auth.example.com", # issuer "aud": "https://api.example.com" # audience } # Signature: HMAC-SHA256(base64(header) + "." + base64(payload), secret) Типы алгоритмов: Симметричные (один ключ): HS256, HS384, HS512 — HMAC-SHA Асимметричные (ключевая пара): RS256 — RSA + SHA256 (рекомендуется для распределённых систем) ES256 — ECDSA + SHA256 (компактнее) EdDSA — Ed25519 (современный) Уязвимости JWT: alg=none — КРИТИЧНО, проверяй алгоритм! Атака: изменить alg на "none", удалить подпись RS256→HS256 подмена Атака: использовать публичный RSA ключ как HMAC секрет Слабый секрет — поддаётся брутфорсу Отсутствие exp — токен не истекает Хранение в localStorage — доступен XSS атаке Лучшие практики: - Короткий TTL (access token: 15 мин, refresh: 7 дней) - Использовать RS256 или ES256 (не HS256 в распределённых системах) - Хранить в HttpOnly cookie (не localStorage!) - Проверять iss, aud, exp - Реализовать token revocation (Redis blacklist или jti)`) utils.Section("OAuth2 и OpenID Connect") utils.Code(`OAuth2 — фреймворк делегированной авторизации (не аутентификации!). OIDC (OpenID Connect) — слой аутентификации поверх OAuth2. OAuth2 Roles: Resource Owner — пользователь Client — приложение (запрашивает доступ) Resource Server — API с защищёнными данными Authorization Server — выдаёт токены OAuth2 Grant Types (потоки): Authorization Code — для веб-приложений (РЕКОМЕНДУЕТСЯ) 1. Redirect → Auth Server с code_challenge (PKCE) 2. Пользователь авторизуется 3. Redirect обратно с code 4. Обмен code на tokens (server-side) Client Credentials — сервис-к-сервису (без пользователя) Device Authorization — умные устройства, CLI ❌ Implicit Flow — устаревший, уязвим (токен в URL) ❌ Resource Owner Password — только для доверенных приложений PKCE (Proof Key for Code Exchange): Защита от перехвата authorization code. Обязателен для публичных клиентов (SPA, мобильные). code_verifier = random() code_challenge = base64url(sha256(code_verifier)) Токены OAuth2: Access Token — краткоживущий, доступ к API Refresh Token — долгоживущий, получение нового access token ID Token — OIDC, JWT с данными пользователя OIDC Scopes: openid — обязательный для OIDC, возвращает ID Token profile — имя, аватар, locale email — email и верификация address — адрес phone — телефон`) utils.Section("RBAC, ABAC и управление доступом") utils.Code(`DAC (Discretionary Access Control): Владелец решает кто имеет доступ (Linux chmod, ACL) MAC (Mandatory Access Control): Системная политика (SELinux, AppArmor) RBAC (Role-Based Access Control): Права назначаются ролям, роли — пользователям. Пример: admin, editor, viewer Kubernetes RBAC: Role → RoleBinding → ServiceAccount/User ABAC (Attribute-Based Access Control): Решения на основе атрибутов (пользователь, ресурс, контекст) Пример: OPA (Open Policy Agent), AWS IAM ReBAC (Relationship-Based Access Control): Права через отношения между объектами Пример: Google Zanzibar, SpiceDB, OpenFGA Принцип наименьших привилегий: Давать только необходимые права Just-in-Time (JIT) доступ — временное повышение привилегий Privileged Access Management (PAM): CyberArk, HashiCorp Vault, AWS IAM Identity Center # OPA — Open Policy Agent (пример Rego политики): package authz default allow = false allow if { input.method == "GET" input.path == ["api", "public"] } allow if { input.user.role == "admin" }`) utils.Section("LDAP и Active Directory") utils.Code(`LDAP (Lightweight Directory Access Protocol): Протокол доступа к каталогам (пользователи, группы, ресурсы). Active Directory — Microsoft LDAP + Kerberos + DNS. LDAP структура: DC=example,DC=com — домен OU=Users — организационная единица CN=Alice Smith — объект (пользователь) Полный DN: CN=Alice Smith,OU=Users,DC=example,DC=com # ldapsearch — поиск в LDAP: ldapsearch -H ldap://dc.example.com \ -D "CN=binduser,DC=example,DC=com" \ -w password \ -b "DC=example,DC=com" \ "(sAMAccountName=alice)" # Атаки на LDAP/AD: Pass-the-Hash — использование хэша NTLM без пароля Pass-the-Ticket — использование Kerberos билета Kerberoasting — получение хэшей service tickets AS-REP Roasting — атака на аккаунты без Kerberos preauth DCSync — имитация контроллера домена (миллионы хэшей) LDAP Injection — инъекция в LDAP-запросы # Защита: - Kerberos AES вместо NTLM/RC4 - Protected Users группа (не кэшировать credentials) - Отключить NTLMv1, ограничить NTLMv2 - LAPS (Local Admin Password Solution) - Tiered Administration Model`) utils.Section("Secrets Management") utils.Code(`НЕ хранить секреты в: ❌ Git / исходном коде ❌ Docker image / Dockerfile ❌ Environment variables (видны в /proc) ❌ Логах Инструменты управления секретами: HashiCorp Vault — де-факто стандарт: Динамические секреты (генерация по запросу) Lease и автообновление Аудит всех обращений AWS Secrets Manager / Parameter Store GCP Secret Manager Azure Key Vault Kubernetes Secrets (base64, не зашифровано по умолчанию!) + Sealed Secrets (Bitnami) — зашифрованные секреты в Git + External Secrets Operator — синхронизация с Vault/AWS # HashiCorp Vault — основные операции: vault server -config=vault.hcl vault operator init # инициализация (ключи разуплотнения) vault operator unseal # разуплотнение vault login vault secrets enable kv-v2 vault kv put secret/myapp db_password=s3cret api_key=abc123 vault kv get secret/myapp vault kv get -field=db_password secret/myapp # Динамические секреты PostgreSQL: vault secrets enable database vault write database/config/mydb \ plugin_name=postgresql-database-plugin \ connection_url="postgresql://{{username}}:{{password}}@db:5432/mydb" \ allowed_roles="my-role" vault write database/roles/my-role \ db_name=mydb \ creation_statements="CREATE ROLE..." \ default_ttl="1h" max_ttl="24h" # Получить временные credentials: vault read database/creds/my-role # → username: v-root-xyz123, password: A1B2C3..., lease_duration: 1h`) utils.Footer() }