Стройте ответ вокруг владения состоянием, лимитов, отказа и восстановления. Определение становится инженерным ответом только в конкретном production-сценарии.
Вопросы и ответы
36 подробных ответов
01В чём разница между аутентификацией и авторизацией?
junior
Короткий ответ: Аутентификация — «кто ты?» (проверка личности). Авторизация — «что тебе можно?» (проверка прав). Сначала аутентификация, потом авторизация.
Подробно:
- Authentication (AuthN) — установление личности. Пользователь доказывает, что он тот, за кого себя выдаёт: логин+пароль, токен, отпечаток, сертификат. Результат — система знает, кто это.
- Authorization (AuthZ) — проверка, что аутентифицированный субъект имеет право выполнить действие или получить доступ к ресурсу. Результат — «можно» или «нельзя» (часто
403 Forbidden).
Пример HTTP-статусов:
401 Unauthorized— на самом деле «не аутентифицирован» (неверный/отсутствующий токен).403 Forbidden— аутентифицирован, но не авторизован (прав не хватает).
Запрос → [AuthN: кто ты?] → [AuthZ: тебе можно это?] → ресурс
↓ нет ↓ нет
401 403
⚠️ Ловушка: Названия HTTP-статусов вводят в заблуждение: 401 Unauthorized относится к аутентификации, а не к авторизации. Авторизация — это 403 Forbidden.
02Как работает session-based аутентификация?
junior
Короткий ответ: После логина сервер создаёт сессию, хранит её состояние у себя и отдаёт клиенту session id в cookie. На каждом запросе браузер шлёт cookie, сервер по id находит сессию.
Подробно:
- Пользователь шлёт логин/пароль.
- Сервер проверяет, создаёт запись сессии (например,
{userId: 42, role: admin}) в хранилище и генерирует случайный непредсказуемыйsession id. - Сервер ставит cookie:
Set-Cookie: sid=abc123; HttpOnly; Secure; SameSite=Lax. - Браузер автоматически прикладывает cookie ко всем последующим запросам на тот же домен.
- Сервер по
sidдостаёт сессию и понимает, кто это.
Сессия — stateful: состояние живёт на сервере, у клиента только указатель (id).
Set-Cookie: sid=8f3a...; HttpOnly; Secure; SameSite=Strict; Max-Age=3600; Path=/
⚠️ Ловушка: session id должен быть криптографически случайным и достаточно длинным. Если его можно предсказать или перебрать — это session hijacking. Никогда не кладите в id предсказуемые данные (например, инкрементный userId).
03Где и как хранятся сессии на сервере?
middle
Короткий ответ: В серверном хранилище: в памяти, в Redis/Memcached или в БД. В распределённых системах — централизованно (Redis), иначе сессия «привязана» к одному инстансу.
Подробно:
- In-memory (память процесса) — быстро, но теряется при рестарте и не работает с несколькими инстансами без sticky sessions.
- Redis / Memcached — стандарт для продакшена: быстро, поддерживает TTL (автоистечение), общий для всех инстансов.
- БД — надёжно, но медленнее.
При горизонтальном масштабировании сессии должны быть в общем хранилище, иначе пользователь, попавший на другой инстанс через балансировщик, окажется «разлогинен». Альтернатива — sticky sessions (балансировщик всегда шлёт пользователя на тот же сервер), но это хрупко.
⚠️ Ловушка: Хранение сессий в памяти инстанса — главная причина «случайных разлогинов» после деплоя/масштабирования. Это частый аргумент в пользу JWT (stateless), но у JWT свои минусы (см. ниже).
04Что такое JWT и как он устроен?
middle
Короткий ответ: JWT (JSON Web Token) — самодостаточный токен из трёх частей header.payload.signature, закодированных в Base64URL и разделённых точками. Подпись гарантирует целостность.
Подробно:
eyJhbGciOiJIUzI1NiJ9 . eyJzdWIiOiI0MiIsInJvbGUiOiJhZG1pbiJ9 . SflKxwRJ...
header (Base64URL) payload (Base64URL) signature
- Header — алгоритм и тип:
{"alg":"HS256","typ":"JWT"}. - Payload — claims (утверждения). Стандартные:
sub(subject/userId),iss(issuer),aud(audience),exp(expiry),iat(issued at),nbf(not before). Плюс кастомные:role,email. - Signature — подпись от
base64(header) + "." + base64(payload)секретным ключом.
JWT stateless: вся информация внутри токена, серверу не нужно хранить состояние — он только проверяет подпись.
Плюсы: stateless, легко масштабировать, удобно для микросервисов и межсервисной аутентификации, не нужен round-trip к хранилищу сессий. Минусы: нельзя легко отозвать, размер больше cookie с session id, данные внутри видны всем (только подписаны, не зашифрованы).
⚠️ Ловушка: Payload не зашифрован, а только закодирован Base64URL и подписан. Любой может прочитать содержимое. Никогда не кладите в JWT пароли, токены карт, PII — это публично читаемо. Base64 ≠ шифрование.
05HS256 vs RS256 — в чём разница?
middle
Короткий ответ: HS256 — симметричный (один общий секрет для подписи и проверки, HMAC-SHA256). RS256 — асимметричный (приватный ключ подписывает, публичный проверяет, RSA-SHA256).
Подробно:
- HS256 (HMAC) — секрет один. Кто проверяет, тот же может и подписать (подделать). Подходит, когда тот же сервис и выдаёт, и проверяет токены.
- RS256 (RSA) — приватным ключом подписывает только auth-сервер, а публичным ключом любой сервис может проверить, не имея возможности подделать. Идеально для микросервисов и сторонних потребителей.
HS256: sign(secret) → verify(secret) // один ключ
RS256: sign(privKey) → verify(pubKey) // пара ключей
⚠️ Ловушка: Классическая атака «alg: none» и «alg confusion»: злоумышленник меняет header на alg:none (без подписи) или на HS256, используя публичный RSA-ключ как HMAC-секрет. Защита: на сервере жёстко фиксируйте ожидаемый алгоритм, не доверяйте полю alg из токена.
06Как сервер валидирует JWT?
middle
Короткий ответ: Пересчитывает подпись по header+payload своим ключом и сравнивает с подписью токена; проверяет exp, iss, aud, nbf. Если что-то не сходится — токен невалиден.
Подробно:
- Разбить токен на три части.
- Пересчитать подпись от
header.payloadключом и сравнить с третьей частью. - Проверить
exp(не истёк),nbf/iat(время),iss(тот, кому доверяем),aud(предназначен нам). - Только после успешной проверки доверять claims (
role,sub).
Валидация чисто криптографическая и не требует обращения к БД — в этом сила stateless.
⚠️ Ловушка: Никогда не доверяйте payload без проверки подписи. И не парсите токен «руками» без проверки exp/alg — используйте проверенную библиотеку. Сравнение подписи должно быть constant-time, чтобы исключить timing-атаки.
07Почему JWT сложно отозвать и что с этим делать?
senior
Короткий ответ: JWT stateless — сервер не хранит выданные токены, поэтому до истечения exp токен валиден всегда, даже если пользователь разлогинился или забанен. Решения: короткий TTL + refresh, blacklist, версии токенов.
Подробно: При сессиях достаточно удалить запись из хранилища — и доступ закрыт мгновенно. С JWT такой кнопки нет. Подходы:
- Короткий TTL (5–15 мин) у access-токена + refresh-токен. Тогда «окно» компрометации мало.
- Blacklist / denylist — хранить отозванные jti в Redis с TTL до их
exp. Это возвращает stateful-составляющую (компромисс). - Token versioning — хранить
tokenVersionу пользователя; при logout/смене пароля инкрементировать. В токене кладётся версия, при проверке сверяется с БД (тоже round-trip).
⚠️ Ловушка: «JWT = можно сделать logout удалением на клиенте» — миф. Удаление токена в браузере не делает его невалидным на сервере; если копия утекла, она работает до exp. Реальный logout требует серверной денилист-логики или коротких TTL.
09Зачем нужны refresh tokens и что такое token rotation?
senior
Короткий ответ: Access-токен короткоживущий (минуты) для запросов; refresh-токен долгоживущий и используется только для получения новых access-токенов. Rotation — каждый refresh выдаёт новый refresh-токен и инвалидирует старый.
Подробно:
- Access token — короткий TTL, шлётся в каждый запрос; если утечёт, быстро протухнет.
- Refresh token — длинный TTL, хранится максимально защищённо (HttpOnly cookie / secure storage), шлётся только на endpoint обновления.
- Token rotation — при каждом использовании refresh-токена сервер выдаёт новую пару и помечает старый refresh использованным. Если кто-то попытается переиспользовать старый refresh — reuse detection: значит, токен украден, сервер отзывает всю цепочку (logout всех сессий).
[access 10м] истёк → POST /refresh (refresh-токен) → новый access + новый refresh
старый refresh → инвалидирован
⚠️ Ловушка: Без rotation и reuse-detection украденный refresh-токен даёт злоумышленнику бесконечный доступ. Refresh-токены нужно хранить на сервере (stateful) для возможности отзыва — это «возврат» к состоянию, но только для refresh, не для каждого запроса.
10Sessions vs JWT — когда что выбрать?
middle
Короткий ответ: Сессии — для классических веб-приложений с одним бэкендом, когда нужен мгновенный отзыв. JWT — для stateless API, микросервисов, межсервисной аутентификации и масштабирования без общего хранилища.
Подробно:
| Критерий | Session (stateful) | JWT (stateless) |
|---|---|---|
| Хранение состояния | На сервере (Redis/БД) | В токене у клиента |
| Отзыв | Мгновенный (удалить запись) | Сложный (blacklist/TTL) |
| Масштабирование | Нужно общее хранилище | Легко, ничего не хранить |
| Round-trip к хранилищу | На каждый запрос | Не нужен (только проверка подписи) |
| Размер | Маленький (id в cookie) | Больше (весь payload) |
| Микросервисы | Неудобно | Удобно |
| Утечка | Сессию убили — конец | Действует до exp |
💡 На практике часто гибрид: JWT access-токен (короткий) + серверный refresh с возможностью отзыва.
⚠️ Ловушка: JWT выбирают «потому что stateless и модно», а потом добавляют blacklist для отзыва — и теряют главное преимущество (statelessness). Если нужен мгновенный отзыв и приложение монолитное — сессии проще и безопаснее.
11OAuth 2.0 — роли и зачем он нужен?
middle
Короткий ответ: OAuth 2.0 — протокол делегированной авторизации: позволяет приложению получить ограниченный доступ к ресурсам пользователя на другом сервисе, не зная его пароль. Это про доступ, не про логин.
Подробно — четыре роли:
- Resource Owner — пользователь, владелец данных.
- Client — приложение, которое хочет доступ (например, сторонний сервис).
- Authorization Server — выдаёт токены (например, accounts.google.com).
- Resource Server — API, где лежат данные и который проверяет access-токен (например, Google Drive API).
Пример: приложение хочет читать ваши фото в Google. Вместо ввода пароля Google в чужом приложении вы логинитесь у Google и даёте согласие на scope photos.read. Приложение получает access-токен с этим scope.
⚠️ Ловушка: OAuth 2.0 — это авторизация (доступ к ресурсам), а не аутентификация (кто вошёл). Использовать «голый» OAuth2 для логина («Login with X») неправильно — для этого есть OpenID Connect (см. ниже). Частая ошибка: считать access-токен доказательством личности.
12OAuth 2.0 — какие бывают grant types?
senior
Короткий ответ: Основной сегодня — Authorization Code + PKCE. Для сервер-к-серверу — Client Credentials. Implicit и Resource Owner Password Credentials устарели и не рекомендуются.
Подробно:
- Authorization Code + PKCE — стандарт для веба, SPA и мобильных. Клиент получает короткий
codeчерез редирект, затем меняет его на токен на бэкенде. PKCE (code_verifier/code_challenge) защищает от перехвата кода у публичных клиентов. - Client Credentials — машина-машина, без пользователя. Сервис аутентифицируется своими credentials и получает токен.
- Implicit (устарел) — токен сразу в редиректе/URL; уязвим (токен в истории браузера, логах). Заменён на Auth Code + PKCE.
- Resource Owner Password Credentials (ROPC) (устарел) — приложение собирает логин/пароль пользователя напрямую; противоречит сути OAuth, использовать нельзя.
Auth Code + PKCE:
client → /authorize?code_challenge=... → login+consent → redirect ?code=XYZ
client → /token (code=XYZ, code_verifier=...) → access_token (+refresh, +id_token)
⚠️ Ловушка: Если на собеседовании предлагают Implicit или Password grant для нового приложения — это red flag. Сегодня для всех клиентов (включая SPA) рекомендуется Authorization Code + PKCE.
13Access token vs refresh token в OAuth?
middle
Короткий ответ: Access-токен — для обращения к Resource Server, короткоживущий. Refresh-токен — для получения новых access-токенов без повторного логина, долгоживущий, идёт только на Authorization Server.
Подробно: Access-токен предъявляется в Authorization: Bearer <token> ресурс-серверу. Когда истекает, клиент использует refresh-токен на token-endpoint auth-сервера и получает новый access-токен. Refresh никогда не шлётся ресурс-серверу.
⚠️ Ловушка: Не путать scope (что разрешено токену) с identity. Access-токен может быть «непрозрачным» (opaque) — тогда ресурс-сервер валидирует его через introspection-endpoint, а не разбирает сам.
14OpenID Connect (OIDC) vs OAuth2?
senior
Короткий ответ: OIDC — слой аутентификации поверх OAuth 2.0. OAuth2 отвечает «что можно» (авторизация доступа), OIDC добавляет «кто вошёл» (аутентификация) через id_token.
Подробно:
- OAuth2 даёт access_token для доступа к API.
- OIDC дополнительно выдаёт id_token — это JWT с информацией о пользователе (claims:
sub,email,name,iss,aud,exp). Именно он подтверждает личность. - OIDC добавляет стандартизированный
/userinfoendpoint и discovery (.well-known/openid-configuration).
«Login with Google/Apple/GitHub» = OIDC, а не чистый OAuth2.
⚠️ Ловушка: access_token нельзя использовать для аутентификации пользователя — он непрозрачен для клиента и предназначен ресурс-серверу. Для «кто это» нужен id_token. Путаница access/id-token — частая ошибка реализации SSO.
15Что такое SSO и SAML?
middle
Короткий ответ: SSO (Single Sign-On) — один вход для доступа к множеству приложений. SAML — XML-протокол обмена аутентификационными данными (assertions) между Identity Provider и Service Provider, популярен в enterprise.
Подробно:
- SSO — пользователь логинится один раз у Identity Provider (IdP), затем заходит в разные приложения (SP) без повторного ввода пароля. Реализуется через SAML, OIDC, Kerberos.
- SAML 2.0 — старый, но живой в корпоративном мире (Okta, AD FS). IdP отправляет подписанный XML-assertion с личностью пользователя в SP. Тяжеловесный (XML, подписи), но широко поддержан.
- OIDC — современная альтернатива SAML на JSON/JWT, легче для мобильных и SPA.
⚠️ Ловушка: SAML-assertions подписываются XML-подписью; уязвимости XML Signature Wrapping позволяли подделывать assertion. Нужно строго валидировать подпись всего документа и доверять только корректно подписанным элементам.
16Как правильно хранить пароли?
junior
Короткий ответ: Никогда в открытом виде и не обычным хешем. Используйте специализированные медленные алгоритмы: argon2 (предпочтительно), bcrypt или scrypt — с солью, встроенной в алгоритм.
Подробно:
- Пароли хранят как хеш, не обратимый.
- Обычные хеши (MD5, SHA-1, SHA-256) слишком быстрые — GPU считает миллиарды в секунду, перебор и rainbow tables эффективны.
- Алгоритмы для паролей специально медленные и настраиваемые по cost-фактору:
- argon2id — победитель Password Hashing Competition, устойчив к GPU и memory-hard атакам. Рекомендуется сегодня.
- bcrypt — проверенный, с work factor (cost). Ограничение длины пароля ~72 байта.
- scrypt — memory-hard, тоже хорош.
hash = bcrypt(password, cost=12) // соль генерируется и хранится внутри строки хеша
⚠️ Ловушка: «Я добавил соль к SHA-256, этого хватит» — нет. Соль убивает rainbow tables, но не спасает от brute force быстрым хешем. Нужен именно медленный алгоритм. И не пишите свою криптографию — используйте библиотеки.
17Salt, pepper и почему медленный хеш — это хорошо?
middle
Короткий ответ: Salt — уникальная случайная строка на каждый пароль, хранится рядом с хешем, защищает от rainbow tables и одинаковых хешей у одинаковых паролей. Pepper — общий секрет, хранимый отдельно от БД. Медленный хеш делает перебор экономически невыгодным.
Подробно:
- Salt — добавляется к паролю до хеширования. Уникален на пользователя ⇒ два одинаковых пароля дают разные хеши, и предрасчитанные таблицы бесполезны. Соль не секрет, обычно лежит в той же строке (bcrypt/argon2 включают её автоматически).
- Pepper — дополнительный секрет, не хранящийся в БД (в env/vault/HSM). Если БД утечёт без pepper, перебор невозможен без секрета. Дополнительный слой.
- Медленный хеш — даже если БД украдена, перебор каждого пароля занимает заметное время; при cost-факторе можно подстраивать «дороговизну» под рост железа.
⚠️ Ловушка: Соль не должна быть глобально одинаковой для всех («статическая соль») — это, по сути, pepper, а не соль, и не защищает от того, что одинаковые пароли дают одинаковые хеши. Соль — на каждого пользователя своя.
18Hashing vs Encryption vs Encoding?
middle
Короткий ответ: Encoding — обратимое преобразование без секрета (Base64), не безопасность. Encryption — обратимое с ключом (шифрование). Hashing — необратимое (одностороннее). Их постоянно путают.
Подробно:
| Обратимо? | Нужен ключ/секрет? | Назначение | |
|---|---|---|---|
| Encoding (Base64, URL-encode) | Да, кто угодно | Нет | Представление данных, не защита |
| Encryption (AES, RSA) | Да, с ключом | Да | Конфиденциальность |
| Hashing (SHA-256, bcrypt) | Нет | Нет (бывает salt/pepper) | Целостность, проверка паролей |
Пароли — хешируют (необратимо). Данные, которые нужно прочитать обратно (номер карты для платежа) — шифруют. Base64 — это просто кодировка, она никого не «защищает».
⚠️ Ловушка: «Я закодировал пароль в Base64» — это не защита, любой декодирует мгновенно. JWT-payload тоже только Base64URL — читается всеми. Encoding ≠ encryption ≠ hashing.
19Симметричное vs асимметричное шифрование?
middle
Короткий ответ: Симметричное — один ключ для шифрования и расшифровки (AES), быстрое. Асимметричное — пара ключей: публичный шифрует/проверяет, приватный расшифровывает/подписывает (RSA, ECC), медленнее, решает проблему обмена ключами.
Подробно:
- Симметричное (AES) — быстро, для больших объёмов данных. Проблема: как безопасно передать общий ключ обеим сторонам.
- Асимметричное (RSA, ECC) — публичный ключ можно раздавать всем; зашифрованное им расшифровывается только приватным. Используется для обмена ключами и цифровых подписей.
- На практике гибрид: TLS использует асимметрику для согласования общего сеансового ключа, затем симметрику (AES) для самих данных — лучшее из двух миров.
⚠️ Ловушка: Асимметричное шифрование не используют для больших данных напрямую — оно медленное и ограничено размером ключа. Им шифруют только сам симметричный ключ.
20Зачем нужен HTTPS/TLS?
junior
Короткий ответ: TLS обеспечивает конфиденциальность (шифрование трафика), целостность (нельзя незаметно изменить) и аутентичность сервера (сертификат). Защищает от перехвата и MITM-атак.
Подробно: Без HTTPS трафик идёт открытым текстом — провайдер,公 Wi-Fi, любой на пути может читать пароли, cookie, данные и подменять контент. TLS:
- Шифрует — нельзя прочитать перехваченное.
- Целостность — нельзя подменить пакеты незаметно.
- Аутентичность — сертификат, подписанный CA, подтверждает, что вы общаетесь с настоящим сервером, а не с прокладкой.
MITM (Man-in-the-Middle) — атакующий встаёт между клиентом и сервером, читает/меняет трафик. TLS+валидный сертификат не даёт это сделать незаметно (клиент увидит ошибку сертификата).
⚠️ Ловушка: HTTPS защищает данные в пути, но не от XSS, SQLi, утечки БД или плохой авторизации. «У нас HTTPS, значит безопасно» — заблуждение. Также флаг cookie Secure обязателен, иначе cookie уйдёт и по HTTP.
21Что такое OWASP Top 10?
middle
Короткий ответ: Список 10 наиболее критичных рисков веб-безопасности от OWASP, обновляемый периодически. Это базовый чек-лист, что проверять.
Подробно (OWASP Top 10, версия 2021, ключевые):
- Broken Access Control — самый частый: IDOR, обход проверок прав, повышение привилегий.
- Cryptographic Failures — слабое/отсутствующее шифрование, пароли в открытом виде, данные по HTTP.
- Injection — SQLi, command injection, LDAP injection (XSS тоже относят сюда).
- Insecure Design — изъяны на уровне архитектуры, отсутствие threat modeling.
- Security Misconfiguration — дефолтные пароли, открытые админки, лишние заголовки/фичи, неверный CORS.
- Vulnerable and Outdated Components — устаревшие зависимости с известными CVE.
- Identification and Authentication Failures — слабые пароли, отсутствие MFA, плохие сессии.
- Software and Data Integrity Failures — небезопасные обновления, десериализация, CI/CD-цепочка.
- Security Logging and Monitoring Failures — нет логов/алертов на атаки.
- Server-Side Request Forgery (SSRF) — сервер заставляют ходить на внутренние ресурсы.
⚠️ Ловушка: Broken Access Control — №1, но именно его чаще всего недооценивают, полагаясь на «фронт не покажет кнопку». Авторизацию проверяет сервер на каждом запросе.
22SQL injection — как работает и как защититься?
middle
Короткий ответ: Атака, где ввод пользователя попадает в SQL-запрос как код, а не как данные. Защита — параметризованные запросы (prepared statements), ORM, валидация ввода.
Подробно: Уязвимый код конкатенирует ввод:
# УЯЗВИМО
query = "SELECT * FROM users WHERE name = '" + name + "'"
# ввод: name = "' OR '1'='1" → вернёт всех пользователей
# ввод: name = "'; DROP TABLE users;--" → удалит таблицу
Защита — параметризованные запросы: значения передаются отдельно от текста запроса, СУБД трактует их строго как данные:
# БЕЗОПАСНО
cursor.execute("SELECT * FROM users WHERE name = %s", (name,))
- ORM (SQLAlchemy, Hibernate, Prisma) по умолчанию параметризует.
- Принцип наименьших привилегий для БД-пользователя приложения.
- Валидация/allowlist для динамических частей (имена колонок нельзя параметризовать — только allowlist).
⚠️ Ловушка: ORM не панацея — raw()-запросы, динамические ORDER BY/имена таблиц и LIKE с конкатенацией всё ещё уязвимы. Параметризовать можно только значения, не идентификаторы — для них нужен строгий allowlist.
23XSS — виды и защита?
middle
Короткий ответ: Cross-Site Scripting — внедрение чужого JS в страницу, исполняемого в браузере жертвы. Виды: stored, reflected, DOM-based. Защита — экранирование вывода, CSP, HttpOnly cookie.
Подробно:
- Stored XSS — вредоносный скрипт сохраняется на сервере (комментарий, профиль) и отдаётся всем посетителям. Самый опасный.
- Reflected XSS — скрипт в параметре запроса отражается в ответе (например, страница поиска), срабатывает по ссылке-приманке.
- DOM-based XSS — уязвимость в клиентском JS, который небезопасно вставляет данные в DOM (
innerHTML,document.write), сервер не участвует.
Что может XSS: украсть cookie/токены, делать запросы от имени жертвы, кейлоггер, дефейс.
Защита:
- Экранирование вывода по контексту (HTML, атрибут, JS, URL). Современные фреймворки (React, Angular) экранируют по умолчанию.
- CSP (Content-Security-Policy) — ограничивает источники скриптов, блокирует inline-скрипты.
HttpOnlycookie — JS не прочитает токен (снижает кражу).- Избегать
innerHTML/dangerouslySetInnerHTML/evalс пользовательскими данными; санитизировать HTML (DOMPurify).
⚠️ Ловушка: Экранировать нужно по контексту вывода, а не «на входе». Одна и та же строка безопасна в тексте HTML, но опасна внутри <script> или атрибута href="javascript:...". Слепая фильтрация на входе ломает данные и не закрывает все контексты.
24CSRF — как работает атака и защита?
middle
Короткий ответ: Cross-Site Request Forgery — заставляет браузер жертвы выполнить нежелательный запрос на сайт, где она авторизована, используя автоматически прикладываемые cookie. Защита: CSRF-токен, SameSite cookie, проверка Origin/Referer.
Подробно: Жертва залогинена в банке (cookie сессии). Заходит на сайт атакующего, где есть скрытая форма/картинка:
<img src="https://bank.com/transfer?to=attacker&amount=1000">
Браузер автоматически приложит cookie банка к этому запросу — перевод уйдёт от имени жертвы. Атакующий не видит ответ, но действие выполнено.
Защита:
- CSRF-токен (synchronizer token) — сервер выдаёт непредсказуемый токен в форме/заголовке; чужой сайт его не знает.
SameSite=Lax/Strictна cookie — браузер не шлёт cookie при кросс-сайтовых запросах. Современная основная защита.- Проверка
Origin/Refererзаголовков на сервере. - Использовать безопасные методы: state-changing операции только через POST/PUT/DELETE, не GET.
⚠️ Ловушка: CSRF актуален только когда аутентификация автоматическая (cookie). Если токен в Authorization-заголовке (его браузер сам не приложит), классический CSRF не работает — но появляется XSS-риск хранения. SameSite=Lax не защищает полностью при некоторых GET-навигациях.
25CORS и same-origin policy?
senior
Короткий ответ: Same-Origin Policy запрещает JS читать ответы с другого origin. CORS — механизм, которым сервер разрешает кросс-доменные запросы через заголовки Access-Control-*. CORS ослабляет SOP, а не защищает сервер.
Подробно:
- Origin = схема + хост + порт.
https://a.comиhttps://b.com(или другой порт/схема) — разные origin. - Same-Origin Policy (SOP) — браузерное правило: скрипт с одного origin не может читать ответ от другого origin.
- CORS — сервер с помощью заголовков говорит браузеру, кому можно:
Access-Control-Allow-Origin: https://app.comAccess-Control-Allow-Methods: GET, POSTAccess-Control-Allow-Headers: Authorization, Content-TypeAccess-Control-Allow-Credentials: true(разрешить cookie)
- Preflight — для «непростых» запросов (методы кроме GET/POST/HEAD, кастомные заголовки) браузер сначала шлёт
OPTIONS, чтобы спросить разрешение, и только потом основной запрос.
Browser → OPTIONS /api (preflight) → Access-Control-Allow-Origin: https://app.com
Browser → POST /api (если разрешено)
⚠️ Ловушка: CORS — это НЕ защита сервера. Он управляет тем, что браузер разрешает читать JS-у. Запрос всё равно доходит до сервера (curl/Postman игнорируют CORS). Опасная мисконфигурация: Access-Control-Allow-Origin: * вместе с Allow-Credentials: true (спецификация это запрещает) или рефлексия Origin без проверки allowlist — открывает доступ любому сайту к данным пользователя. CORS не заменяет аутентификацию/авторизацию.
26Авторизация: RBAC vs ABAC, scopes, least privilege?
middle
Короткий ответ: RBAC — права через роли (admin, editor). ABAC — права через атрибуты (отдел, время, владелец). Scopes — гранулярные разрешения токена. Least privilege — давать минимально необходимое.
Подробно:
- RBAC (Role-Based) — пользователю назначают роли, ролям — права. Просто, но грубо при сложных правилах.
- ABAC (Attribute-Based) — решение по атрибутам субъекта, ресурса и контекста: «менеджер может видеть документ, если он автор ИЛИ из того же отдела И рабочее время». Гибко, сложнее в поддержке.
- Scopes — в OAuth/токенах: что разрешено токену (
read:orders,write:profile). - Principle of Least Privilege — каждый компонент/пользователь получает только тот доступ, что строго нужен. Меньше прав — меньше ущерб при компрометации.
⚠️ Ловушка: Авторизацию надо проверять на сервере на каждом запросе и на уровне объекта (этот пользователь имеет право на ЭТУ запись?), а не только «у роли есть доступ к эндпоинту». Иначе — IDOR. Скрытие кнопки на фронте — не авторизация.
27Rate limiting и защита от brute force?
middle
Короткий ответ: Ограничение числа запросов за интервал (по IP/пользователю/ключу). Защищает от перебора паролей, DoS, скрейпинга. Дополняется account lockout, CAPTCHA, экспоненциальной задержкой.
Подробно:
- Rate limiting — алгоритмы token bucket, sliding window. Ответ
429 Too Many Requestsпри превышении. - Brute force защита для логина:
- Прогрессивная задержка (экспоненциальный backoff) после неудач.
- Account lockout — временная блокировка после N неудач.
- CAPTCHA после нескольких ошибок.
- Мониторинг credential stuffing (попытки известных утёкших паролей).
- Лимиты лучше вешать и на уровне IP, и на уровне аккаунта (чтобы distributed-атака с многих IP не обошла per-IP лимит).
⚠️ Ловушка: Жёсткий account lockout сам становится вектором DoS: атакующий нарочно блокирует чужие аккаунты, перебирая пароли. Часто лучше прогрессивная задержка + MFA + мониторинг, чем глухая блокировка. И не раскрывайте, существует ли логин («неверный логин или пароль» — единое сообщение).
28Secrets management — как хранить секреты?
middle
Короткий ответ: Никогда не хранить секреты (ключи, пароли БД, токены) в коде/репозитории. Использовать переменные окружения, а лучше — секрет-менеджеры (Vault, AWS Secrets Manager, KMS) с ротацией и аудитом.
Подробно:
- Не в коде/Git — секрет в репозитории = утёк навсегда (история, форки). Если попал — ротировать немедленно, не просто удалить коммит.
- Env vars / .env — базовый уровень;
.envв.gitignore. Лучше чем хардкод, но не идеал (видны в окружении процесса, дампах). - Secret managers / Vault — централизованное хранение, шифрование at-rest, контроль доступа, аудит, ротация, динамические короткоживущие credentials.
- KMS/HSM — для ключей шифрования.
- Сканеры секретов в CI (git-secrets, trufflehog, gitleaks) — ловить утечки до коммита.
⚠️ Ловушка: Удалить секрет из последнего коммита недостаточно — он остаётся в истории Git и у всех, кто склонировал. Единственно правильно — ротировать (отозвать) скомпрометированный секрет.
29Заголовки безопасности (CSP, HSTS, X-Frame-Options)?
middle
Короткий ответ: HTTP-заголовки, которыми сервер инструктирует браузер усилить защиту: CSP (источники ресурсов), HSTS (только HTTPS), X-Frame-Options (анти-clickjacking), X-Content-Type-Options (анти-MIME-sniffing).
Подробно:
Content-Security-Policy— белый список источников скриптов/стилей/картинок; главная защита от XSS и инъекций. Пример:default-src 'self'; script-src 'self'.Strict-Transport-Security(HSTS) — браузер всегда использует HTTPS для домена, даже если ввели http.max-age=31536000; includeSubDomains. Защита от SSL-stripping.X-Frame-Options: DENY/SAMEORIGIN— запрещает встраивать страницу в<iframe>⇒ защита от clickjacking. (Современный эквивалент —frame-ancestorsв CSP.)X-Content-Type-Options: nosniff— браузер не «угадывает» MIME-тип, использует заявленный ⇒ защита от исполнения замаскированных файлов.- Дополнительно:
Referrer-Policy,Permissions-Policy, отсутствиеServer/X-Powered-By(информационная гигиена).
⚠️ Ловушка: CSP легко сделать бесполезным: script-src 'unsafe-inline' 'unsafe-eval' или * сводят защиту на нет. Внедрять CSP надо постепенно (report-only режим), иначе сломаете легитимные скрипты.
30IDOR — Insecure Direct Object Reference?
middle
Короткий ответ: Уязвимость, когда приложение даёт доступ к объекту по его идентификатору без проверки, что у пользователя есть право на ЭТОТ объект. Подвид Broken Access Control.
Подробно: Эндпоинт GET /api/invoices/1043 возвращает счёт по id. Если сервер не проверяет, что счёт принадлежит текущему пользователю, атакующий просто меняет id на 1044, 1045 и читает чужие данные.
GET /api/orders/1001 (мой) → 200 OK
GET /api/orders/1002 (чужой) → должно быть 403, но возвращает 200 = IDOR
Защита:
- Проверять владение/права на уровне объекта на каждом запросе (
WHERE id=? AND owner_id=currentUser). - Не полагаться на «непредсказуемость» id; UUID помогает от угадывания, но не заменяет проверку прав.
⚠️ Ловушка: «У нас id — длинный UUID, угадать нельзя» — это security through obscurity. UUID не заменяет проверку авторизации: ссылка может утечь, и доступ всё равно должен проверяться.
31Mass assignment?
senior
Короткий ответ: Уязвимость, когда приложение слепо маппит все поля из тела запроса в объект модели, позволяя пользователю задать поля, которые он не должен (isAdmin, role, balance).
Подробно: Форма обновления профиля шлёт {name, email}. Но клиент добавляет {"name":"X","email":"y","isAdmin":true}, и если код делает user.update(request.body) без фильтрации — пользователь становится админом.
// УЯЗВИМО
user.update(req.body); // принимает любые поля
// БЕЗОПАСНО — allowlist полей (DTO)
const { name, email } = req.body;
user.update({ name, email });
Защита: allowlist разрешённых полей (strong parameters в Rails, DTO/binding-модели, @JsonIgnore), отдельные input-модели от доменных.
⚠️ Ловушка: Использовать одну и ту же ORM-модель и для приёма входных данных, и как доменную сущность — прямой путь к mass assignment. Разделяйте входные DTO и сущности.
322FA, MFA, TOTP?
middle
Короткий ответ: MFA — несколько факторов аутентификации (что-то знаешь / имеешь / есть ты). 2FA — частный случай (два фактора). TOTP — одноразовый код по времени из приложения-аутентификатора.
Подробно:
- Факторы: знание (пароль), владение (телефон, ключ), биометрия (отпечаток).
- 2FA = пароль + второй фактор. Резко снижает риск компрометации при утечке пароля.
- TOTP (Time-based One-Time Password) — приложение (Google Authenticator, Authy) и сервер делят общий секрет; код вычисляется из секрета + текущего времени (окно ~30 сек). Не требует сети.
- Методы 2FA по надёжности: аппаратные ключи (WebAuthn/FIDO2/U2F) > TOTP-приложение > SMS (уязвим к SIM-swap, перехвату).
⚠️ Ловушка: SMS как второй фактор — слабый (SIM-swap, перехват SS7). Предпочтительнее TOTP или аппаратные ключи. Также важна защита процесса восстановления/recovery codes — иначе MFA обходят через «забыли доступ».
33Почему нельзя хранить пароли в открытом виде и зачем медленный хеш?
concept
Короткий ответ: При утечке БД открытые пароли мгновенно компрометируют всех (и другие сайты — люди переиспользуют пароли). Хеш необратим. Медленный хеш делает массовый перебор экономически нецелесообразным.
Подробно: Даже сотрудники не должны видеть пароли. Хранят необратимый хеш — при логине хешируют введённое и сравнивают. Но быстрый хеш (SHA-256) перебирается миллиардами в секунду на GPU. Медленный (argon2/bcrypt) с настраиваемым cost замедляет каждую попытку в тысячи раз ⇒ перебор украденной базы становится непрактичным. Соль убирает rainbow tables и одинаковость хешей.
⚠️ Ловушка: «Зашифрую пароли AES» — плохо: шифрование обратимо, и при утечке ключа все пароли вскрываются. Пароли именно хешируют, а не шифруют.
35Чем XSS опаснее CSRF?
concept
Короткий ответ: XSS исполняет произвольный код атакующего в браузере жертвы — он может всё, что может пользователь, читать токены, обходить CSRF-токены, кейлоггить. CSRF лишь заставляет выполнить конкретное предугаданное действие вслепую.
Подробно: При CSRF атакующий не видит ответ и ограничен заранее известными запросами; защищается SameSite/CSRF-токеном. При XSS код выполняется в контексте сайта: читает DOM, ответы, локальные токены, считывает и подставляет CSRF-токен из страницы, делает любые аутентифицированные запросы. То есть XSS обходит CSRF-защиту. Поэтому XSS — фундаментально опаснее.
⚠️ Ловушка: Защита от CSRF (CSRF-токены) не помогает против XSS — скрипт на странице сам прочитает этот токен. Сначала закрывают XSS.
36Что значит «не доверяй клиенту»?
concept
Короткий ответ: Любые данные и проверки на клиенте (браузер, мобильное приложение) могут быть подделаны. Все проверки безопасности — валидация, авторизация, лимиты — должны дублироваться и быть авторитетными на сервере.
Подробно: Клиент полностью под контролем пользователя: можно изменить JS, отправить запрос через curl/Postman, подменить заголовки, цены, id, скрытые поля, обойти валидацию формы. Поэтому:
- Валидация на фронте — только UX, серверная — обязательна.
- Авторизация — на сервере на каждом запросе и каждом объекте (не «скрыли кнопку»).
- Цены, скидки, права, количество — пересчитывать/проверять на сервере, не верить значениям из запроса (см. mass assignment).
⚠️ Ловушка: Скрытое поле, disabled-кнопка, проверка только на фронте, «секретный» эндпоинт без авторизации — всё это обходится тривиально. Сервер — единственная граница доверия.
Источники
Источники и редакционная политика
Материалы RecallDeck сопоставлены с официальной документацией и открытыми публикациями компаний, когда первичный источник доступен. Мы не связаны с упомянутыми работодателями, не публикуем конфиденциальные задания и не продаём места в подборках. Формат найма может меняться — уточняйте его у рекрутера.
От чтения к воспроизведению
Отрепетируйте полный цикл интервью.
RecallDeck возвращает сложные темы по расписанию и помогает удерживать в памяти язык, SQL, архитектуру и поведенческие истории.