работа с токенами php
Использование и обработка токенов PHP-форм
Я начинаю работать над скриптом входа в PHP. Это выражение для токенов формы, которое у меня есть до сих пор:
Заявление выдается сразу после того, как пользователь указывает, что он хочет войти в систему.
Мое ограниченное понимание заключается в том, что цель токенов состоит в том, чтобы идентифицировать уникального пользователя в уникальный момент времени и замаскировать информацию о токенах формы.
Тогда все становится нечетким. Вот мои 3 открытых вопроса:
Когда лучше всего «проверить» токен формы для целей безопасности?
Когда когда-либо я «уничтожаю» токен формы? (IOW, будет ли токен формы оставаться активным до тех пор, пока пользователь не выйдет из системы?
Нет необходимости делать то, что вы пытаетесь сделать. Когда вы начинаете сеанс в PHP с помощью session_start (), для вас уже создан уникальный SESSIONID. Вы не должны помещать это в форму. По умолчанию он обрабатывается через файлы cookie. Также нет необходимости проверять SESSIONID, который снова обрабатывается для вас.
Вы должны убедиться, что session_start () является одной из первых вещей для всех страниц вашего сайта.
Изменить: я неправильно понял первоначальный вопрос. Я добавил вышеописанные методы для генерации и проверки хэшей форм;
См. Следующие ресурсы:
это предотвращает атаки CSRF
злоумышленный сайт может теоретически отобразить форму, которая помещается в ваше приложение. форма может содержать инструкции, которые вызывают нарушение данных или какое-либо нежелательное действие. пользователь может быть обманут, отправив форму, которую приложение примет, потому что пользователь уже выполнил вход. Значок формы гарантирует, что форма была создана вашим сайтом, а не каким-либо другим сайтом.
проверка HTTP_REFERER часто достаточно хороша, но не как полное решение (https, например, не отправит строку referrer).
если вы действительно хотите сохранить все формы с помощью токена, вы можете создать некоторые удобные функции, такие как emitToken () и checkToken (), которые сделают его работу по всему сайту.
Вы можете проверить реализацию фреймворка zend.
Помимо конкретной реализации, документы описывают рассуждения и использование этого типа элемента в форме.
Авторизация PHP с помощью JWT (веб-токены JSON)
Было время, когда единственный способ аутентифицировать себя в приложении заключался в предоставлении ваших учетных данных (обычно имени пользователя или адреса электронной почты и пароля), а затем использовался сеанс для поддержания состояния пользователя до тех пор, пока пользователь не вышел из системы. Чуть позже мы начали использовать API аутентификации. А в последнее время JWT или веб-токены JSON все чаще используются как еще один способ аутентификации запросов к серверу.
В этой статье вы узнаете, что такое JWT и как использовать их с PHP для выполнения аутентифицированных запросов пользователей.
JWT против сеансов
Но сначала, почему сеансы — не такая уж хорошая вещь? Что ж, есть три основных причины:
Теперь давайте начнем изучать JWT. Спецификация веб-токена JSON (RFC 7519) была впервые опубликована 28 декабря 2010 г. и последний раз обновлялась в мае 2015 г.
У JWT есть много преимуществ перед ключами API, в том числе:
Как выглядит JWT?
На первый взгляд кажется, что строка представляет собой просто случайные группы символов, объединенных точкой или точкой. Таким образом, он может не сильно отличаться от ключа API. Однако, если вы присмотритесь, есть три отдельные строки.
Заголовок JWT
Первая строка — это заголовок JWT. Это строка JSON в кодировке Base64 с кодировкой URL. Он указывает, какой криптографический алгоритм использовался для генерации подписи, и тип токена, который всегда имеет значение JWT. Алгоритм может быть, как симметричным, так и асимметричным.
Симметричный алгоритм использует один ключ как создать и проверить маркер. Ключ используется совместно создателем JWT и его потребителем. Важно убедиться, что секрет известен только создателю и потребителю. В противном случае любой может создать действующий токен.
Асимметричный алгоритм использует секретный ключ, чтобы подписать маркер и открытый ключ для проверки его. Эти алгоритмы следует использовать, когда общий секрет нецелесообразен или другим сторонам нужно только проверить целостность токена.
Полезная нагрузка JWT
Вторая строка — это полезная нагрузка JWT. Это также строка JSON в кодировке Base64 с кодировкой URL. Он содержит несколько стандартных полей, которые называются «претензиями». Есть три типа требований: зарегистрированные, публичные и частные.
Зарегистрированные претензии предопределены. Вы можете найти их список в RFC JWT. Вот некоторые из наиболее часто используемых:
Публичные претензии можно определять по своему усмотрению. Однако они не могут совпадать с зарегистрированными претензиями или претензиями уже существующих публичных претензий. Вы можете создавать частные претензии по желанию. Они предназначены только для использования двумя сторонами: производителем и потребителем.
Подпись JWT
Подпись JWT — это криптографический механизм, предназначенный для защиты данных JWT с помощью цифровой подписи, уникальной для содержимого токена. Она обеспечивает целостность JWT, чтобы потребители могли убедиться, что она не была взломана злоумышленником.
Подпись JWT — это комбинация трех вещей:
Эти три подписаны цифровой подписью ( не зашифрованы ) с использованием алгоритма, указанного в заголовке JWT. Если мы расшифруем приведенный выше пример, у нас будут следующие строки JSON:
Заголовок JWT
Данные JWT
Попробуйте сами jwt.io, где вы можете поиграть с кодированием и декодированием ваших собственных JWT.
Давайте использовать JWT в приложении на основе PHP
Теперь, когда вы узнали, что такое JWT, пришло время узнать, как использовать их в приложении PHP. Прежде чем мы углубимся, не стесняйтесь клонировать код для этой статьи или следуйте инструкциям и создавайте его по мере продвижения.
Есть много способов подойти к интеграции JWT, но вот как мы это сделаем.
Все запросы к приложению, за исключением страницы входа и выхода, должны быть аутентифицированы через JWT. Если пользователь делает запрос без JWT, он будет перенаправлен на страницу входа.
После того, как пользователь заполнит и отправит форму входа, она будет отправлена через JavaScript в конечную точку входа authenticate.phpв нашем приложении. Затем конечная точка извлечет учетные данные (имя пользователя и пароль) из запроса и проверит, действительны ли они.
Если это так, он сгенерирует JWT и отправит его клиенту. Когда клиент получает JWT, он сохранит его и будет использовать с каждым будущим запросом к приложению.
В упрощенном сценарии пользователь может запросить только один ресурс — файл PHP с подходящим названием resource.php. Он ничего не сделает, просто вернет строку, содержащую текущую временную метку на момент запроса.
Есть несколько способов использовать JWT при выполнении запросов. В нашем приложении JWT будет отправлен в заголовке авторизации Bearer.
Если вы не знакомы с авторизацией на предъявителя, это форма HTTP-аутентификации, при которой токен (например, JWT) отправляется в заголовке запроса. Сервер может проверить токен и определить, следует ли предоставить доступ «носителю» токена.
Вот пример заголовка:
Authorization: Bearer ab0dde18155a43ee83edba4a4542b973
Для каждого запроса, полученного нашим приложением, PHP будет пытаться извлечь токен из заголовка Bearer. Если он присутствует, то он подтверждается. Если он действителен, пользователь увидит нормальный ответ на этот запрос. Однако, если JWT недействителен, пользователю не будет разрешен доступ к ресурсу.
Обратите внимание, что JWT не предназначен для замены файлов cookie сеанса.
Предпосылки
Для начала нам нужно, чтобы в наших системах были установлены PHP и Composer.
В корне проекта запустите composer install. Это приведет к включению Firebase PHP-JWT, сторонней библиотеки, которая упрощает работу с JWT, а также ламинаса-config, предназначенного для упрощения доступа к данным конфигурации в приложениях.
Установив библиотеку, давайте пройдемся по коду входа в authenticate.php. Сначала мы выполняем обычную настройку, гарантируя, что автозагрузчик, созданный Composer, доступен.
Затем мы инициализируем набор переменных, которые будут использоваться для создания JWT. Помните, что, поскольку JWT можно проверить на стороне клиента, не включайте в него конфиденциальную информацию.
Когда данные полезной нагрузки готовы к работе, мы затем используем статический encodeметод php-jwt для создания JWT.
Принимает три параметра:
При вызове echoрезультата функции возвращается сгенерированный токен:
const res = await fetch(’/authenticate.php’, <
’Content-type’: ’application/x-www-form-urlencoded; charset=UTF-8′
if (res.status >= 200 && res.status <
const res = await fetch(’/resource.php’, <
const timeStamp = await res.text();
Когда мы нажимаем кнопку, делается запрос, подобный следующему:
GET /resource.php HTTP/1.1
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE0MjU1ODg4MjEsImp0aSI6IjU0ZjhjMjU1NWQyMjMiLCJpc3MiOiJzcC1qd3Qtc2ltcGxlLXRlY25vbTFrMy5jOS5pbyIsIm5iZiI6MTQyNTU4ODgyMSwiZXhwIjoxNDI1NTkyNDIxLCJkYXRhIjp7InVzZXJJZCI6IjEiLCJ1c2VyTmFtZSI6ImFkbWluIn19.HVYBe9xvPD8qt0wh7rXI8bmRJsQavJ8Qs29yfVbY-A0
Предполагая, что JWT действителен, мы увидим ресурс, после чего ответ будет записан в консоль.
Наконец, давайте посмотрим, как мы можем проверить токен в PHP. Как всегда, мы включили автозагрузчик Composer. Затем мы могли бы, при желании, проверить, был ли использован правильный метод запроса. Я пропустил код, чтобы продолжить работу с кодом, специфичным для JWT:
header(’HTTP/1.1 401 Unauthorized’);
Если токен недействителен, потому что, например, срок действия токена истек, пользователю будет отправлен заголовок HTTP 401 Unauthorized, и сценарий завершится.
Если процесс декодирования JWT завершился неудачно, это могло быть так:
Количество предоставленных сегментов не соответствовало трем стандартным, как описано ранее.
Потребление JWT
Теперь, когда у клиента есть токен, вы можете сохранить его с помощью JavaScript или любого другого механизма, который вам больше нравится. Вот пример того, как это сделать с помощью ванильного JavaScript. В index.htmlпосле успешного представления формы, возвращаемая JWT хранятся в памяти, форма Логина скрыта, и отображается кнопка для запроса метки:
Использование JWT
При нажатии кнопки «Получить текущую отметку времени» выполняется запрос GET resource.php, который устанавливает JWT, полученный после аутентификации, в заголовке авторизации.
Когда мы нажимаем кнопку, делается запрос, подобный следующему:
Предполагая, что JWT действителен, мы увидим ресурс, после чего ответ будет записан в консоль.
Проверка JWT
Наконец, давайте посмотрим, как мы можем проверить токен в PHP. Как всегда, мы включили автозагрузчик Composer. Затем мы могли бы, при желании, проверить, был ли использован правильный метод запроса. Я пропустил код, чтобы продолжить работу с кодом, специфичным для JWT:
Затем код попытается извлечь токен из заголовка Bearer. Я сделал это с помощью preg_match. Если вы не знакомы с функцией, она выполняет сопоставление регулярного выражения в строке.
Регулярное выражение, которое я использовал здесь, будет пытаться извлечь токен из заголовка Bearer и сбросить все остальное. Если он не найден, возвращается неверный запрос HTTP 400:
Обратите внимание, что по умолчанию, Apache не будет проходить в HTTP_AUTHORIZATIONзаголовок PHP.
Заголовок базовой авторизации является безопасным только в том случае, если ваше соединение выполняется через HTTPS, поскольку в противном случае учетные данные отправляются в виде закодированного простого текста (не зашифрованного) по сети, что является огромной проблемой безопасности.
Я полностью понимаю логику этого решения. Однако, чтобы избежать путаницы, добавьте в конфигурацию Apache следующее. Тогда код будет работать должным образом. Если вы используете NGINX, код должен работать должным образом:
Если мы дойдем до этого момента, JWT был извлечен, поэтому мы перейдем к этапу декодирования и проверки. Для этого нам снова понадобится наш секретный ключ, который будет извлечен из среды или конфигурации приложения. Затем мы используем статический decodeметод php-jwt, передавая ему JWT, секретный ключ и массив алгоритмов для декодирования JWT.
Если он может быть успешно декодирован, мы затем пытаемся его проверить. Пример, который у меня здесь, довольно упрощен, поскольку он использует только эмитента, а не временные метки до и истечения срока действия. В реальном приложении вы, вероятно, также использовали бы ряд других утверждений.
Если токен недействителен, потому что, например, срок действия токена истек, пользователю будет отправлен заголовок HTTP 401 Unauthorized, и сценарий завершится.
Если процесс декодирования JWT завершился неудачно, это могло быть так:
Если процесс декодирования и проверки завершится успешно, пользователю будет разрешено сделать запрос, и ему будет отправлен соответствующий ответ.
Заключение
Это краткое введение в веб-токены JSON или JWT и способы их использования в приложениях на основе PHP. С этого момента вы можете попробовать реализовать JWT в своем следующем API, возможно, попробовав некоторые другие алгоритмы подписи, которые используют асимметричные ключи, такие как RS256, или интегрируя его в существующий сервер аутентификации OAUTH2 в качестве ключа API.
Как правильно добавить токен CSRF с помощью PHP
Я пытаюсь добавить некоторую безопасность в формы на моем сайте. Одна из форм использует AJAX, а другая-это простая форма «свяжитесь с нами». Я пытаюсь добавить токен CSRF. Проблема, с которой я сталкиваюсь, заключается в том, что токен появляется только в HTML «value» некоторое время. В остальное время значение пусто. Вот код, который я использую в форме AJAX:
3 ответов:
Предупреждение: md5(uniqid(rand(), TRUE)) не является безопасным способом для генерации случайных чисел. Смотрите ответ для получения дополнительной информации и решение, которое использует криптографически безопасный генератор случайных чисел.
Похоже, вам нужно еще с вашим if.
создание токена CSRF
PHP 7
Примечание: один из мой работодатель проекты с открытым исходным кодом это инициатива по backport random_bytes() и random_int() в PHP 5 проектов. Это MIT лицензировано и доступно на Github и Composer как paragonie / random_compat.
PHP 5.3+ (или с ext-mcrypt)
проверка токена CSRF
не просто использовать == или даже === используйте hash_equals() (PHP 5.6+ только, но доступны для более ранних версий с hash-compat библиотека.)
Идем дальше с каждой формой токенов
во-первых, создайте второй токен для использования в качестве ключа HMAC, а затем используйте логику, подобную этой представьте его:
а затем с помощью конгруэнтной операции при проверке маркера:
Бонус: Гибридный Подход + Интеграция Веточек
всем, кто использует Twig templating engine может воспользуйтесь упрощенной двойной стратегией, добавив этот фильтр в свою среду веточек:
С помощью этой функции веточки вы можете использовать как токены общего назначения, так и:
или заблокированный вариант:
Twig связан только с визуализацией шаблона; вы все равно должны правильно проверить маркеры. На мой взгляд, стратегия Twig предлагает большую гибкость и простоту, сохраняя при этом возможность для максимального безопасность.
одноразовые токены CSRF
если у вас есть требование безопасности, чтобы каждый токен CSRF можно было использовать ровно один раз, самая простая стратегия регенерирует его после каждой успешной проверки. Однако это приведет к недействительности каждого предыдущего токена, который не очень хорошо сочетается с людьми, которые просматривают сразу несколько вкладок.
Paragon Initiative Enterprises поддерживает библиотека анти-CSRF для этих случаев углу. Оно работает исключительно с одноразовыми токенами для каждой формы. Когда в данных сеанса будет сохранено достаточное количество токенов (конфигурация по умолчанию: 65535), сначала будут задействованы самые старые неиспользованные токены.
PHP авторизация с JWT (JSON Web Tokens)
Против сессий
Было время, когда единственный способ аутентифицировать себя в приложении — выдавать учетные данные. Позже появились сервисные API, и отправка учетных данных в виде простого текста была недопустимой. Идея API-токенов возникла и в настоящее время является обычной практикой.
Некоторые из недостатков выдачи учетных данных приложению и поддержания состояния пользователя по отношению к приложению с использованием сеансовых файлов cookie:
Данные хранятся в виде простого текста на сервере
Даже если данные обычно не хранятся в общей папке, любой, у кого есть доступ, может прочитать содержимое файлов сеанса.
Файловая система запросов на чтение / запись
Каждый раз, когда начинается сеанс или изменяются его данные, серверу необходимо обновить файл сеанса. То же самое касается каждого раза, когда приложение отправляет куки-файл сессии. Если у вас будет значительное количество пользователей, у вас будет медленный сервер, если вы не используете альтернативные хранилища сеансов.
JSON Web Signature — это криптографический механизм, разработанный для защиты данных с помощью цифровой подписи, уникальной для содержимого токена, таким образом, что мы можем определить, были ли данные токена подделаны или нет.
Использование JWT имеет много преимуществ перед одним ключом API:
На что это похоже?
JWT будет выглядеть следующим образом:
Может показаться, что строка представляет собой просто случайные символы, соединенные вместе, и не сильно отличается от ключа API. Однако, если вы посмотрите внимательно, на самом деле есть 3 строки, разделенные точечным символом.
Первая и вторая строки — строки JSON в кодировке Base64 URL, поэтому, если мы их декодируем, мы получим следующие результаты:
Первая строка — это заголовок JWS, в котором указывается, какой криптографический алгоритм использовался для генерации подписи и типа полезной нагрузки. Вторая строка является полезной нагрузкой и передает некоторые стандартные поля, любые данные, которые вы хотите отправить в токене. Третья строка является криптографической подписью и будет декодироваться в двоичные данные.
Что интересно в сигнатуре, так это то, что криптографическому алгоритму требуется секретный ключ, строка, которую должен знать только приложение-эмитент и никогда не должен раскрываться. Таким образом, когда приложение получает токен, оно может сверять подпись с содержимым токена, используя указанный секретный ключ. Если проверка подписи не удалась, мы можем точно знать, что данные внутри токена были подделаны и должны быть отброшены.
Вы можете взглянуть на jwt.io, где вы можете поиграть с кодированием и декодированием JWT.
Поиграем
Как только мы войдем в систему, мы сможем извлечь защищенный ресурс из приложения.
Есть еще одна PHP-библиотека, jose from namshi, если вы захотите поиграть с ней позже.
Теперь давайте предположим, что форма входа в систему передает данные в нашу службу JWT-эмитента через AJAX, где учетные данные проверяются по базе данных, и после определения того, что учетные данные действительны, мы должны создать наш токен. Давайте сначала создадим его как массив:
Обратите внимание, что вы можете определить структуру данных так, как хотите, однако есть некоторые зарезервированные утверждения, такие как те, что использовались выше:
Преобразовать этот массив в JWT очень просто:
JWT::encode() позаботится обо всем (преобразование массива в JSON, создание заголовков, подписание полезной нагрузки и кодирование окончательной строки). Вы захотите сделать свой секретный ключ длинной двоичной строкой, закодировать его в файле конфигурации и никогда не раскрывать его. Иметь его прямо в коде — плохая идея.
Теперь, когда у клиента есть токен, вы можете сохранить его с помощью JS или любого другого механизма, который вам нравится. Вот пример использования jQuery:
Теперь давайте восстановим ресурс, который защищен нашим механизмом JWT.
При нажатии на кнопку «Получить ресурс >>», если все в порядке, вы должны увидеть изображение в серой области. Давайте используем ajax-вызов для отправки запроса в службу ресурсов:
Теперь мы можем увидеть, что такое защищенный ресурс:
Вот как мы проверяем токен в службе ресурсов.
Я использую Zend\Http\PhpEnvironment\Request чтобы немного упростить работу с извлечением типов HTTP-запросов и заголовков:
Теперь давайте выясним, есть ли в заголовке авторизации строка JWT:
Если вы не хотите иметь дело с заголовками HTTP-авторизации, вы можете выбрать одну из альтернатив: включить токен в запрос в качестве параметра URL:
Давайте попробуем декодировать JWT сейчас. Помните секретный ключ, который мы использовали ранее для создания токена? Это жизненно важная часть процесса декодирования здесь:
Если процесс декодирования JWT завершится неудачно, это может быть так:
Как вы можете видеть, JWT имеет хороший набор элементов управления, которые будут помечать его как недействительный, без необходимости вручную отзывать его или сверять со списком допустимых токенов.
На данный момент мы можем быть уверены, что JWT является действительным. Кроме того, вы можете проверить, является ли пользователь в токене по-прежнему действительным, если вы являетесь iss токена (из утверждения iss ), или в вашем токене есть встроенные флаги разрешений, а затем проверить их на соответствие действиям, которые запрашивает пользователь. выполнять.
Если вы хотите поиграть с примером приложения, вы можете проверить репо моего проекта для этой статьи, следовать инструкциям README и более внимательно посмотреть код.
Вывод
С этого момента вы можете попытаться реализовать JWT в своем следующем API, возможно, попробовав некоторые другие алгоритмы подписи, которые используют асимметричные ключи, такие как RS256 или интегрировать его в существующий сервер аутентификации OAUTH2 в качестве ключа API. Все ваши конструктивные отзывы приветствуются, а также любые вопросы или комментарии.
Как правильно добавить токен CSRF с помощью PHP
Я пытаюсь добавить некоторую безопасность в формы на моем веб-сайте. Одна из форм использует AJAX, а другая – простая форма «связаться с нами». Я пытаюсь добавить токен CSRF. Проблема, с которой я сталкиваюсь, заключается в том, что токен только отображается в HTML-значении некоторое время. В остальное время значение пусто. Вот код, который я использую в форме AJAX:
Похоже, вам нужно другое с вашим if.
Создание токена CSRF
PHP 7
PHP 5.3+ (или с ext-mcrypt)
Проверка токена CSRF
Дальнейшая работа с токенами для каждой формы
Во-первых, сгенерируйте второй токен для использования в качестве ключа HMAC, затем используйте для этого такую логику:
И затем используя конгруэнтную операцию при проверке токена:
Бонус: гибридный подход + интеграция Twig
Любой, кто использует движок шаблонов Twig, может воспользоваться упрощенной двойной стратегией, добавив этот фильтр в среду Twig:
С помощью этой функции Twig вы можете использовать оба токена общего назначения:
Или заблокированный вариант:
Twig занимается только обработкой шаблона; вы все равно должны правильно проверить токены. На мой взгляд, стратегия Twig предлагает большую гибкость и простоту, сохраняя при этом максимальную безопасность.
Одноразовые токены CSRF
Если у вас есть требование безопасности, чтобы каждый токен CSRF был разрешен к использованию ровно один раз, простейшая стратегия регенерирует его после каждой успешной проверки. Однако это приведет к недействительности каждого предыдущего токена, который не будет хорошо сочетаться с людьми, которые просматривают сразу несколько вкладок.
Paragon Initiative Enterprises поддерживает библиотеку Anti-CSRF для этих угловых случаев. Он работает только с одноразовыми токенами для каждой формы. Когда в данных сеанса хранятся достаточное количество токенов (конфигурация по умолчанию: 65535), сначала будут выбивать самые старые неиспользуемые маркеры.