РНР-безопасность: где и как хранить пароли. Часть 1

    Каждый год в мире происходит все больше хакерских атак: от краж кредитных карт до взломов сайтов онлайн-магазинов. Уверены, что ваши скрипты по настоящему защищены? В преддверии старта курса «Backend-разработчик на PHP» наш коллега подготовил интересную публикацию на тему безопасности в PHP...




    Введение


    Скандал с Facebook и Cambridge Analytica, утечка переписки Демократической партии США в 2016 году, нарушение безопасности данных Google в 2018 году, взлом Yahoo Voice в 2012 году — вот лишь несколько примеров крупных утечек, зафиксированных за последние несколько лет.

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

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

    Язык РНР предоставляет несколько инструментов и функций, которые можно задействовать для обеспечения безопасности приложения.

    3 правила безопасности паролей




    Пароли пользователей должны оставаться неизвестными для вас.


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

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

    Методом проб и ошибок вы все равно придете к выводу, что пароли не надо хранить в формате обычного текста или в таком виде, чтобы они легко поддались расшифровке.

    Не вводите ограничения на пароли


    Давайте сыграем в одну игру. Попробуйте угадать пароль:

    **********

    Сложно, правда? Давайте попробуем так:

    P*r***e***

    Теперь вы знаете, что здесь есть заглавная буква и несколько прописных. А если вот так:

    P*r***e911

    Теперь вам будет намного легче угадать пароль — ведь вы знаете, что он включает в себя заглавную букву, прописные буквы и число.

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

    Требовать некую минимальную длину пароля — это нормально, так как длина пароля влияет на то время, которое требуется, чтобы подобрать его. Однако вместо этого будет намного полезнее узнать, как работают алгоритмы и хеширование.

    Кстати, правильный ответ к приведенной выше загадке — «Porsche911» :)

    Никогда не отправляйте пароли по е-мейлу в чистом виде


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

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

    1. Он знает ваш пароль.
    2. Он хранит ваш пароль в чистом виде, не используя никакого шифрования.
    3. Он не испытывает ни малейшего беспокойства при пересылке паролей через интернет.

    В ответ ничего не остаётся, как уволить такого сотрудника.

    А вот как должен поступить веб-разработчик:

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

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

    Видите, насколько возросла безопасность приложения благодаря этим простым шагам? При желании, мы можем повысить уровень безопасности еще больше, добавив лимит времени между запросом и установлением нового пароля.

    Как хешировать пароли пользователей




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

    Хеширование предполагает, что последовательность нельзя вернуть в формат незашифрованного текста. Именно это конечная цель всего процесса.

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

    SHA-1


    Это была исторически первая функция хеширования. Аббревиатура SHA-1 расшифровывается как «безопасный алгоритм хеширования», разработало его Агентство национальной безопасности США.

    SHA-1 был хорошо известен и широко востребован в сфере РНР для создания 20-байтовой шестнадцатеричной строки длиной в 40 символов.

    SSL-индустрия в течение нескольких лет пользовалась SHA-1 для цифровых подписей. Затем, после выявления некоторых слабых мест, в Google решили, что пора переходить на SHA-2.
    Первая версия алгоритма была признана устаревшей в 2005 году. Впоследствии были разработаны и приняты к использованию новые версии: SHA-2, SHA-2 и SHA-256.

    Bcrypt


    Bcrypt, не являясь результатом естественного развития SHA, сумел привлечь к себе широкую аудиторию благодаря своему уровню безопасности.

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

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

    Argon2


    Это новый модный алгоритм в сфере хеширования, разработанный Алексом Бирюковым, Даниэлем Дину и Дмитрием Ховратовичем из Люксембургского университета. В 2015 году он стал победителем Конкурса хеширования паролей.

    Argon2 представлен в 3 версиях:

    1. Argon2d обращается к массиву памяти, что сокращает издержки памяти и времени. Однако у него существует риск атаки по сторонним каналам.
    2. Argon2i является противоположностью Argon 2d. Он оптимизирован относительно атак по сторонним каналам и получает доступ к памяти в порядке, не зависящем от пароля.
    3. Argon2id представляет собой промежуточный вариант между двумя предыдущими версиями.

    Эта функция насчитывает 6 параметров: последовательность пароля, salt, memory cost, time cost, фактор параллелизма (максимальное разрешенное число параллельных потоков), длина хеша.

    Во второй части статьи я расскажу, как использовать это хеширование в РНР, задействуя встроенные функции, а сейчас хочу пригласить всех на бесплатный онлайн вебинар «ServerLess PHP», в рамках которого мы познакомимся с концепцией Serverless, поговорим о её реализации в AWS, применимости, ценах. Разберём принципы сборки и запуска, а также построим простой TG-бот на базе AWS Lambda.
    OTUS. Онлайн-образование
    680,59
    Цифровые навыки от ведущих экспертов
    Поделиться публикацией

    Комментарии 35

      0
      Это была исторически первая функция хеширования. Аббревиатура SHA-1 расшифровывается как «безопасный алгоритм хеширования»
      А куда MD5 исчез — который появился на 3 года раньше? А до MD5 был MD4. А до MD4…

      И ведь до сих пор горе-разработчики, насмотревшиеся «курсов PHP», пишут:
      $hash = md5(md5($password));

      А после SHA-2 был создан SHA-3 — и о нём в статье тоже ни слова.
        +1
        Отсутствие MD5 говорит о том, когда автор начал первые шаги в хешировании паролей.
        Ждём статью от «метров безопасности», которые скажут, что первый был DES из 70-х. Главное, что бы они не сказали, что MD5 — это самый последний.
          0
          Осталось понять что DES и MD5 — алгоритмы разного, скажем так, назначения…
            0
            Потому «метры» в кавычках.
              +1
              Сарказм оказался слишком тонок ;-)
          +1
          А после SHA-2 был создан SHA-3 — и о нём в статье тоже ни слова.

          Да, как же давно это было, вы прямо совсем в историю закопались! Сейчас-то все уже на SHA-256, а некоторые и на SHA-512 сидят! [/sarcasm]
            0
            мы старались писать всё таки о новейшей, так сказать, истории. Поэтому MD5 не взяли по временным характеристикам, SHA-2 и SHA-3 по причине схожести логики работы
            +7
            Почему в статье о хешировании паролей в PHP ни слова про функцию password_hash?
            Ответа на вопрос «где» хранить пароли — в статье не содержится, статья не соответствует заголовку.
              –2
              про password_hash поговорим в следующей части
                +9
                Простите, но это как-то не тянет на статью или даже на часть. Это похоже на урезанную справочную информацию созданную ради ссылки в конце на «бесплатный онлайн вебинар».
                  +2

                  Назначение этой статьи не дать ответы на вопросы в заголовке, не принести какие-то знания, а только быть вместилищем для рекламных ссылок. Тут и РНР за уши притянут потому, что надо прорекламировать соотв. курс.


                  По-моему это вообще один из самых низкокачественных корпоративных блогов.

              +6
              За отсутствие упоминания о password_hash() — однозначный минус.
              От таких «статей» больше вреда, чем пользы.
                –1
                Такое ощущение, что этот вот сценарий копипастят не особо понимая, т.к. звучит он красиво и весомо «заказчик знает как лучше, увольняет разработчика, ввернуто пара умных слов про хэширование, круто чё»
                мы про этот сценарий
                Представьте, что вы клиент и вы нанимаете разработчика, чтобы он создал для вашего бизнеса симпатичный сайт электронной коммерции. Этот разработчик прислал вам е-мейл, который содержит пароль для вашего сайта. Теперь вам известно три вещи о вашем сотруднике:

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

                В ответ ничего не остаётся, как уволить такого сотрудника.

                А вот как должен поступить веб-разработчик:

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

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

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

                По поводу того, как должен был поступить веб-разработчик.
                Он должен был поступить соответственно ТЗ предоставленному заказчиком.
                Неожиданно, да? Но абсолютно верно. Если поступил по ТЗ — прав, если не по ТЗ — не прав.
                Если у разработчика спрашивают мнение по поводу ТЗ, он может его высказывать, но после принятия ТЗ — он должен делать всё по ТЗ и только так. Всё на этом.
                  0

                  А если нет ТЗ? Да и заказчика нет, есть начальство.

                    0
                    В таком случае, скорее всего вы должны написать ТЗ, или ваше непосредственное начальство, буде оно обладает необходимым техническим бэкграундом. Иначе рискуете получить продукт, резко отличающийся от того что хотело начальство и долгие разговоры на тему «Я же ясно объяснил, что сайт должен быть как у ХХХ, а он не как у ХХХ, мне пофиг что они за это время 3 раза сменили стиль и функционал!». В случае конторы условного дяди Коли с 1 «программистом», клепающим сайты на вордпресс, я думаю вопрос ТЗ стоит не настолько остро.
                      0

                      Какая разница между "написать себе ТЗ по решению бизнес-задачи и имплементировать его в коде" и "решить бизнес-задачу в коде"? Сунуть его на подпись человеку, который не понимает ничего в нём и прикрыть тем самым себе разные места?

                        0
                        Сунуть его на подпись человеку, который не понимает ничего в нём и прикрыть тем самым себе разные места?
                        Вы удивитесь — суть технического задания не в том чтобы описать себе процессы разработки, а в том чтобы согласовать «задумку» условного заказчика с реально работающим кодом. И ТЗ — это не только про «реализовать контроллеры a, b, и c, используя протоколы x, y, z», но и «В верхней части сайта расположено меню, содержащее следующие пункты:…, в дизайне представленном в приложении (6). При клике на пункт… ». То есть вполне себе сценарий использования, который доступен обывателю.
                          0

                          Вы удивитесь, но для некоторых сценарии использования — это входные данные для составления ТЗ, если оно составляется. Может в мире госзаказов и гостов всё несколько по другому, конечно.

                            0
                            Сценарии использования являются неотъемлемой частью ТЗ, так как функционал внутренний описывает ЧТО делать, а кейсы описывают механизмы взаимодействия с интерфейсом. И именно это будет проверять конечный заказчик перед приемкой и подписанием акта выполненных работ, а вовсе не то насколько тонкие у вас контроллеры.
                              0

                              Не сильно ошибся с госзаказом… заказичк, акты...

                  0

                  Передача паролей в открытом виде имеет право на жизнь. Например в случае телефонной (голос или смс), почтовой (бумажной) или офисной поддержки. Но это должен быть одноразовый пароль.


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

                    0
                    А я вот вообще отказался от паролей.

                    В приложении хранится только email или телефон, при входе отправляется письмо (или смс) с одноразовым кодом, код валиден только 1 час + связан с email или телефоном.

                    Плюсы (из-за отсутствия паролей):
                    + Пользователи не смогут делать простые пароли
                    + Пользователь никогда не забудет свой пароль, не нужно делать механизм восстановления пароля
                    + При краже базы пользователей не получится узнать пароли пользователей от других сервисов (а то ведь многие используют на сторонних сервисах почту и пароль от этой почты)

                    Минусы:
                    — Получив доступ к почте пользователя можно войти в любой сервис, но тут уже итак полный провал, если получили доступ к вашей почте то пиши пропало, даже там где есть пароли, там можно использовать восстановление
                      –1
                      Чем ваш «код» отличается от «пароля»?
                        0
                        Ммм, временем жизни (либо протух, либо использовали) он тут же удаляется из базы, т.к. вход произведён и выдана сессия. Коды не хранятся вечно.

                        Ах да, если по одному аккаунту 3 раза ввели неверный код, то все верные активные коды этого аккаунта автоматически удаляются, во избежание возможного брутфорса
                          –1
                          То есть только наличие «времени действия»? Или попыток ввода? Что то это мне напоминает… ах да! Политику паролей. Вот так сюрприз, то есть по сути пароль от кода отличается политикой действия, которую просто можно усложнить. На самом деле пользоваться сервисом который каждый раз для входа будет присылать тебе В СТОРОННИЙ СЕРВИС твой «код», кроме того что сверхнеудобно, так еще и не так уж и безопасно.
                      –1
                      Теперь вам известно три вещи о вашем сотруднике:
                      Он знает ваш пароль.
                      Он хранит ваш пароль в чистом виде, не используя никакого шифрования.
                      Надо добавить что еще вам следует проверить себя на наличие параноидального синдрома.
                      Пароль обычно рандомно генерируется системой и ей же автоматически отправляется, и следовательно «сотрудник» про ваш пароль ни сном ни духом. И естественно пароль не хранится в открытом виде, после отсылки в базе останется только хеш пароля. В остальном — отправлять разовый ключ доступа или сгенерированный системой пароль почти одно и то же, разница в том что поведением разового ключа мы можем управлять (например не пускать второй раз, что впрочем можно реализовать и с временным паролем).

                      PS: В итоге в статье не только не рассказано как (точнее рассказано как не надо) хранить, но и тема где совершенно не раскрыта. Ожидал откровения и хитромудрых подходов, получил тухлый помидор, которым только и можно что пульнуть в автора сего опуса.
                        0
                        Например в Redmine есть такая опция. При создании нового пользователя — указываю опции «сгенерировать пароль», «отправить пароль на почту», «принудительная смена пароля при входе».

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

                          Чтобы слить базу и подставлять из неё?

                            0
                            Да, Вы правы.
                              0
                              Как я понял, хранить подписанную куку, основанную на хеше пароля, уже норм идея?
                                0

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

                              0
                              А не получится ли ошибка:
                              Извините, Вы не можете использовать указанный пароль. Такой пароль уже использует пользователь Misha. Пожалуйста, придумайте другой пароль.
                                0
                                Нет.
                                Дополнительно будет кука с ид пользователя.
                                0
                                Такой алгоритм применяет форум SMF, правда там чуть сложнее — sha1(хеш пароля + сессионый хеш), вроде так. Минус в том, что имея SQL дамп, можно входить от любого пользователя, не тратя время на брут пароля и соли. Хотя, если слит дамп базы, то дела уже весьма плохи…

                                Автор, почему ничего не сказано про соль (salt)? Вы считаете это неактуальным или как? Под веб пишу редко, но помню, что раньше делали md5(pass.salt) и было нормально, т.е. от радужных таблиц уже спасало.

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

                              Самое читаемое