Каждый год в мире происходит все больше хакерских атак: от краж кредитных карт до взломов сайтов онлайн-магазинов. Уверены, что ваши скрипты по настоящему защищены? В преддверии старта курса «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.

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


  1. eandr_67
    06.11.2019 16:25

    А куда MD5 исчез? Ведь до сих пор горе-разработчики, насмотревшиеся «курсов PHP», пишут:

    $hash = md5(md5($password));


    1. nochkin
      06.11.2019 17:28

      Отсутствие MD5 говорит о том, когда автор начал первые шаги в хешировании паролей.
      Ждём статью от «метров безопасности», которые скажут, что первый был DES из 70-х. Главное, что бы они не сказали, что MD5 — это самый последний.


      1. vilgeforce
        06.11.2019 17:32

        Осталось понять что DES и MD5 — алгоритмы разного, скажем так, назначения…


        1. nochkin
          06.11.2019 17:51

          Потому «метры» в кавычках.


          1. vilgeforce
            06.11.2019 17:52

            Сарказм оказался слишком тонок ;-)


    1. Tatikoma
      06.11.2019 17:35

      А после SHA-2 был создан SHA-3 — и о нём в статье тоже ни слова.

      Да, как же давно это было, вы прямо совсем в историю закопались! Сейчас-то все уже на SHA-256, а некоторые и на SHA-512 сидят! [/sarcasm]


    1. nmonax
      06.11.2019 17:40

      мы старались писать всё таки о новейшей, так сказать, истории. Поэтому MD5 не взяли по временным характеристикам, SHA-2 и SHA-3 по причине схожести логики работы


  1. Tatikoma
    06.11.2019 17:29

    Почему в статье о хешировании паролей в PHP ни слова про функцию password_hash?
    Ответа на вопрос «где» хранить пароли — в статье не содержится, статья не соответствует заголовку.


    1. nmonax
      06.11.2019 17:38
      -1

      про password_hash поговорим в следующей части


      1. stalevar1990
        06.11.2019 18:38
        +8

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


        1. maximw
          06.11.2019 22:33
          +2

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


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


  1. AlexLeonov
    06.11.2019 23:29
    +6

    За отсутствие упоминания о password_hash() — однозначный минус.
    От таких «статей» больше вреда, чем пользы.


  1. edogs
    07.11.2019 00:33

    Такое ощущение, что этот вот сценарий копипастят не особо понимая, т.к. звучит он красиво и весомо «заказчик знает как лучше, увольняет разработчика, ввернуто пара умных слов про хэширование, круто чё»

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

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

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

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

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

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

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


    1. VolCh
      07.11.2019 06:49

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


      1. ThunderCat
        07.11.2019 13:07
        -1

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


        1. VolCh
          07.11.2019 13:11

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


          1. ThunderCat
            07.11.2019 13:28

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


            1. VolCh
              07.11.2019 19:20

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


              1. ThunderCat
                08.11.2019 10:40

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


                1. VolCh
                  09.11.2019 19:28

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


  1. VolCh
    07.11.2019 06:56

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


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


  1. DimNS
    07.11.2019 07:55

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

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

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

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


    1. ThunderCat
      07.11.2019 13:09
      -1

      Чем ваш «код» отличается от «пароля»?


      1. DimNS
        07.11.2019 13:11

        Ммм, временем жизни (либо протух, либо использовали) он тут же удаляется из базы, т.к. вход произведён и выдана сессия. Коды не хранятся вечно.

        Ах да, если по одному аккаунту 3 раза ввели неверный код, то все верные активные коды этого аккаунта автоматически удаляются, во избежание возможного брутфорса


        1. ThunderCat
          07.11.2019 13:33
          -1

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


  1. ThunderCat
    07.11.2019 13:17
    -1

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

    PS: В итоге в статье не только не рассказано как (точнее рассказано как не надо) хранить, но и тема где совершенно не раскрыта. Ожидал откровения и хитромудрых подходов, получил тухлый помидор, которым только и можно что пульнуть в автора сего опуса.


    1. Tatikoma
      07.11.2019 13:58

      Например в Redmine есть такая опция. При создании нового пользователя — указываю опции «сгенерировать пароль», «отправить пароль на почту», «принудительная смена пароля при входе».

      Весьма разумный функционал, на мой взгляд.


  1. php7
    07.11.2019 19:01

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


    1. VolCh
      07.11.2019 19:21

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


      1. php7
        09.11.2019 18:09

        Да, Вы правы.


    1. bliznezz
      09.11.2019 16:11

      А не получится ли ошибка:
      Извините, Вы не можете использовать указанный пароль. Такой пароль уже использует пользователь Misha. Пожалуйста, придумайте другой пароль.


      1. php7
        09.11.2019 18:09

        Нет.
        Дополнительно будет кука с ид пользователя.