Хорошо, позвольте мне прямо заявить: если вы помещаете пользовательские данные или что-либо, полученное из пользовательских данных, в файл cookie для этой цели, вы делаете что-то не так.
Там. Я сказал это. Теперь мы можем перейти к фактическому ответу.
Вы спрашиваете, что не так с хешированием пользовательских данных? Ну, это сводится к поверхности воздействия и безопасности через неизвестность.
Представьте на секунду, что вы нападающий. Вы видите криптографическое печенье, установленное для запоминания на вашем сеансе. Это 32 символа в ширину. Gee. Это может быть MD5 ...
Давайте на секунду представим, что они знают алгоритм, который вы использовали. Например:
md5(salt+username+ip+salt)
Теперь все, что нужно атакующему, это грубая сила «соли» (которая на самом деле не соль, а об этом позже), и теперь он может генерировать все фальшивые токены, которые ему нужны, с любым именем пользователя для своего IP-адреса! Но грубая соль - это трудно, верно? Абсолютно. Но современные графические процессоры чрезвычайно хороши в этом. И если вы не используете в нем достаточную случайность (сделайте его достаточно большим), он быстро упадет, а вместе с ним и ключи от вашего замка.
Короче говоря, единственное, что защищает вас, это соль, которая на самом деле не защищает вас так сильно, как вы думаете.
Но ждать!
Все это было основано на том, что злоумышленник знает алгоритм! Если это секретно и сбивает с толку, то вы в безопасности, верно? НЕПРАВИЛЬНО . У этой линии мышления есть название: Безопасность через неизвестность , на которую НИКОГДА не следует полагаться.
Лучший путь
Лучший способ - никогда не пускать информацию пользователя с сервера, кроме идентификатора.
Когда пользователь входит в систему, генерирует большой (от 128 до 256 бит) случайный токен. Добавьте это в таблицу базы данных, которая сопоставляет токен с идентификатором пользователя, а затем отправьте его клиенту в файле cookie.
Что если злоумышленник угадает случайный токен другого пользователя?
Хорошо, давайте сделаем немного математики здесь. Мы генерируем 128-битный случайный токен. Это означает, что есть:
possibilities = 2^128
possibilities = 3.4 * 10^38
Теперь, чтобы показать, насколько абсурдно велико это число, давайте представим, что каждый сервер в Интернете (скажем, 50 000 000 сегодня) пытается перебить это число со скоростью 1 000 000 000 в секунду каждый. В действительности ваши серверы будут таять под такой нагрузкой, но давайте поиграем с этим.
guesses_per_second = servers * guesses
guesses_per_second = 50,000,000 * 1,000,000,000
guesses_per_second = 50,000,000,000,000,000
Итак, 50 квадриллионов догадок в секунду. Это быстро! Правильно?
time_to_guess = possibilities / guesses_per_second
time_to_guess = 3.4e38 / 50,000,000,000,000,000
time_to_guess = 6,800,000,000,000,000,000,000
Итак, 6,8 секстиллионных секунд ...
Давайте попробуем свести это к более дружелюбным числам.
215,626,585,489,599 years
Или даже лучше:
47917 times the age of the universe
Да, это 47917 раз возраст вселенной ...
По сути, он не будет взломан.
Итак, подведем итог:
Лучший подход, который я рекомендую, - хранить куки-файл из трех частей.
function onLogin($user) {
$token = GenerateRandomToken(); // generate a token, should be 128 - 256 bit
storeTokenForUser($user, $token);
$cookie = $user . ':' . $token;
$mac = hash_hmac('sha256', $cookie, SECRET_KEY);
$cookie .= ':' . $mac;
setcookie('rememberme', $cookie);
}
Затем, чтобы проверить:
function rememberMe() {
$cookie = isset($_COOKIE['rememberme']) ? $_COOKIE['rememberme'] : '';
if ($cookie) {
list ($user, $token, $mac) = explode(':', $cookie);
if (!hash_equals(hash_hmac('sha256', $user . ':' . $token, SECRET_KEY), $mac)) {
return false;
}
$usertoken = fetchTokenByUserName($user);
if (hash_equals($usertoken, $token)) {
logUserIn($user);
}
}
}
Примечание. Не используйте токен или комбинацию пользователя и токена для поиска записи в вашей базе данных. Обязательно извлекайте запись, основанную на пользователе, и используйте безопасную по времени функцию сравнения для последующего сравнения извлеченного токена. Подробнее о сроках атаки .
Теперь очень важно, чтобы это SECRET_KEY
был криптографический секрет (генерируемый чем-то вроде /dev/urandom
и / или получаемый из входных данных с высокой энтропией). Кроме того, GenerateRandomToken()
должен быть сильный случайный источник ( mt_rand()
не достаточно сильный. Используйте библиотеку, такую как RandomLib или random_compat , или mcrypt_create_iv()
с DEV_URANDOM
) ...
Это hash_equals()
для предотвращения времени атаки . Если вы используете версию PHP ниже PHP 5.6, функция hash_equals()
не поддерживается. В этом случае вы можете заменить hash_equals()
его функцией хронометража:
/**
* A timing safe equals comparison
*
* To prevent leaking length information, it is important
* that user input is always used as the second parameter.
*
* @param string $safe The internal (safe) value to be checked
* @param string $user The user submitted (unsafe) value
*
* @return boolean True if the two strings are identical.
*/
function timingSafeCompare($safe, $user) {
if (function_exists('hash_equals')) {
return hash_equals($safe, $user); // PHP 5.6
}
// Prevent issues if string length is 0
$safe .= chr(0);
$user .= chr(0);
// mbstring.func_overload can make strlen() return invalid numbers
// when operating on raw binary strings; force an 8bit charset here:
if (function_exists('mb_strlen')) {
$safeLen = mb_strlen($safe, '8bit');
$userLen = mb_strlen($user, '8bit');
} else {
$safeLen = strlen($safe);
$userLen = strlen($user);
}
// Set the result to the difference between the lengths
$result = $safeLen - $userLen;
// Note that we ALWAYS iterate over the user-supplied length
// This is to prevent leaking length information
for ($i = 0; $i < $userLen; $i++) {
// Using % here is a trick to prevent notices
// It's safe, since if the lengths are different
// $result is already non-0
$result |= (ord($safe[$i % $safeLen]) ^ ord($user[$i]));
}
// They are only identical strings if $result is exactly 0...
return $result === 0;
}
Обычно я делаю что-то вроде этого:
Конечно, вы можете использовать разные имена файлов cookie и т. Д. Также вы можете немного изменить содержимое файла cookie, просто убедитесь, что его нелегко создать. Вы также можете, например, создать user_salt при создании пользователя и добавить его в файл cookie.
Также вы можете использовать sha1 вместо md5 (или почти любой алгоритм)
источник
Введение
Ваш заголовок «Keep Me Logged In» - лучший подход, из-за которого мне трудно понять, с чего начать, потому что, если вы ищете наилучший подход, вам придется учитывать следующее:
Печенье
Файлы cookie являются уязвимыми. Между общими уязвимостями кражи файлов cookie браузера и атаками с использованием межсайтовых сценариев мы должны признать, что файлы cookie не являются безопасными. Чтобы улучшить безопасность, вы должны отметить, что
php
setcookies
имеет дополнительные функции, такие какОпределения
Простой подход
Простое решение будет:
В приведенном выше примере приведены все примеры, приведенные на этой странице, но их недостатки заключаются в том, что
Лучшее решение
Лучшее решение было бы
Пример кода
Используемый класс
Тестирование в Firefox & Chrome
преимущество
Недостаток
Быстрая починка
Подход с использованием нескольких файлов cookie
Когда злоумышленник собирается украсть куки, он фокусируется только на определенном веб-сайте или домене, например. example.com
Но на самом деле вы можете аутентифицировать пользователя из 2 разных доменов ( example.com и fakeaddsite.com ) и сделать его похожим на «Рекламное печенье»
Некоторые люди могут спросить, как вы можете использовать 2 разных куки? Ну, это возможно, представьте себе
example.com = localhost
иfakeaddsite.com = 192.168.1.120
. Если вы проверяете куки, это будет выглядеть такС картинки выше
192.168.1.120
HTTP_REFERER
REMOTE_ADDR
преимущество
Недостаток
улучшение
ajax
источник
Я задал один угол этого вопроса здесь , и ответы будут вести вас ко всему токен на основе тайм-ауте печенье ссылки вам нужно.
По сути, вы не сохраняете userId в куки. Вы храните одноразовый токен (огромную строку), который пользователь использует для получения своего старого сеанса входа в систему. Затем, чтобы сделать его действительно безопасным, вы запрашиваете пароль для тяжелых операций (например, изменение самого пароля).
источник
Старый поток, но все еще действительная проблема. Я заметил несколько хороших отзывов о безопасности и об отказе от использования «безопасности через неизвестность», но настоящие технические методы были недостаточны в моих глазах. Вещи, которые я должен сказать, прежде чем внести свой метод:
Тем не менее, есть два отличных способа автоматического входа в систему.
Во-первых, дешевый, легкий способ, который ставит все это на кого-то другого. Если вы поддерживаете вход на свой сайт, например, с помощью своего аккаунта google +, возможно, у вас есть упрощенная кнопка google +, которая будет входить в систему, если пользователи уже вошли в google (я сделал это здесь, чтобы ответить на этот вопрос, как и всегда вошел в гугл). Если вы хотите, чтобы пользователь автоматически входил в систему, если он уже вошел с помощью доверенного и поддерживаемого средства проверки подлинности, и поставил флажок, чтобы сделать это, пусть ваши клиентские скрипты перед загрузкой выполняют код, соответствующий соответствующей кнопке «Вход в систему». просто убедитесь, что сервер хранит уникальный идентификатор в таблице автоматического входа, который содержит имя пользователя, идентификатор сеанса и аутентификатор, используемый для пользователя. Поскольку эти методы входа используют AJAX, вы все равно ждете ответа, и этот ответ является либо подтвержденным ответом, либо отклонением. Если вы получили проверенный ответ, используйте его как обычно, затем продолжите загрузку зарегистрированного пользователя как обычно. В противном случае вход в систему не удастся, но не говорите пользователю, просто продолжайте, не входя в систему, они заметят. Это сделано для того, чтобы злоумышленник, который украл куки (или подделал их в попытке повысить привилегии), не узнал, что пользователь автоматически выполняет вход на сайт.
Это дешево, и некоторые также могут посчитать его грязным, потому что оно пытается проверить вашу потенциально уже зарегистрированную личность в таких местах, как Google и Facebook, даже не сказав вам об этом. Однако его не следует использовать для пользователей, которые не запрашивали автоматическую регистрацию на вашем сайте, и этот конкретный метод предназначен только для внешней аутентификации, как в Google+ или FB.
Поскольку внешний аутентификатор использовался для скрытого информирования сервера о том, прошел ли пользователь проверку, злоумышленник не может получить ничего, кроме уникального идентификатора, который сам по себе бесполезен. Я уточню:
Независимо от того, что, даже если злоумышленник использует идентификатор, который не существует, попытка должна завершиться неудачей на всех попытках, кроме тех случаев, когда получен проверенный ответ.
Этот метод может и должен использоваться вместе с вашим внутренним аутентификатором для тех, кто входит на ваш сайт с помощью внешнего аутентификатора.
=========
Теперь, для вашей собственной системы аутентификации, которая может автоматически подписывать пользователей, вот как я это делаю:
БД имеет несколько таблиц:
Обратите внимание, что имя пользователя может быть длиной 255 символов. Моя серверная программа ограничивает имена пользователей в моей системе 32 символами, но внешние аутентификаторы могут иметь имена пользователей с их @ domain.tld больше этого значения, поэтому я просто поддерживаю максимальную длину адреса электронной почты для максимальной совместимости.
Обратите внимание, что в этой таблице нет поля пользователя, поскольку имя пользователя при входе в систему находится в данных сеанса, и программа не допускает нулевые данные. Идентификатор session_id и session_token могут быть сгенерированы с использованием случайных хэшей md5, хэшей sha1 / 128/256, меток даты и времени со случайными строками, добавленными к ним, затем хэшированными или как вам угодно, но энтропия вашего вывода должна оставаться настолько высокой, насколько допустимо для предотвращать атаки методом "грубой силы", даже отрываясь от земли, и все хеши, сгенерированные вашим классом сеансов, должны быть проверены на совпадения в таблице сеансов, прежде чем пытаться их добавить.
MAC-адреса по своей природе должны быть УНИКАЛЬНЫМИ, поэтому имеет смысл, что каждая запись имеет уникальное значение. Имена хостов, с другой стороны, могут быть законно дублированы в отдельных сетях. Сколько людей используют «Домашний ПК» в качестве одного из имен своих компьютеров? Имя пользователя берется из данных сеанса серверным бэкэндом, поэтому манипулирование им невозможно. Что касается токена, тот же метод генерации токенов сеанса для страниц должен использоваться для генерации токенов в файлах cookie для автоматической регистрации пользователя. Наконец, добавляется код даты и времени, когда пользователю необходимо будет подтвердить свои учетные данные. Либо обновите эту дату-время при входе пользователя в систему, сохраняя его в течение нескольких дней, либо вынудите его истечь, независимо от того, какой последний вход сохранил его, в течение месяца или около того, в зависимости от того, что диктует ваш дизайн.
Это препятствует тому, чтобы кто-то систематически подделывал MAC и имя хоста для пользователя, которого он знает, выполняет автоматический вход. НИКОГДАпопросите пользователя сохранить cookie со своим паролем, открытым текстом или другим способом. Регенерируйте токен на каждой странице навигации так же, как токен сеанса. Это значительно снижает вероятность того, что злоумышленник сможет получить действительный токен-cookie и использовать его для входа в систему. Некоторые люди пытаются сказать, что злоумышленник может украсть файлы cookie у жертвы и выполнить атаку воспроизведения сеанса для входа в систему. Если бы злоумышленник мог украсть куки (что возможно), он, несомненно, скомпрометировал бы все устройство, то есть он мог бы просто использовать устройство для входа в систему в любом случае, что полностью противоречит цели кражи куки. Пока ваш сайт работает по протоколу HTTPS (что должно происходить при работе с паролями, номерами CC или другими системами входа в систему), вы предоставляете пользователю всю защиту, которую вы можете использовать в браузере.
Следует помнить одну вещь: данные сеанса не должны истекать, если вы используете автоподпись. Вы можете прервать возможность ложного продолжения сеанса, но проверка в системе должна возобновить данные сеанса, если это постоянные данные, которые, как ожидается, будут продолжаться между сеансами. Если вам нужны как постоянные, так и непостоянные данные сеанса, используйте другую таблицу для постоянных данных сеанса с именем пользователя в качестве PK и попросите сервер извлечь их, как если бы это были обычные данные сеанса, просто используйте другую переменную.
После того, как логин получен таким способом, сервер все равно должен проверить сеанс. Здесь вы можете кодировать ожидания для украденных или скомпрометированных систем; паттерны и другие ожидаемые результаты входа в сеансовые данные часто могут привести к выводам о том, что система была взломана или файлы cookie были подделаны для получения доступа. Именно здесь ваш специалист по ISS может установить правила, которые будут инициировать блокировку учетной записи или автоматическое удаление пользователя из системы автоматического входа, не позволяя злоумышленникам оставаться на достаточно долгое время, чтобы пользователь мог определить, как злоумышленник добился успеха и как его отключить.
В качестве заключительного примечания убедитесь, что любая попытка восстановления, изменения пароля или ошибки входа в систему после превышения порогового значения приводят к отключению автоматической регистрации до тех пор, пока пользователь не подтвердит правильность и не подтвердит, что это произошло.
Я прошу прощения, если кто-то ожидал, что код будет выдан в моем ответе, этого не произойдет Я скажу, что я использую PHP, jQuery и AJAX для запуска своих сайтов, и я НИКОГДА не использую Windows как сервер ... никогда.
источник
Я бы порекомендовал подход, упомянутый Стефаном (т. Е. Следуйте рекомендациям в разделе «Советы и рекомендации по использованию файлов cookie для улучшенного постоянного входа в систему» ), а также рекомендую убедиться, что ваши файлы cookie являются файлами cookie HttpOnly, поэтому они недоступны для потенциально вредоносного JavaScript.
источник
Создайте хеш, возможно, с секретом, который вам известен, а затем сохраните его в своей БД, чтобы он мог быть связан с пользователем. Должно работать хорошо.
источник
Мое решение таково. Это не на 100% пуленепробиваемый, но я думаю, что это спасет вас в большинстве случаев.
Когда пользователь успешно вошел в систему, создайте строку с этой информацией:
Зашифровать
$data
, установить тип для HttpOnly и установить cookie.Когда пользователь вернется на ваш сайт, выполните следующие действия:
:
характером.Если пользователь выходит из системы, удалите этот файл cookie. Создайте новый файл cookie, если пользователь повторно войдет в систему.
источник
Я не понимаю концепции хранения зашифрованных файлов в cookie-файлах, когда вам нужна взломанная версия. Если я что-то упустил, пожалуйста, прокомментируйте.
Я думаю о том, чтобы применить этот подход к «Помни меня». Если вы видите какие-либо проблемы, пожалуйста, прокомментируйте.
Создайте таблицу для хранения данных «Запомнить меня» - отдельно от пользовательской таблицы, чтобы я мог войти с нескольких устройств.
При успешном входе в систему (с пометкой «Запомнить меня»):
a) Сгенерируйте уникальную случайную строку, которая будет использоваться в качестве UserID на этом компьютере: bigUserID
б) генерировать уникальную случайную строку: bigKey
c) Хранить куки: bigUserID: bigKey
г) В таблицу «Запомнить меня» добавьте запись с: UserID, IP Address, bigUserID, bigKey
Если вы пытаетесь получить доступ к тому, что требует входа в систему:
а) Проверьте наличие cookie и найдите bigUserID & bigKey с соответствующим IP-адресом
б) Если вы найдете его, войдите в систему, но установите флажок в пользовательской таблице «soft login», чтобы при любых опасных операциях вы могли запрашивать полный вход в систему.
При выходе отметьте все записи «Запомнить меня» для этого пользователя как просроченные.
Единственные уязвимости, которые я вижу, это;
источник
Я прочитал все ответы и все еще находил трудным извлечь то, что я должен был сделать. Если картинка стоит 1 тыс. Слов, я надеюсь, что это поможет другим внедрить безопасное постоянное хранилище на основе передового опыта использования файлов cookie для улучшенного постоянного входа Барри Джаспана.
Если у вас есть вопросы, отзывы или предложения, я постараюсь обновить диаграмму, чтобы учесть новичка, пытающегося внедрить безопасный постоянный вход в систему.
источник
Реализация функции «Keep Me Logged In» означает, что вам необходимо точно определить, что это будет означать для пользователя. В простейшем случае я бы использовал это, чтобы означать, что время сеанса намного больше: 2 дня (скажем) вместо 2 часов. Для этого вам понадобится ваше собственное хранилище сеансов, возможно, в базе данных, поэтому вы можете установить время истечения срока действия для данных сеанса. Затем вам нужно убедиться, что вы установили cookie-файл, который будет храниться в течение нескольких дней (или дольше), а не истекает при закрытии браузера.
Я слышу, как вы спрашиваете: «Почему 2 дня? Почему не 2 недели?». Это потому, что использование сессии в PHP автоматически отодвигает срок действия обратно. Это связано с тем, что истечение срока сеанса в PHP на самом деле является временем простоя.
Теперь, сказав это, я бы, вероятно, реализовал более жесткое значение тайм-аута, которое я храню в самом сеансе и примерно через 2 недели, и добавил бы код, чтобы увидеть это и принудительно аннулировать сеанс. Или, по крайней мере, выйти из них. Это будет означать, что пользователю будет предложено периодически входить в систему. Yahoo! Является ли это.
источник
Я думаю, вы могли бы просто сделать это:
хранить
$cookiestring
в БД и установите его как cookie. Также установите имя пользователя человека в виде куки. Весь смысл хэша в том, что его нельзя перепроектировать.Когда появляется пользователь, получите имя пользователя из одного файла cookie, а не
$cookieString
из другого. Если$cookieString
совпадает с тем, что хранится в БД, то пользователь проходит аутентификацию. Так как password_hash каждый раз использует различную соль, не имеет значения, что такое открытый текст.источник