Кодирование файлов cookie, чтобы их нельзя было подделать, прочитать и т. Д. - PullRequest
18 голосов
/ 16 февраля 2011

Я пишу PHP-приложение.Я хочу сохранить информацию о входе пользователя в cookie-файлы, чтобы пользователю не приходилось входить в систему при каждом посещении.

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

Обновление:

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

Ответы [ 5 ]

52 голосов
/ 16 февраля 2011

Краткий ответ

Не делай этого.Вы пожалеете об этом в долгосрочной перспективе.Конечно, вы можете зашифровать его, но что произойдет, когда кто-то выяснит ваш ключ шифрования.Теперь вы просто передали им учетные данные всех пользователей на табличке (ну, не совсем, но достаточно близко).

Лучший способ сделать это

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

$randomToken = hash('sha256',uniq_id(mt_rand(), true).uniq_id(mt_rand(), true));

Затем сохраните его в базе данных рядом с пользователем и отправьте cookie клиенту (я бы также предложил подписать токен, чтобы предотвратить подделку:

$randomToken .= ':'.hash_hmac('md5', $randomToken, $serverKey);

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

list($token, $hmac) = explode(':', $_COOKIE['remember_me'], 2);
if ($hmac != hash_hmac('md5', $token, $serverKey)) {
    die('tampered token!');
}

Оттуда, просто найдите пользователя по токену. Если вы найдете его, войдите в систему этого пользователя.

Я бы также предложил менять маркер при каждой смене пароля.

Чтобы ответить на ваш вопрос напрямую

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

Чтобы закодировать его, я бы использовал mcrypt для шифрования данных в cookie. Затем я бы сделал случайную соль и сохранил еес строкой пользователя, а затем подписать зашифрованные данные с hash_hmac используя эту уникальную соль.Таким образом, если кто-то перехватит файл cookie и определит ключ для шифрования, вы все равно сможете обнаружить недопустимый hmac и найти тамперы.

function generateCredentialsCookie($user_id, $password) {
    $encrypted = encrypt($user_id.':'.$password, $secretkey);
    $salt = uniq_id(mt_rand(), true);
    $encrypted .= ':'.hash_hmac('sha256', $encrypted, $salt);
    storeSaltForUser($user_id, $salt);
    set_cookie('credentials', $encrypted);
}

function readCredentialsCookie() {
    $parts = explode(':', $_COOKIE['credentials']);
    $salt = array_pop($parts);
    $encrypted = implode(':', $parts); //needed incase mcrypt added `:`
    $raw = decrypt($encrypted, $secretkey);
    list ($user_id, $password) = explode(':', $raw, 2);
    if ($salt == getSaltForUser($user_id)) 
        return array($user_id, $password);
    } else {
        return die('Invalid Cookie Found');
    }
}

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

НЕ используйте длительные сеансы!

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

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

  • DOS (отказ в обслуживании созданы уязвимости

    • Дисковое пространство - каждый сеанс использует достаточно небольшой объем дискового пространства. Но если у вас длительный сеанс, каждый новый сеанс только добавляет к предыдущему общему количеству. То же самое с длительными сеансамикому-то просто нужно снова и снова посещать ваш сайт с новым идентификатором сеанса, и вдруг у вас не хватает места на диске (при условии нормального диска).

    • Место в папке- Каждый сеанс занимает один файл в одной папке. Большинство популярных файловых систем будет замедляться с большим количеством файлов в одной папке. Поэтому, если вы поместите 1 миллион файлов сеансов, чтение или запись в файл сеанса будет медленным (очень медленным)И сборка мусора (которая очищает старые файлы) будет ОЧЕНЬ ОЧЕНЬ ОЧЕНЬ ОЧЕНЬ медленной (если она вообще будет работать).

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

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

4 голосов
/ 16 февраля 2011

Хранение пользовательских данных в cookie - неправильный способ. Вы должны использовать PHP Sessions . Единственная вещь, которая будет храниться на клиенте, будет идентификатором сеанса в простом cookie (который PHP будет обрабатывать для вас автоматически). Это уже зашифрованная строка.

PHP будет отслеживать пользовательские данные на стороне сервера.

Это обеспечит желаемый эффект, который вы описали, при этом оставаясь более безопасным, чем использование файлов cookie.

2 голосов
/ 16 февраля 2011

Абсолютно ни при каких обстоятельствах не следует хранить учетные данные пользователя в cookie-файле.Вы должны всегда предполагать, что куки, как и все пользовательские данные, нельзя доверять.

Пара методов:

Если пользователь выбирает «запомнить меня», то просто установитеперед инициализацией сеанса.

session_set_cookie_params(60 * 60 * 24 * 7); //save cookie session for 7 days

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

Я бы порекомендовал первый вариант.

0 голосов
/ 24 сентября 2017

Проще создать 16 или более криптографически безопасное случайное число и сохранить его в файле cookie.Нет необходимости в шифровании / расшифровке.Используйте его с ограниченным временем действия, проверенным на стороне сервера (не полагайтесь на MaxAge или Expires).Это сессионный cookie.

Это очень безопасно, так как никакая критическая информация не покидает сервер.

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

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

Недостатком этого метода является то, что если кто-то узнает ключ, он может подделать файлы cookie.Затем он может создавать файлы cookie с разными идентификаторами пользователей и получать доступ к своей учетной записи.Поэтому используйте этот метод там, где риск ограничен, а доступ к ключу хорошо контролируется.Решением может быть выделенное аппаратное устройство, выполняющее шифрование / дешифрование и скрывающее ключ.Но это в настоящее время необычно и дорого.Его задержка может быть больше, чем поиск случайного идентификатора сеанса в кэше.Последнее является более простым и безопасным решением.

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

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

0 голосов
/ 16 февраля 2011

Солёное печенье перед сохранением. Добавьте user-agent, ip, если хотите расширить безопасность.

$cookie_to_save = sha1($pwd . $user_agent . $yourSalt);

при аутологине

if($cookie_saved == sha1($pwd . $user_agent . $yourSalt) ok...
...