Все знают о стандартной аутентификации пользователя в приложении. Это олдскульная процедура регистрации — пользователь вводит адрес почты, пароль и т. д., — а затем при входе мы сравниваем почту и/или пароль с сохранёнными данными. Если совпадает, даём доступ. Но времена изменились, и сегодня появилось много других методов аутентификации. Если хотите оставаться востребованным программистом/разработчиком в этом меняющемся, словно калейдоскоп, мире разработки ПО, то вы должны знать обо всех этих новых методах.


Нельзя отрицать, что в любых приложениях и ОС «аутентификация» — крайне важный элемент обеспечения сохранности пользовательских данных и регулирования доступа к информации. Чтобы понять, какой метод аутентификации для вас лучше, нужно разбираться в достоинствах и недостатках всех методов, а также неплохо представлять, как же они работают.


Здесь я постараюсь рассказать о большинстве распространённых сегодня методов аутентификации. Это не подробное техническое руководство, а лишь способ познакомить вас с ними. Хотя методы описаны с учётом применения в вебе, эти идеи можно реализовать и в других условиях.


Будем считать, вы уже знаете о том, что большая часть веба/интернета построена на протоколе HTTP. Также вам нужно знать, как работают веб-приложения, что означает аутентификация пользователя в приложении и что такое клиент-серверная архитектура.


Готовы? Поехали.


Аутентификация на основе сессий


Протокол HTTP не отслеживает состояния, и, если мы аутентифицируем пользователя с помощью имени и пароля, наше приложение не будет знать, тот ли это человек, что и в предыдущем запросе. Нам придётся аутентифицировать снова. При каждом запросе HTTP не знает ничего о том, что происходило до этого, он лишь передаёт запрос. Так что, если вам нужны личные данные, придётся снова логиниться, чтобы приложение знало, что это точно вы. Может сильно раздражать.


Чтобы избавиться от этого неудобства, придумали аутентификацию на основе сессий/кук, с помощью которых реализовали отслеживание состояний (stateful). Это означает, что аутентификационная запись или сессия должны храниться и на сервере, и на клиенте. Сервер должен отслеживать активные сессии в базе данных или памяти, а на фронтенде создаётся кука, в которой хранится идентификатор сессии. Это аутентификация на основе куки, самая распространённый и широко известный метод, используемый уже давно.


Процедура аутентификации на основе сессий:


  1. Пользователь вводит в браузере своё имя и пароль, после чего клиентское приложение отправляет на сервер запрос.
  2. Сервер проверяет пользователя, аутентифицирует его, шлёт приложению уникальный пользовательский токен (сохранив его в памяти или базе данных).
  3. Клиентское приложение сохраняет токены в куках и отправляет их при каждом последующем запросе.
  4. Сервер получает каждый запрос, требующий аутентификации, с помощью токена аутентифицирует пользователя и возвращает запрошенные данные клиентскому приложению.
  5. Когда пользователь выходит, клиентское приложение удаляет его токен, поэтому все последующие запросы от этого клиента становятся неаутентифицированными.


У этого метода несколько недостатков.


  • При каждой аутентификации пользователя сервер должен создавать у себя запись. Обычно она хранится в памяти, и при большом количестве пользователей есть вероятность слишком высокой нагрузки на сервер.
  • Поскольку сессии хранятся в памяти, масштабировать не так просто. Если вы многократно реплицируете сервер, то на все новые серверы придётся реплицировать и все пользовательские сессии. Это усложняет масштабирование. (Я считал, этого можно избежать, если иметь выделенный сервер для управления сессиями, но это сложно реализовать, да и не всегда возможно.)

Аутентификация на основе токенов


Аутентификация на основе токенов в последние годы стала очень популярна из-за распространения одностраничных приложений, веб-API и интернета вещей. Чаще всего в качестве токенов используются Json Web Tokens (JWT). Хотя реализации бывают разные, но токены JWT превратились в стандарт де-факто.


При аутентификации на основе токенов состояния не отслеживаются. Мы не будем хранить информацию о пользователе на сервере или в сессии и даже не будем хранить JWT, использованные для клиентов.


Процедура аутентификации на основе токенов:


  1. Пользователь вводит имя и пароль.
  2. Сервер проверяет их и возвращает токен (JWT), который может содержать метаданные вроде user_id, разрешений и т. д.
  3. Токен хранится на клиентской стороне, чаще всего в локальном хранилище, но может лежать и в хранилище сессий или кук.
  4. Последующие запросы к серверу обычно содержат этот токен в качестве дополнительного заголовка авторизации в виде Bearer {JWT}. Ещё токен может пересылаться в теле POST-запроса и даже как параметр запроса.
  5. Сервер расшифровывает JWT, если токен верный, сервер обрабатывает запрос.
  6. Когда пользователь выходит из системы, токен на клиентской стороне уничтожается, с сервером взаимодействовать не нужно.


Более подробное описание.


У метода есть ряд преимуществ:


  • Главное преимущество: поскольку метод никак не оперирует состояниями, серверу не нужно хранить записи с пользовательскими токенами или сессиями. Каждый токен самодостаточен, содержит все необходимые для проверки данные, а также передаёт затребованную пользовательскую информацию. Поэтому токены не усложняют масштабирование.
  • В куках вы просто храните ID пользовательских сессий, а JWT позволяет хранить метаданные любого типа, если это корректный JSON.
  • При использовании кук бэкенд должен выполнять поиск по традиционной SQL-базе или NoSQL-альтернативе, и обмен данными наверняка длится дольше, чем расшифровка токена. Кроме того, раз вы можете хранить внутри JWT дополнительные данные вроде пользовательских разрешений, то можете сэкономить и дополнительные обращения поисковые запросы на получение и обработку данных.
    Допустим, у вас есть API-ресурс /api/orders, который возвращает последние созданные приложением заказы, но просматривать их могут только пользователи категории админов. Если вы используете куки, то, сделав запрос, вы генерируете одно обращение к базе данных для проверки сессии, ещё одно обращение — для получения пользовательских данных и проверки, относится ли пользователь к админам, и третье обращение — для получения данных.
    А если вы применяете JWT, то можете хранить пользовательскую категорию уже в токене. Когда сервер запросит его и расшифрует, вы можете сделать одно обращение к базе данных, чтобы получить нужные заказы.
  • У использования кук на мобильных платформах есть много ограничений и особенностей. А токены сильно проще реализовать на iOS и Android. К тому же токены проще реализовать для приложений и сервисов интернета вещей, в которых не предусмотрено хранение кук.

Благодаря всему этому аутентификация на основе токенов сегодня набирает популярность.


Беспарольная аутентификация


Первой реакцией на термин «беспарольная аутентификация» может быть «Как аутентифицировать кого-то без пароля? Разве такое возможно?»


В наши головы внедрено убеждение, что пароли — абсолютный источник защиты наших аккаунтов. Но если изучить вопрос глубже, то выяснится, что беспарольная аутентификация может быть не просто безопасной, но и безопаснее традиционного входа по имени и паролю. Возможно, вы даже слышали мнение, что пароли устарели.


Беспарольная аутентификация — это способ конфигурирования процедуры входа и аутентификации пользователей без ввода паролей. Идея такая:


Вместо ввода почты/имени и пароля пользователи вводят только свою почту. Ваше приложение отправляет на этот адрес одноразовую ссылку, пользователь по ней кликает и автоматически входит на ваш сайт / в приложение. При беспарольной аутентификации приложение считает, что в ваш ящик пришло письмо со ссылкой, если вы написали свой, а не чужой адрес.


Есть похожий метод, при котором вместо одноразовой ссылки по SMS отправляется код или одноразовый пароль. Но тогда придётся объединить ваше приложение с SMS-сервисом вроде twilio (и сервис не бесплатен). Код или одноразовый пароль тоже можно отправлять по почте.


И ещё один, менее (пока) популярный (и доступный только на устройствах Apple) метод беспарольной аутентификации: использовать Touch ID для аутентификации по отпечаткам пальцев. Подробнее о технологии.


Если вы пользуетесь Slack, то уже могли столкнуться с беспарольной аутентификацией.



Medium предоставляет доступ к своему сайту только по почте. Я недавно обнаружил, что Auth0, или Facebook AccountKit, — это отличный вариант для реализации беспарольной системы для вашего приложения.


Что может пойти не так?


Если кто-то получит доступ к пользовательским почтам, он получит и доступ к приложениям и сайтам. Но это не ваша головная боль — беспокоиться о безопасности почтовых аккаунтов пользователей. Кроме того, если кто-то получит доступ к чужой почте, то сможет перехватить аккаунты в приложениях с беспарольной аутентификацией, воспользовавшись функцией восстановления пароля. Но мы ничего не можем поделать с почтой наших пользователей. Пойдём дальше.


В чём преимущества?


Как часто вы пользуетесь ссылкой «забыли пароль» для сброса чёртового пароля, который так и не смогли вспомнить после нескольких неудачных попыток входа на сайт / в приложение? Все мы бываем в такой ситуации. Все пароли не упомнишь, особенно если вы заботитесь о безопасности и для каждого сайта делаете отдельный пароль (соблюдая все эти «должен состоять не менее чем из восьми символов, содержать хотя бы одну цифру, строчную букву и специальный символ»). От всего этого вас избавит беспарольная аутентификация. Знаю, вы думаете сейчас: «Я использую менеджер паролей, идиот». Уважаю. Но не забывайте, что подавляющее большинство пользователей не такие техногики, как вы. Это нужно учитывать.


Беспарольная аутентификация хороша не только для пользователей, но и для вас как разработчика. Вам не нужно реализовывать механизм восстановления паролей. Все в выигрыше.


Если вы думаете, что какие-то пользователи предпочтут старомодные логин/пароль, то предоставьте им оба варианта, чтобы они могли выбирать.



Сегодня беспарольная аутентификация быстро набирает популярность.


Единая точка входа (Single Sign On, SSO)


Обращали внимание, что, когда логинишься в браузере в каком-нибудь Google-сервисе, например Gmail, а потом идёшь на Youtube или иной Google-сервис, там не приходится логиниться? Ты автомагически получаешь доступ ко всем сервисам компании. Впечатляет, верно? Ведь хотя Gmail и Youtube — это сервисы Google, но всё же раздельные продукты. Как они аутентифицируют пользователя во всех продуктах после единственного входа?


Этот метод называется единой точкой входа (Single Sign On, SSO).


Реализовать его можно по-разному. Например, использовать центральный сервис для оркестрации единого входа между несколькими клиентами. В случае с Google этот сервис называется Google Accounts. Когда пользователь логинится, Google Accounts создаёт куку, которая сохраняется за пользователем, когда тот ходит по принадлежащим компании сервисам. Как это работает:


  1. Пользователь входит в один из сервисов Google.
  2. Пользователь получает сгенерированную в Google Accounts куку.
  3. Пользователь идёт в другой продукт Google.
  4. Пользователь снова перенаправляется в Google Accounts.
  5. Google Accounts видит, что пользователю уже присвоена кука, и перенаправляет пользователя в запрошенный продукт.

Очень простое описание единой точки входа: пользователь входит один раз и получает доступ ко всем системам без необходимости входить в каждую из них. В этой процедуре используется три сущности, доверяющие другу прямо и косвенно. Пользователь вводит пароль (или аутентифицируется иначе) у поставщика идентификационной информации (identity provider, IDP), чтобы получить доступ к поставщику услуги (service provider (SP). Пользователь доверяет IDP, и SP доверяет IDP, так что SP может доверять пользователю.


Выглядит очень просто, но конкретные реализации бывают очень сложными. Подробнее об этом методе аутентификации.


Аутентификация в соцсетях


Уверен, эта картинка знакома всем:



Это часто называют аутентификацией в соцсетях (Social sign-in) или социальным логином (Social Login). Вы можете аутентифицировать пользователей по их аккаунтам в соцсетях. Тогда пользователям не придётся регистрироваться отдельно в вашем приложении.


Формально социальный логин — это не отдельный метод аутентификации. Это разновидность единой точки входа с упрощением процесса регистрации/входа пользователя в ваше приложение.


Лучшее из двух миров


Пользователи могут войти в ваше приложение одним кликом, если у них есть аккаунт в одной из соцсетей. Им не нужно помнить логины и пароли. Это сильно улучшает опыт использования вашего приложения. Вам как разработчику не нужно волноваться о безопасности пользовательских данных и думать о проверке адресов почты — они уже проверены соцсетями. Кроме того, в соцсетях уже есть механизмы восстановления пароля.


Как использовать


Как разработчик вы должны разбираться в работе этого метода аутентификации. Большинство соцсетей в качестве механизма аутентификации используют авторизацию через OAuth2 (некоторые используют OAuth1, например Twitter). Разберёмся, что такое OAuth. Соцсеть — это сервер ресурсов, ваше приложение — клиент, а пытающийся войти в ваше приложение пользователь — владелец ресурса. Ресурсом называется пользовательский профиль / информация для аутентификации. Когда пользователь хочет войти в ваше приложение, оно перенаправляет пользователя в соцсеть для аутентификации (обычно это всплывающее окно с URL’ом соцсети). После успешной аутентификации пользователь должен дать вашему приложению разрешение на доступ к своему профилю из соцсети. Затем соцсеть возвращает пользователя обратно в ваше приложение, но уже с токеном доступа. В следующий раз приложение возьмёт этот токен и запросит у соцсети информацию из пользовательского профиля. Так работает OAuth (ради простоты я опустил технические подробности).


Для реализации такого механизма вам может понадобиться зарегистрировать своё приложение в разных соцсетях. Вам дадут app_id и другие ключи для конфигурирования подключения к соцсетям. Также есть несколько популярных библиотек/пакетов (вроде Passport, Laravel Socialite и т. д.), которые помогут упростить процедуру и избавят от излишней возни.


Двухфакторная аутентификация (2FA)


Двухфакторная аутентификация (2FA) улучшает безопасность доступа за счёт использования двух методов (также называемых факторами) проверки личности пользователя. Это разновидность многофакторной аутентификации. Наверное, вам не приходило в голову, но в банкоматах вы проходите двухфакторную аутентификацию: на вашей банковской карте должна быть записана правильная информация, и в дополнение к этому вы вводите PIN. Если кто-то украдёт вашу карту, то без кода он не сможет ею воспользоваться. (Не факт! — Примеч. пер.) То есть в системе двухфакторной аутентификации пользователь получает доступ только после того, как предоставит несколько отдельных частей информации.


Другой знакомый пример — двухфакторная аутентификация Mail.Ru, Google, Facebook и т. д. Если включён этот метод входа, то сначала вам нужно ввести логин и пароль, а затем одноразовый пароль (код проверки), отправляемый по SMS. Если ваш обычный пароль был скомпрометирован, аккаунт останется защищённым, потому что на втором шаге входа злоумышленник не сможет ввести нужный код проверки.



Вместо одноразового пароля в качестве второго фактора могут использоваться отпечатки пальцев или снимок сетчатки.


При двухфакторной аутентификации пользователь должен предоставить два из трёх:


  • То, что вы знаете: пароль или PIN.
  • То, что у вас есть: физическое устройство (смартфон) или приложение, генерирующее одноразовые пароли.
  • Часть вас: биологически уникальное свойство вроде ваших отпечатков пальцев, голоса или снимка сетчатки.

Большинство хакеров охотятся за паролями и PIN-кодами. Гораздо труднее получить доступ к генератору токенов или биологическим свойствам, поэтому сегодня двухфакторка обеспечивает высокую безопасность аккаунтов.


То есть это универсальное решение? Возможно, нет.


И всё же двухфакторка поможет усилить безопасность аутентификации в вашем приложении. Как реализовать? Возможно, стоит не велосипедить, а воспользоваться существующими решениями вроде Auth0 или Duo.


Аутентификация или авторизация?


Некоторые путают термины «аутентификация» и «авторизация». Это разные вещи.


  • Аутентификация — это проверка вашей личности. Когда вы входите в приложение с именем и паролем, вы аутентифицируетесь.
  • Авторизация — это проверка наличия у вас доступа к чему-либо. Это может быть набор разрешений на какие-то действия. Например, если вы создали в приложении ресурс, то вы можете быть единственным, кому разрешено удалять этот ресурс (потому что вы владелец), а другие пользователи для того не «авторизованы».


Ещё тут?


Поздравляю, вы успешно дочитали длинную, нудную и скучную статью.

Комментарии (68)


  1. nmk2002
    28.11.2017 13:25

    Спасибо за статью. Немного намешено разных аспектов аутентифкации, но в основном написаны правильные вещи.

    И ещё один, менее (пока) популярный (и доступный только на устройствах Apple) метод беспарольной аутентификации: использовать Touch ID для аутентификации по отпечаткам пальцев.

    Тут надо отметить, что Touch ID обычно только заменят PIN-код при доступе к криптографическим ключам, которые используются для аутентификации.
    Кстати есть решения и с новомодным FaceID.
    Что касается биометрии, то ее следует рассматривать как локальную аутентификацию на устройстве. Я бы избегал систем, где биометрические данные используются для централизованной аутентификации.

    Одним из трендов в аутентификации обещает стать FIDO U2F. Он, к сожалению, не упоминается в этой статье. Про него очень неплохо написано тут.


  1. Loki3000
    28.11.2017 14:51

    Что-то с токенами я не очень понял: если у каждого клиента на сервере хранится свой ключ для подписи токена, то один фиг придется лазить в базу при каждом запросе, если же один ключ для подписей всех токенов, то непонятно как инвалидировать скомпрометированные токены?


    1. nmk2002
      28.11.2017 15:21

      Очевидно, что сервер подписывает ответ своим ключом для всех токенов.
      Если аутентификация stateless, то инвалидировать нельзя никак. Единственное, чем вы можете управлять это время жизни токена. Нужно с умом выбирать тот или иной способ аутентификации в соответсвии с конкретной задачей. И конечно не стоит слепо гнаться за «набирающими популярность» вещами. Надо все самому взвешивать и оценивать.


    1. ahmpro
      28.11.2017 17:00

      by-design инвалидировать не получится, только костылить и хранить список отозванных токенов, что по сути возвращает нас к сессиям


      1. Vanadium
        29.11.2017 02:14

        По сути — да, но размер базы будет меньше, а поиск быстрее, ведь список отозванных токенов будет куда короче, чем список вообще всех токенов, плюс по истечении времени действия отозванных токенов их можно безопасно удалять.


        1. DonAlPAtino
          29.11.2017 13:08

          А разве чтобы отозвать токен нам не придется его где-то хранить на сервере? Иначе как отозвать токен, который где-то там на клиенте? Или я чего-то не понимаю…


          1. pbatanov
            29.11.2017 21:16

            Хранит придется только его идентификатор, что очень дешево


          1. Vanadium
            30.11.2017 02:56

            Да, нам придется хранить на сервере список отозванных токенов, но это будет куда дешевле, чем хранить вообще все токены. Это некоторый компромисс между удобством валидации токена и возможностью его отозвать


            1. ahmpro
              30.11.2017 16:43
              -1

              На самом деле не вижу особенной разницы между хранением всех токенов или только отозванных. И в том и другом случае об этом надо думать.
              А вопрос объема дело десятое, т.к. на малом объеме это не существенно, а на большом есть проблемы и посерьезнее.


              1. nvv
                30.11.2017 17:32
                +1

                Отозванные за всё время хранить "дёшево"?


                1. pbatanov
                  30.11.2017 19:53

                  Зачем хранить за все время? или вы токены выдаете на года? Хранить надо до истечения времени жизни токена


            1. DonAlPAtino
              30.11.2017 19:06

              Вы меня не поняли. Разве не надо в каком-то виде хранить инфу о выданном токене, чтобы потом его можно было отозвать? Как можно отозвать на сервере то чего на сервер нет?


              1. pbatanov
                30.11.2017 19:55

                Как сейчас государство отзывает (объявляет недействительными) паспорта, которые лежат у нас в карманах? Принцип примерно тот же — достаточно внести идентификатор в базу. Хранить идентификатор — дешево. Проверить — быстро.


  1. crazylh
    28.11.2017 15:30

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

    И вот тут есть проблема — приложение должно особым образом обрабатывать выход (закрытие вкладки или окна). Так же стоит обратить внимание что токен не может быть отозван серверном до истечения expire. Ну то есть можно, но вообще нет.


    1. samizdam
      29.11.2017 00:13

      Пожалуй единственный недостаток jwt — отсутствие стандартных механизмов верификации. Но это прямо вытекает из его ориентированности на распределённость.


      1. YourChief
        29.11.2017 00:49

        Не совсем понятно, что вы имеете в виду под «стандартными механизмами верификации». Можете ли Вы раскрыть более детально ваш тезис?


        1. shalomman
          29.11.2017 11:05

          Наверно имелось ввиду то, что верифицировать токен можно имея только приватный ключ сервера.
          Это не очень удобно если нужно дать возможность верификации другим сервисам (или даже сторонним). Было бы удобно если бы поддерживался еще и открытый ключ для верификации который можно было бы передавать другим.


          1. kafeman
            29.11.2017 13:13

            Вы не поверите:

            {"alg":"RS256","typ":"JWT"}


        1. samizdam
          29.11.2017 21:25

          Я имел ввиду, что технология JWT не предусматривает механизма отзыва токена по инициативе сервера, или проверки его актуальности. Без централтного сервера выдачи токенов, или сессионно подобного хранилища этого не реализовать, кмк.


          1. nvv
            30.11.2017 17:41

            Возможно ограничение целей/приложений где и как долго токен действует.
            Или приложение может требовать токен не старше N секунд и отправлять принудительно за новым


            1. samizdam
              30.11.2017 21:47

              Возможно ограничение целей/приложений где и как долго токен действует.

              Если в самом токене — это не возможность отзыва при бане, например.
              Или приложение может требовать токен не старше N секунд и отправлять принудительно за новым
              механизм получения по хорошему должен требовать действий от пользователя (аутентификация), в общем случае. Получается ограничение жизни «сессии».


  1. FreeDobby
    28.11.2017 16:49

    Не очень понял насчет токенов. Если токен хранится только на клиенте и в нем содержится роль юзера, то что ему мешает подделать ее и прописать себя админом? Или он зашифрованный хранится?

    И еще, не надо сыпать сложной терминологией в простой статье без пояснений, пожалуйста. :( Я ничего не знаю про репликацию. Я даже не знаю что это.

    А так вообще очень крутая статья. Хорошо все объяснено.


    1. dmirogin
      28.11.2017 16:58

      В статье приведена ссылка на английский ресурс, где очень хорошо рассказывается про JWT.


    1. YourChief
      28.11.2017 17:59

      Если токен хранится только на клиенте и в нем содержится роль юзера, то что ему мешает подделать ее и прописать себя админом?

      Этому препятствует тот факт, что токен криптографически подписан.


      1. genew
        29.11.2017 10:47

        На расшифровку подписи при каждом запросе будут тратиться ресурсы сервера.
        Значит у сессий и у токенов один общий недостаток остается — нагрузка на сервер.


        1. xpoback
          29.11.2017 13:19

          Нагрузка, которой вполне можно пренебречь


  1. Akdmeh
    28.11.2017 17:16

    Вы вот шутите первой картинкой: «я использую только md5», а я сейчас как раз правлю сайт, в котором все пароли вместе с эмейлами лежат в таблице MySQL без любого шифра…
    А вы говорите, «md5»…


    1. PravdorubMSK
      28.11.2017 18:06
      -1

      пароли без соли в md5 — в принципе, правильное решение — при потери соли придется обнулять все пароли


      1. Akdmeh
        28.11.2017 18:09
        +1

        Правильное решение в PHP — это хэшировать с помощью password_hash.
        А без соли хранить md5 нельзя, так как в наши дни это равнозначно отсутствию хеширования — сейчас существует масса таблиц, в которых можно запросто найти все популярные хеши md5.


        1. user-vova
          29.11.2017 09:16

          Хранить md5 нельзя ни с солью, ни без. Это очень быстрый алгоритм. А массу радужных таблиц можно найти далеко не только для md5.


          1. khim
            29.11.2017 12:01

            Раз уж вы так уверены в том, что MD5 хранить нельзя, то, наверное, знаете когда для него нашли прообраз, да? Ну или хотя бы для MD2, который, как известно, ещё хуже, чем MD5?

            Правильный ответ
            Ни MD5, ни MD2 до сих пор не взломаны. Атака дней рождения успешно убивается случайной солью, а без этого — требуется память, измеряемая зеттабайтами даже для MD2


            1. YourChief
              29.11.2017 14:15

              Не совсем понимаю, причём тут атака дней рождения и случайная соль. Случайная соль нужна для того, чтобы нельзя было радужную таблицу построить. Атака дней рождения — из другой оперы.

              MD5 и какие-либо другие одиночные хэши не стоит использовать даже с солью — при известном хэше и соли 8-мизначный пароль из букв верхнего и нижнего регистра, цифр и спецсимволов можно перебрать за несколько часов. Вместо этого современные системы используют PBKDF2 с большим количеством итераций для сверки пароля.


              1. khim
                29.11.2017 17:55

                Не совсем понимаю, причём тут атака дней рождения
                В том и дело, что ни причём. Но это единственная атака, которую практически можно провести на MD5. Кроме перебора, конечно.

                MD5 и какие-либо другие одиночные хэши не стоит использовать даже с солью — при известном хэше и соли 8-мизначный пароль из букв верхнего и нижнего регистра, цифр и спецсимволов можно перебрать за несколько часов.
                Это другая история. Можно точно также сделать много раундов MD5.


    1. Fafhrd
      28.11.2017 22:43

      Какого года сайт?
      Лет 15-17 назад мало кто заморачивался хешированиями и соленьями.
      Открытые пароли в базах лежали в каждой первой базе, которую я видел ^_^


      1. Akdmeh
        28.11.2017 22:44

        Свежий сайт, работает на PHP 7.0 минимум (из-за синтаксического сахара не запустишь на более ранней версии). Просто вот такие разработчики с таким вот опытом…


  1. DarkGenius
    28.11.2017 19:00

    Хотелось бы еще почитать про аутентификацию на основе утверждений (claims-based).


  1. dolovar
    28.11.2017 19:56

    Аутентификация — это проверка вашей личности. Когда вы входите в приложение с именем и паролем, вы аутентифицируетесь.
    Пароль в примере — способ разрешить дальнейшее использование аккаунта, идентификатором которого выступает имя. Аутентификация — проверка на подлинность, на соответствие заявленному. Проверку прав на доступ к аккаунту можно считать подвидом авторизации. Аутентификацию можно считать неотъемлемой частью, обязательным шагом процедуры авторизации. То есть «не путайте» не должно превратиться в «основательно разделяйте».


  1. Neuyazvimy1
    28.11.2017 22:46

    А еще можно новомодным блокчейном аутентификацию делать)


    1. worldxaker
      29.11.2017 00:32

      запарная это штука. пока простое решение есть у emercoin, но там авторизация по сертификату. но для его получения нужен кошелёк и прочие проблемы


  1. TimsTims
    28.11.2017 23:13

    Про минусы токенов то не написали: невозможно инвалидировать принудительно, и возросший оверхед при запросах.


    1. pbatanov
      29.11.2017 21:23

      Не очень понятно про возросший оверхед — сессию вы проверяли бесплатно? Поясните, пожалуйста. Инвалидация — да, болячка известная


  1. Tab10id
    28.11.2017 23:21

    Понимаю что статья для новичков и вообще является перводом, но тут явно не хватает описания минусов всех описанных методов помимо аутентификации по сессии (а они есть и еще огого какие). Кроме того можно было бы хотя бы перечислить некоторые менее очевидные методы (тот же kerberos, к примеру).


  1. samizdam
    29.11.2017 00:08

    Мне кажется, или идея уже освещалась на хабре уважаемым SuperPaintman не так давно
    https://habrahabr.ru/post/341164/


    1. TimsTims
      29.11.2017 02:06

      del


  1. newpavlov
    29.11.2017 00:20
    +1

    Странно что не упомянули такую вещь как PAKE, которая позволяет аутентифицировать пользователя не передавая его пароль на сервер, тем самым исключая возможность «логирования» данного пароля сервером в открытом виде.


  1. debounce
    29.11.2017 01:22

    Apple здесь превзошла всех: root без пароля теперь для всех и каждого
    Попробуйте twitter.com/lemiorhan/status/935578694541770752


  1. rustamaha
    29.11.2017 06:29

    Спасибо, актуально! Как раз ночью сдал контрольную на coursera.org, по аутентификации и авторизации в node.js через токены и пасспорт и думал что-нибудь почитать ещё по теме)


  1. JuniorIL
    29.11.2017 07:53

    Автор, большое тебе спасибо! Я давно искал что-то вроде JWT, но почему-то Гугл для авторизации без состояния советовал только отдельные сервера для аутентификации, типо SAML и oAuth. Единственное о чем я думаю, секрет должен генерироваться раз в какой-то промежуток времени, иначе если его подобрали, то вся система скомпрометирована.


  1. 0x1000000
    29.11.2017 08:54

    В статье приравниваются понятия аутентификации на основе кук и на основе сессий. Но ничто не мешает положить тот же токен в куку и не создавать сессии на сервере.


    1. user-vova
      29.11.2017 09:21

      В статье так и написано.
      "Токен хранится на клиентской стороне, чаще всего в локальном хранилище, но может лежать и в хранилище сессий или кук."


      1. DonAlPAtino
        29.11.2017 13:14

        Тренировался тут на кошках… токены для gmail и vk.com благополучно были доставлены на другую машину путем экспорта-импорта кук. На свежей машине для тех же свежеавторизованных gmail и vk.com в локальном хранилище ничего. Возникает подозрение, что токены ОБЫЧНО хранятся в куках, но МОГУТ лежать и в локальном хранилище. Т.е. все наоборот. Какой все-таки best practice в этом вопросе?


        1. user-vova
          29.11.2017 16:14

          Или я вас не пойму, или вы запутались.
          Сессионный токен это просто идентификатор без полезной нагрузки, просто случайно сгенерированная строка. Такой токен нет особого смысла держать в веб-хранилище. Он передается на сервер через куки, а потом сравнивается с имеющимися токенами в БД.


          Токен JWT это зашифрованные данные. Они могут занимать большой размер и поэтому в куки могут не поместится, тут на помощь приходит веб-хранилище. Поскольку доступ к этому хранилищу осуществляется через js, то такой подход актуален, в основном, для SPA.


          1. DonAlPAtino
            29.11.2017 16:48

            Однозначно я запутался -поэтому и спрашиваю. Тогда уточнение gmail и vk вообще используют JWT для авторизации? А кто из больших использует? Хочется в chrome dev tool на него «живьем» посмотреть.
            И правильно ли я понимаю, что если мы используем jwt — мы должны его при каждом запросе передавать на сервер? или есть нюансы?


            1. FilimoniC
              29.11.2017 18:53

              Токен jwt содержит ваш userid и все права котопые вам нужны. Типа «Пользователь 17, Администратор рубрики 1, администратор рубрики 7». Эту строку сервер генерирует и подписывает своим сертификатом и отдает вам. Пои последующих запросах вы только отдаете эту строку серверу, и если сервер убедился что строка подписана его сертификатом то он доверяет указанным правам сразу, не проверяя ваши права ни по каким своим базам.
              Токен jwt можно использовать как вам вздумается. Например если у вас токен большой то чтобы его не гонять, можно его хранить в webstorage и токеном получать классическую сессионную куку на сервере и гонять уже ее. В таком случае плюс в экономии траффика и возможности сделать короткую сессию чтобы базу не забивать сессиями годовалой давности.

              Недостаток у токена один: если кто то отберет у вас права, то в токене они останутся и сервер будет доверять токену, а не обновленным правам (потому что токен валиден). Чтобы этого избежать придется городить костыль и проверять права при каждом запросе, и jwt перестает отличаться от простых сессионных куки. Можно конечно сделать красивый костыль — например при смене прав куда-то писать что для такого пользователя все токены старше х считать недействительными, и еще хранить дату выдачи в токене, и еще проверять при каждом запросе эту базу, вместо перечитывания всех прав


              1. DonAlPAtino
                30.11.2017 19:10

                Ну и все-таки у кого из известных сервис провайдеров можно живьем jwt увидеть? Хоть в хранилище, хоть в куках…


  1. user-vova
    29.11.2017 09:05

    "Кроме того, раз вы можете хранить внутри JWT дополнительные данные вроде пользовательских разрешений, то можете сэкономить и дополнительные обращения поисковые запросы на получение и обработку данных."


    Ага, а если нам нужно изменить пользовательские разрешения?


    1. Amikrill
      29.11.2017 13:19

      Всегда можно выдать пользователю новый токен


      1. user-vova
        29.11.2017 15:05

        Ну на сервере мы токен не храним. Когда пользователь к нам прийдёт с токеном, откуда мы будем знать что для него нужно выдать новый токен? Из БД?


        1. DonAlPAtino
          29.11.2017 16:54

          Могу предположить что надо сравнивать дату выдачи токена и дату изменения записи пользователя… И еще в этом момент сразу отзывать старый токен. А то будет потом ходить один пользователь с разными токенами, разными правами скажем с разных машин и жаловаться что «все глючит».


  1. coalesce
    29.11.2017 09:48

    Забавный момент в переводе
    Оригинал
    Another example you might be familiar with is the 2-step verification of Google, facebook etc.

    Перевод
    Другой знакомый пример — двухфакторная аутентификация Mail.Ru, Google, Facebook и т. д.


    1. jia3ep
      29.11.2017 09:53

      Забавно (а скорее печально) тут то, что это — знакомый пример двухшаговой аутентификации (2-step verification — 2SV), которую часто ошибочно считают двухфакторной (2FV). И такая ошибка в переводе более существенна, чем безобидное расширение списка компаний.

      ГОСТ на эту тему сейчас только разрабатывается, но есть же NIST SP 800-63b, где про это очень хорошо написано. И Mail.ru стоило бы более грамотно подходить к этому вопросу, в переводах в том числе.


  1. Ti_Fix
    29.11.2017 12:00

    Авторизация — это проверка наличия у вас доступа к чему-либо. Это может быть набор разрешений на какие-то действия.

    Авторизация — это НЕ проверка наличия у вас доступа к чему-либо.
    Авторизация — это процедура предоставления субъекту определённых прав.


    1. xi-tauw
      29.11.2017 12:24

      В литературе часто встречается, что авторизация состоит из двух частей — аутентификации (проверки наличия прав), а затем, по результатам, предоставление этих прав или отказ в них.
      Так что это вопрос базисной терминологии.


      1. foal
        29.11.2017 14:00

        Ну вот, вы всё запутали :) Aутентификация — проверка того, что идетифицированный субъект, есть тот за кого себя выдает. До прав еще не дошли. Контроль доступа (access approval, access control или enforcement) проверка при действии субъекта на наличие у него прав на это действие, то что часто и, не совсем правильно, называют авторизацией по-русски.


      1. dolovar
        29.11.2017 18:14

        Поддерживаю, проблема размытости термина — авторизация это и процесс, и результат процесса.
        Если процесс, то включает в себя аутентификацию.
        Если результат, то отказ или отсутствие отказа, причем отсутствие отказа можно назвать предоставлением права.


  1. kafeman
    29.11.2017 13:10

    На мой взгляд незаслуженно не рассмотрен вариант аутентификации на основе X.509.

    В случае с Google этот сервис называется Google Accounts.
    ЕМНИП сервис называется Google Maia, или что-то вроде того.


  1. GeorgeIV
    29.11.2017 13:19

    Since JWT are signed and encoded only, and since JWT are not encrypted, JWT do not guarantee any security for sensitive data.


    1. ahmpro
      30.11.2017 16:53

      Есть такое, но это не особая проблема т.к. и так JWT должен пересылаться поверх https. Если нужно большее, то есть JWE (JSON Web Encryption).