"Keep Me Logged In" - лучший подход

Мое веб-приложение использует сеансы для хранения информации о пользователе после входа в систему и для поддержания этой информации при перемещении со страницы на страницу в приложении. В этом конкретном приложении я сохраняю user_id, first_name и last_name человека.

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

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

Ответ 1

Уведомление о безопасности. Основываясь на cookie с хешем MD5 детерминированных данных, это плохая идея; лучше использовать случайный токен, полученный из CSPRNG. См. ответ ircmaxell на этот вопрос для более безопасного подхода.

Обычно я делаю что-то вроде этого:

  • Пользователь входит в систему с 'keep me logged in'
  • Создать сеанс
  • Создайте файл cookie под названием SOMETHING, содержащий: md5 (соль + имя пользователя + ip + соль) и файл cookie, называемый somethingElse, содержащий id
  • Сохранить файл cookie в базе данных
  • Пользователь делает вещи и оставляет ----
  • Пользователь возвращает, проверяет наличие somethingElse cookie, если он существует, получает старый хэш из базы данных для этого пользователя, проверяя соответствие содержимого cookie SOMETHING с хешем из базы данных, которое также должно совпадать с недавно вычисленным хэшем (для ip): cookieHash == databaseHash == md5 (соль + имя пользователя + ip + соль), если они это делают, goto 2, если они не имеют 1

Конечно, вы можете использовать разные имена файлов cookie и т.д. Также вы можете немного изменить содержимое файла cookie, просто убедитесь, что его не легко создать. Например, вы можете создать user_salt, когда пользователь будет создан, а также поместить его в файл cookie.

Также вы можете использовать sha1 вместо md5 (или почти любой алгоритм)

Ответ 2

Хорошо, позвольте мне прямо сказать: если вы помещаете данные пользователя или что-либо, полученное из пользовательских данных, в cookie для этой цели, вы делаете что-то неправильно.

Там. Я сказал это. Теперь мы можем перейти к фактическому ответу.

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

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

Давайте также предположим, что они знают алгоритм, который вы использовали. Например:

md5(salt+username+ip+salt)

Теперь все, что нужно злоумышленнику, это грубая сила "соли" (которая на самом деле не соль, но более подробно об этом позже), и теперь он может генерировать все поддельные токены, которые он хочет, с любым именем пользователя для своего Айпи адрес! Но грубая заставлять соль трудно, не так ли? Абсолютно. Но современные графические процессоры чрезвычайно хороши в этом. И если вы не используете в нем достаточную случайность (сделайте ее достаточно большой), она быстро упадет, а вместе с ней и ключи к вашему замку.

Короче говоря, единственное, что вас защищает, это соль, которая на самом деле не защищает вас так сильно, как вы думаете.

Но подождите!

Все это предполагалось, что злоумышленник знает алгоритм! Если это секретно и запутанно, тогда вы в безопасности, не так ли? НЕПРАВИЛЬНО. Эта линия мышления имеет имя: Security Through Obscurity, на которое следует полагаться НИКОГДА.

Лучший способ

Лучший способ - никогда не оставлять информацию о пользователе на сервере, кроме идентификатора.

Когда пользователь входит в систему, генерирует большой (от 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 раз больше возраста Вселенной...

В принципе, он не будет взломан.

Итак, подведем итог:

Лучшим подходом, который я рекомендую, является сохранение файла cookie с тремя частями.

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() функцией timingSafeCompare:

/**
 * 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 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;
}

Ответ 3

Введение

Ваше название "Keep Me Logged In" - лучший подход затрудняет мне знать, с чего начать, потому что, если вы смотрите на лучший подход, вам нужно будет рассмотреть следующее:

  • Определение
  • Безопасность

Cookies

Cookies уязвимы. Между общими уязвимостями cookie-кражи браузера и атаками межсайтового скриптинга мы должны признать, что файлы cookie небезопасны. Чтобы повысить безопасность, вы должны заметить, что php setcookies имеет дополнительные функции, такие как

bool setcookie (строка $name [, string $value [, int $expire = 0 [, string $path [, string $domain [, bool $secure= false [, bool $httponly= false]]]]]])

  • secure (с использованием HTTPS-соединения)
  • httponly (Сокращение кражи личных данных с помощью атаки XSS)

Определения

  • Токен (непредсказуемая случайная строка из n длины, например. /dev/urandom )
  • Ссылка (непредсказуемая случайная строка длиной n, например. /dev/urandom )
  • Подпись (сгенерируйте хеш-значение с ключом с использованием метода HMAC)

Простой подход

Простое решение:

  • Пользователь вошел в систему с помощью Запомнить меня
  • Входное Cookie, выпущенное с токеном и подписью
  • Когда возвращается, подпись отмечена
  • Если подпись одобрена, тогда имя пользователя и токен просматриваются в базе данных
  • if not valid.. вернуться на страницу входа
  • Если действительный автоматический вход в систему

В приведенном выше примере исследования суммируется весь пример, приведенный на этой странице, но они имеют недостатки в том, что

  • Невозможно узнать, были ли украдены файлы cookie.
  • Атакующим могут быть операции с доступом, такие как смена пароля или данные, такие как личная информация и информация об выпечке и т.д.
  • Скомпрометированный файл cookie будет по-прежнему действителен для продолжительности жизни файла cookie

Лучшее решение

Лучшим решением будет

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

Пример кода

// Set privateKey
// This should be saved securely 
$key = 'fc4d57ed55a78de1a7b31e711866ef5a2848442349f52cd470008f6d30d47282';
$key = pack("H*", $key); // They key is used in binary form

// Am Using Memecahe as Sample Database
$db = new Memcache();
$db->addserver("127.0.0.1");

try {
    // Start Remember Me
    $rememberMe = new RememberMe($key);
    $rememberMe->setDB($db); // set example database

    // Check if remember me is present
    if ($data = $rememberMe->auth()) {
        printf("Returning User %s\n", $data['user']);

        // Limit Acces Level
        // Disable Change of password and private information etc

    } else {
        // Sample user
        $user = "baba";

        // Do normal login
        $rememberMe->remember($user);
        printf("New Account %s\n", $user);
    }
} catch (Exception $e) {
    printf("#Error  %s\n", $e->getMessage());
}

Используемый класс

class RememberMe {
    private $key = null;
    private $db;

    function __construct($privatekey) {
        $this->key = $privatekey;
    }

    public function setDB($db) {
        $this->db = $db;
    }

    public function auth() {

        // Check if remeber me cookie is present
        if (! isset($_COOKIE["auto"]) || empty($_COOKIE["auto"])) {
            return false;
        }

        // Decode cookie value
        if (! $cookie = @json_decode($_COOKIE["auto"], true)) {
            return false;
        }

        // Check all parameters
        if (! (isset($cookie['user']) || isset($cookie['token']) || isset($cookie['signature']))) {
            return false;
        }

        $var = $cookie['user'] . $cookie['token'];

        // Check Signature
        if (! $this->verify($var, $cookie['signature'])) {
            throw new Exception("Cokies has been tampared with");
        }

        // Check Database
        $info = $this->db->get($cookie['user']);
        if (! $info) {
            return false; // User must have deleted accout
        }

        // Check User Data
        if (! $info = json_decode($info, true)) {
            throw new Exception("User Data corrupted");
        }

        // Verify Token
        if ($info['token'] !== $cookie['token']) {
            throw new Exception("System Hijacked or User use another browser");
        }

        /**
         * Important
         * To make sure the cookie is always change
         * reset the Token information
         */

        $this->remember($info['user']);
        return $info;
    }

    public function remember($user) {
        $cookie = [
                "user" => $user,
                "token" => $this->getRand(64),
                "signature" => null
        ];
        $cookie['signature'] = $this->hash($cookie['user'] . $cookie['token']);
        $encoded = json_encode($cookie);

        // Add User to database
        $this->db->set($user, $encoded);

        /**
         * Set Cookies
         * In production enviroment Use
         * setcookie("auto", $encoded, time() + $expiration, "/~root/",
         * "example.com", 1, 1);
         */
        setcookie("auto", $encoded); // Sample
    }

    public function verify($data, $hash) {
        $rand = substr($hash, 0, 4);
        return $this->hash($data, $rand) === $hash;
    }

    private function hash($value, $rand = null) {
        $rand = $rand === null ? $this->getRand(4) : $rand;
        return $rand . bin2hex(hash_hmac('sha256', $value . $rand, $this->key, true));
    }

    private function getRand($length) {
        switch (true) {
            case function_exists("mcrypt_create_iv") :
                $r = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
                break;
            case function_exists("openssl_random_pseudo_bytes") :
                $r = openssl_random_pseudo_bytes($length);
                break;
            case is_readable('/dev/urandom') : // deceze
                $r = file_get_contents('/dev/urandom', false, null, 0, $length);
                break;
            default :
                $i = 0;
                $r = "";
                while($i ++ < $length) {
                    $r .= chr(mt_rand(0, 255));
                }
                break;
        }
        return substr(bin2hex($r), 0, $length);
    }
}

Тестирование в Firefox и Chrome

enter image description here

Преимущество

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

Недостаток

  • Не поддерживает постоянное соединение через несколько браузеров (Mobile и Web).
  • Файл cookie все равно может быть украден, потому что пользователь получает уведомление только после следующего входа.

Быстрое исправление

  • Внедрение системы утверждения для каждой системы, которая должна иметь постоянное соединение.
  • Использовать несколько файлов cookie для аутентификации

Множественный подход к cookie

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

Но действительно вы можете аутентифицировать пользователя из двух разных доменов (example.com и fakeaddsite.com) и сделать его похожим на "Cookie для рекламы"

  • Пользователь выполнил вход в example.com, чтобы запомнить меня
  • Сохранить имя пользователя, токен, ссылку в файле cookie
  • Сохранять имя пользователя, токен, ссылку в базе данных, например. Memcache
  • Отправить refrence id через get и iframe на fakeaddsite.com
  • fakeaddsite.com использует ссылку для извлечения пользователя и токена из базы данных
  • fakeaddsite.com сохраняет подпись
  • Когда пользователь возвращает информацию подписи fetch с iframe с сайта fakeaddsite.com
  • Объединить данные и выполнить проверку
  • ..... вы знаете оставшиеся

Некоторые люди могут задаться вопросом, как вы можете использовать 2 разных файла cookie? Ну его возможно, представьте example.com = localhost и fakeaddsite.com = 192.168.1.120. Если вы проверите файлы cookie, это будет выглядеть как

enter image description here

Из изображения выше

  • Текущее посещение сайта - localhost
  • Он также содержит файлы cookie, установленные из 192.168.1.120.

192.168.1.120

  • Принимает только определенные HTTP_REFERER
  • Принимает только соединение из указанного REMOTE_ADDR
  • Нет JavaScript, нет содержимого, но состоит из ничего, кроме знака и добавления или извлечения из файла cookie.

Преимущество

  • 99% процентов времени, когда вы обманули атакующего
  • Вы можете легко заблокировать учетную запись в первой попытке злоумышленника.
  • Атаку можно предотвратить даже до следующего входа, как и другие методы.

Недостаток

  • Несколько запросов на сервер только для одного входа

Улучшение

  • Выполнено использование iframe ajax

Ответ 5

Я задал один угол этого вопроса здесь, и ответы приведут вас к всем связанным с маркером тайм-тайм файлам cookie, которые вам нужны.

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

Ответ 6

Я рекомендовал бы подход, упомянутый Стефаном (т.е. следовать рекомендациям в Улучшенная постоянная практика печенья для зарегистрированных пользователей), а также рекомендовать вам убедиться ваши файлы cookie HttpOnly cookie, поэтому они недоступны, возможно, вредоносным, JavaScript.

Ответ 7

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

Ответ 8

Старый поток, но все же действительный интерес. Я заметил некоторые хорошие отзывы о безопасности и избегал использования "безопасности через безвестность", но фактические технические методы были недостаточными в моих глазах. Вещи, которые я должен сказать, прежде чем вносить свой метод:

  • НИКОГДА не хранит пароль в текстовом виде... EVER!
  • НИКОГДА не хранит пароль пользователя в нескольких местах в вашей базе данных. Бэкэнд сервера всегда способен вытащить хешированный пароль из таблицы пользователей. Не более эффективно хранить избыточные данные вместо дополнительных транзакций БД, обратное верно.
  • Идентификатор сеанса должен быть уникальным, поэтому ни один из двух пользователей не мог когда-либо делиться идентификатором, следовательно, цель идентификатора (может ли ваш идентификатор лицензии на водительский номер когда-либо соответствовать другим лицам?). Это генерирует уникальная комбинация из двух частей, основанная на 2 уникальных строках. В таблице "Сеансы" следует использовать идентификатор в качестве ПК. Чтобы разрешить нескольким устройствам доверять автозапуск, используйте другую таблицу для доверенных устройств, которая содержит список всех проверенных устройств (см. Мой пример ниже) и отображается с использованием имени пользователя.
  • Он не предназначен для хэширования известных данных в файл cookie, cookie может быть скопирован. То, что мы ищем, является подходящим пользовательским устройством для предоставления достоверной информации, которая не может быть получена без злоумышленника, ставящего под угрозу пользовательскую машину (опять же, см. Мой пример). Это означало бы, однако, что законный пользователь, который запрещает свою статическую информацию своего компьютера (то есть MAC-адрес, имя хоста устройства, useragent, если он ограничен браузером и т.д.) Из оставшихся согласованных (или обманывает его в первую очередь), не сможет используйте эту функцию. Но если это вызывает беспокойство, подумайте о том, что вы предлагаете авто-signin для пользователей, которые идентифицируют себя уникально, поэтому, если они отказываются быть известными, спуская их MAC, подделывая их useragent, spoofing/change их имя хоста, скрываясь за прокси-серверами и т.д., тогда они не идентифицируются и никогда не должны быть аутентифицированы для автоматической службы. Если вы этого хотите, вам необходимо изучить доступ к смарт-карте в комплекте с клиентским программным обеспечением, которое устанавливает идентификатор для используемого устройства.

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

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

Это дешево, и некоторые из них также могут считаться грязными, потому что он пытается подтвердить ваши потенциально уже подписанные в себе с такими местами, как Google и Facebook, даже не сообщая вам. Однако он не должен использоваться для пользователей, которые не просили автоматически подписывать ваш сайт, и этот конкретный метод предназначен только для внешней аутентификации, например, в Google+ или FB.

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

  • Пользователь "joe" посещает сайт в первый раз, идентификатор сеанса, помещенный в cookie 'session'.
  • Пользователь "joe" Вход в систему, эскалация привилегий, получение нового идентификатора сеанса и обновление сеанса cookie.
  • Пользователь "joe" выбирает автоматическую подпись с помощью google +, получает уникальный идентификатор, помещенный в файл cookie 'keepmesignedin'.
  • Пользователь "joe" имеет google, чтобы они подписались, позволяя вашему сайту автоматически вводить пользователя в действие, используя Google в вашем бэкэнд.
  • Атакующий систематически пробует уникальные идентификаторы для "keepmesignedin" (это общедоступные данные, раздаваемые каждому пользователю) и не подписывается нигде; пробует уникальный идентификатор, присвоенный 'joe'.
  • Сервер получает уникальный идентификатор для "joe" , вытягивает соответствие в БД для учетной записи google +.
  • Сервер отправляет Attacker на страницу входа, на которой выполняется запрос AJAX для входа в систему Google.
  • Сервер Google получает запрос, использует его API, чтобы видеть, что Attacker не зарегистрирован в настоящее время.
  • Google отправляет ответ, что в настоящее время пользователь не подключен к этому соединению.
  • Страница атакующего получает ответ, script автоматически перенаправляет на страницу входа со значением POST, закодированным в URL-адресе.
  • Страница входа получает значение POST, отправляет cookie для "keepmesignedin" в пустое значение и действует до даты 1-1-1970, чтобы сдержать автоматическую попытку, в результате чего браузер Attacker просто удалит файл cookie.
  • Нападающему предоставляется обычная первая страница входа в систему.

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

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

=========

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

DB имеет несколько таблиц:

TABLE users:
UID - auto increment, PK
username - varchar(255), unique, indexed, NOT NULL
password_hash - varchar(255), NOT NULL
...

Обратите внимание, что имя пользователя может содержать 255 символов. У меня есть серверная программа, ограничивающая имена пользователей в моей системе до 32 символов, но внешние аутентификаторы могут иметь имена пользователей с их @domain.tld, которые будут больше, поэтому я просто поддерживаю максимальную длину адреса электронной почты для максимальной совместимости.

TABLE sessions:
session_id - varchar(?), PK
session_token - varchar(?), NOT NULL
session_data - MediumText, NOT NULL

Обратите внимание, что в этой таблице нет поля пользователя, поскольку имя пользователя при входе в систему находится в данных сеанса, а программа не допускает нулевые данные. Session_id и session_token могут быть сгенерированы с использованием случайных хешей md5, sha1/128/256 хэшей, штампов даты и времени со случайными строками, добавленными к ним, а затем хэширования или чего бы вы ни хотели, но энтропия вашего вывода должна оставаться настолько высокой, насколько допустимо смягчить атаки грубой силы даже с земли, и все хэши, созданные вашим классом сеанса, должны быть проверены на совпадения в таблице сеансов, прежде чем пытаться их добавить.

TABLE autologin:
UID - auto increment, PK
username - varchar(255), NOT NULL, allow duplicates
hostname - varchar(255), NOT NULL, allow duplicates
mac_address - char(23), NOT NULL, unique
token - varchar(?), NOT NULL, allow duplicates
expires - datetime code

MAC-адреса по своему характеру должны быть УНИКАЛЬНЫМИ, поэтому имеет смысл, что каждая запись имеет уникальное значение. Хост-имена, с другой стороны, могут быть дублированы на отдельных сетях законно. Сколько людей использует "Домашний ПК" как одно из имен своих компьютеров? Имя пользователя берется из данных сеанса сервером, поэтому манипулировать им невозможно. Что касается токена, тот же метод для создания токенов сеанса для страниц должен использоваться для создания токенов в файлах cookie для автоматического входа пользователя. Наконец, код даты и времени добавляется, когда пользователю необходимо будет подтвердить свои учетные данные. Либо обновляйте это время и время в пользовательском входе, сохраняя его в течение нескольких дней, либо заставляйте его истекать, независимо от последнего входа, сохраняя его только на месяц или около того, в зависимости от того, что ваш дизайн диктует.

Это не позволяет кому-то систематически подменять MAC и имя хоста для пользователя, которого они знают автоматически. НИКОГДА у пользователя есть файл cookie с их паролем, текстом или другим текстом. Восстановите токен на каждой странице навигации так же, как и токен сеанса. Это значительно уменьшает вероятность того, что злоумышленник может получить действительный файл cookie-токена и использовать его для входа в систему. Некоторые люди будут пытаться сказать, что злоумышленник может украсть файлы cookie у жертвы и сделать атаку повторного сеанса для входа в систему. Если злоумышленник может украсть файлы cookie (что возможно), они наверняка скомпрометировали бы все устройство, а это означает, что они могут просто использовать устройство для входа в систему в любом случае, что наносит ущерб цели кражи файлов cookie полностью. Пока ваш сайт работает через HTTPS (который должен иметь дело с паролями, номерами CC или другими системами входа в систему), вы предоставили всю защиту пользователю, который вы можете использовать в браузере.

Одна вещь, о которой нужно помнить: данные сеанса не должны заканчиваться, если вы используете автозапись. Вы можете устаревать, чтобы продолжить сеанс ложно, но проверка в системе должна возобновить данные сеанса, если это постоянные данные, которые, как ожидается, будут продолжаться между сеансами. Если вы хотите как постоянные, так и непостоянные данные сеанса, используйте другую таблицу для постоянных данных сеанса с именем пользователя в качестве ПК и получите сервер, как и обычные данные сеанса, просто используйте другую переменную.

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

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

Я прошу прощения, если кто-то ожидал, что код будет выдан в моем ответе, что не произойдет здесь. Я скажу, что я использую PHP, jQuery и AJAX для запуска своих сайтов, и я НИКОГДА не использую Windows в качестве сервера... когда-либо.

Ответ 9

Мое решение такое. Он не на 100% пуленепробиваемый, но я думаю, что он спасет вас в большинстве случаев.

Когда пользователь вошел в систему, успешно создайте строку с этой информацией:

$data = (SALT + ":" + hash(User Agent) + ":" + username 
                     + ":" + LoginTimestamp + ":"+ SALT)

Зашифруйте $data, установите тип HttpOnly и установите cookie.

Когда пользователь вернется на ваш сайт, выполните следующие действия:

  • Получить данные cookie. Удалите опасные символы внутри файла cookie. Разверните его с помощью символа :.
  • Проверить правильность. Если cookie старше X дней, переадресовать пользователя на страницу входа.
  • Если cookie не старый; Получите последнее время смены пароля из базы данных. Если пароль изменен после последнего входа пользователя в систему, перенаправите пользователя на страницу входа.
  • Если пропуск не был изменен в последнее время; Получить текущий агент браузера. Проверьте (currentUserAgentHash == cookieUserAgentHash). IF-агенты одинаково переходят к следующему шагу, иначе перенаправляются на страницу входа.
  • Если все шаги успешно пройдены, авторизуйте имя пользователя.

Если пользовательские выходы, удалите этот файл cookie. Создайте новый файл cookie, если пользователь повторно запустится.

Ответ 10

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

Я думаю о том, чтобы использовать этот подход для "Запомнить меня" . Если вы видите какие-либо проблемы, прокомментируйте.

  • Создайте таблицу для хранения данных "Запомнить меня" - отделитесь от таблицы пользователя, чтобы я мог входить в систему с нескольких устройств.

  • При успешном входе в систему (с напоминанием "Запомнить меня" ):

    a) Создайте уникальную случайную строку, которая будет использоваться как UserID на этом компьютере: bigUserID

    b) Создайте уникальную случайную строку: bigKey

    c) Храните файл cookie: bigUserID: bigKey

    d) В таблице "Запомнить меня" добавьте запись с: UserID, IP-адресом, bigUserID, bigKey

  • Если вы пытаетесь получить доступ к тому, что требует входа в систему:

    a) Проверьте файл cookie и выполните поиск по BigUserID и bigKey с соответствующим IP-адресом.

    b) Если вы его найдете, зарегистрируйте человека, но установите флажок в пользовательской таблице "soft login", чтобы при любых опасных операциях вы могли запросить полный логин.

  • При выходе из системы отметьте все записи "Запомнить меня" для этого пользователя, срок действия которых истек.

Единственными уязвимостями, которые я вижу, является:

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

Ответ 11

Я прочитал все ответы и все еще затрудняюсь извлечь то, что я должен был сделать. Если изображение стоит 1 тыс. Слов, я надеюсь, что это поможет другим реализовать безопасное постоянное хранилище на основе Barry Jaspan Улучшенная передовая практика cookie для постоянных пользователей

введите описание изображения здесь

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

Ответ 12

Реализация функции "Keep Me Logged In" означает, что вам нужно точно определить, что это будет означать для пользователя. В простейшем случае я бы использовал это, чтобы означать, что сессия имеет гораздо больший таймаут: 2 дня (скажем) вместо 2 часов. Для этого вам понадобится ваше собственное хранилище сеансов, возможно, в базе данных, поэтому вы можете установить пользовательские сроки истечения срока действия для данных сеанса. Затем вам нужно убедиться, что вы установили cookie, который будет придерживаться в течение нескольких дней (или дольше), а не истекает, когда они закрывают браузер.

Я слышу, как вы спрашиваете "почему 2 дня? почему бы не 2 недели?". Это связано с тем, что использование сеанса в PHP автоматически приведет к истечению срока действия. Это связано с тем, что истечение сеанса в PHP на самом деле является тайм-аутом в режиме ожидания.

Теперь, сказав это, я бы, вероятно, использовал более сложное значение таймаута, которое я храню в самом сеансе, и выходил через 2 недели или около того, и добавлял код, чтобы увидеть это и принудительно аннулировать сеанс. Или, по крайней мере, вывести их из системы. Это будет означать, что пользователю будет предложено войти в систему периодически. Yahoo! делает это.

Ответ 13

Использовать какой-то хэш cookie, имя пользователя + md5($ip, $username, $password)? Это было бы моим предложением.

И if(md5($_SERVER['REMOTE_ADDR'], $username, $password) = $cookiehash)?:)