"Keep me Logged In" - najlepsze podejście

Moja aplikacja internetowa używa sesji do przechowywania informacji o użytkowniku po zalogowaniu się i do utrzymywania tych informacji podczas podróży ze strony na stronę w aplikacji. W tej konkretnej aplikacji przechowuję user_id, first_name i last_name osoby.

Chciałbym zaoferować opcję "Pozostaw mnie zalogowanym" po zalogowaniu, która spowoduje umieszczenie pliku cookie na komputerze użytkownika na dwa tygodnie, który ponownie uruchomi sesję z tymi samymi danymi po powrocie do aplikacji.

Co to jest najlepsze podejście do tego? Nie chcę przechowywać ich user_id w pliku cookie, ponieważ wydaje się, że ułatwi to jednemu użytkownikowi próbę sfałszowania tożsamości innego użytkownika.

Author: Jimbo, 2009-08-31

12 answers

Ok, pozwól, że powiem wprost: jeśli umieszczasz dane użytkownika lub cokolwiek pochodzi z danych użytkownika w pliku cookie w tym celu, robisz coś złego.

Tam. Powiedziałem to. Teraz możemy przejść do odpowiedzi.

Co jest nie tak z hashowaniem danych użytkowników, pytasz? Cóż, sprowadza się to do powierzchni ekspozycji i bezpieczeństwa poprzez zaciemnienie.

Wyobraź sobie, że jesteś napastnikiem. Widzisz kryptograficzny plik cookie ustawiony dla remember-me na twojej sesji. Liczy 32 znaki. Rany. To może być MD5... Wyobraźmy sobie przez chwilę, że znają algorytm, którego użyłeś. Na przykład:
md5(salt+username+ip+salt)

Teraz, wszystko, co atakujący musi zrobić, to brutalna siła " sól "(która tak naprawdę nie jest solą, ale o tym później), i może teraz wygenerować wszystkie fałszywe tokeny, które chce z dowolną nazwą użytkownika dla swojego adresu IP! Ale brutalne wymuszanie soli jest trudne, prawda? Oczywiście. Ale Współczesne GPU są w tym niezmiernie dobre. I chyba, że użyjesz wystarczająca przypadkowość w nim (uczynić go wystarczająco duży), to będzie szybko spaść, a wraz z nim Klucze do zamku.

Krótko mówiąc, jedyną rzeczą, która cię chroni, jest sól, która tak naprawdę nie chroni cię tak bardzo, jak myślisz.

Ale Czekaj!

Wszystko to było oparte na tym, że napastnik zna algorytm! Jeśli to tajne i zagmatwane, to jesteś bezpieczny, prawda? źle . Ta linia myślenia ma nazwę: bezpieczeństwo poprzez Mroczność , na której nigdy nie powinno się polegać.

The Better Way

Lepszym sposobem jest nigdy nie pozwolić, aby informacje użytkownika opuściły serwer, z wyjątkiem id.

Gdy użytkownik się zaloguje, Wygeneruj duży (od 128 do 256 bitów) losowy token. Dodaj to do tabeli bazy danych, która mapuje token do identyfikatora użytkownika, a następnie wyślij go do Klienta w pliku cookie.

Co jeśli atakujący odgadnie losowy token innego użytkownika?

Dobrze, Policzmy trochę. Generujemy 128-bitowy losowy token. Oznacza to, że istnieją:

possibilities = 2^128
possibilities = 3.4 * 10^38

Teraz, aby pokazać, jak absurdalnie duża jest ta liczba, wyobraźmy sobie, że każdy serwer w Internecie (powiedzmy 50,000,000 dzisiaj) próbuje brutalnie wymusić tę liczbę w tempie 1,000,000,000 na sekundę każdy. W rzeczywistości twoje serwery stopiłyby się pod takim obciążeniem, ale Zagrajmy w to.

guesses_per_second = servers * guesses
guesses_per_second = 50,000,000 * 1,000,000,000
guesses_per_second = 50,000,000,000,000,000
Więc 50 bilionów domysłów na sekundę. Szybko! Prawda?
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

Tak 6.8 sekstillion sekund...

Spróbujmy sprowadzić to do bardziej przyjaznych liczb.
215,626,585,489,599 years

Albo jeszcze lepiej:

47917 times the age of the universe
Tak, to 47917 razy więcej niż wiek Wszechświata...

W Zasadzie, to nie będzie pęknięty.

Więc podsumowując:

Lepsze podejście, które polecam, to Przechowywanie ciastka z trzema częściami.

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);
}

Następnie, aby potwierdzić:

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);
        }
    }
}

Uwaga: nie używaj tokena lub kombinacji user I token do wyszukuje rekord w bazie danych. Zawsze pamiętaj, aby pobrać rekord oparty na użytkowniku i użyć funkcji porównania bezpiecznego dla czasu, aby następnie porównać pobrany token. więcej o atakach czasowych .

Teraz, to jest bardzo Ważne, aby SECRET_KEY była tajemnicą kryptograficzną (generowaną przez coś w rodzaju /dev/urandom i/lub pochodzącą z wejścia o wysokiej entropii). Ponadto, GenerateRandomToken() musi być silnym źródłem losowym (mt_rand() nie jest wystarczająco silny. Korzystać z biblioteki, takiej jak RandomLib lub random_compat , lub mcrypt_create_iv() z DEV_URANDOM)...

The hash_equals() jest zapobieganie atakom czasowym . Jeśli używasz wersji PHP poniżej PHP 5.6 funkcja hash_equals() nie jest obsługiwana. W takim przypadku można zastąpić hash_equals() z funkcją 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'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;
}
 627
Author: ircmaxell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-27 08:48:43

Uwaga dotycząca bezpieczeństwa: oparcie pliku cookie na hashu MD5 deterministycznych danych jest złym pomysłem; lepiej jest użyć losowego tokena pochodzącego z csprng. Zobacz odpowiedź ircmaxell na to pytanie, aby uzyskać bardziej bezpieczne podejście.

Zazwyczaj robię coś takiego:

  1. Użytkownik loguje się za pomocą "keep me logged in"
  2. Utwórz sesję
  3. Utwórz plik cookie o nazwie coś zawierającego: md5 (salt+username+ip+salt) oraz plik cookie o nazwie somethingElse zawierający id
  4. przechowuj plik cookie w bazie danych
  5. User does stuff and leaves - - - -
  6. user returns, check for somethingElse cookie, if it exists, get the old hash from the database for that user, check of the content of cookie SOMETHING match with the hash from the database, which should also match with a newly calculated hash (for the ip) thus: cookieHash= = databaseHash= = md5 (salt+username+ip+salt), if they do, goto 2, if they don 't goto 2, if they don' t goto 1

Oczywiście możesz używać różnych nazw plików cookie itp. możesz również nieco zmienić zawartość pliku cookie, po prostu upewnij się, że nie jest to łatwe tworzenie. Można na przykład utworzyć user_salt, gdy użytkownik jest tworzony, a także umieścić go w pliku cookie.

Możesz też użyć sha1 zamiast md5 (lub praktycznie dowolnego algorytmu)
 94
Author: Pim Jager,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:32

Wprowadzenie

Twój tytuł "Keep Me Logged In" - najlepsze podejście sprawia, że trudno mi wiedzieć, od czego zacząć, ponieważ jeśli szukasz najlepszego podejścia, musisz wziąć pod uwagę następujące kwestie :

  • Identyfikacja
  • bezpieczeństwo

Cookies

Pliki cookie są podatne na zagrożenia, między typowymi lukami w zabezpieczeniach przeglądarki i atakami skryptowymi między stronami musimy zaakceptować, że pliki cookie nie są bezpieczne. Aby poprawić bezpieczeństwo należy pamiętać, że php setcookies posiada dodatkowe funkcje, takie jak

Bool setcookie (string $name [, string $value [, int $expire = 0 [, string $path [, string $domain [, bool $secure = false [, bool $httponly = false ]]]]]] )

  • bezpieczne (przy użyciu połączenia HTTPS)
  • W 2007 roku firma została założona w 2008 roku.]}

Definicje

  • Token (nieprzewidywalny losowy ciąg n długości np. / dev / urandom)
  • Reference (nieprzewidywalny losowy ciąg N długości np. / dev / urandom)
  • Signature (generowanie wartości skrótu z kluczem przy użyciu metody HMAC)

Proste Podejście

Prostym rozwiązaniem byłoby:

  • użytkownik jest zalogowany przez Remember Me
  • Login Cookie issued with token & Signature
  • Po powrocie podpis jest sprawdzone
  • jeśli podpis jest ok .. następnie nazwa użytkownika i token są sprawdzane w bazie danych
  • Jeśli nie jest poprawna .. powrót do strony logowania
  • If valid automatically login

Powyższe studium przypadku podsumowuje wszystkie przykłady podane na tej stronie, ale są one wadą jest to, że

    Nie wiadomo, czy ciastka zostały skradzione.]}
  • atakujący może mieć dostęp do poufnych operacji, takich jak zmiana hasła lub danych, takich jak osobiste i pieczenia informacje itp.
  • Plik cookie może być przechowywany przez cały okres użytkowania.]}

Lepsze Rozwiązanie

Lepszym rozwiązaniem byłoby

  • użytkownik jest zalogowany i wybierz Zapamiętaj mnie
  • Generuj Token i podpis i przechowuj w pliku cookie
  • tokeny są losowe i są ważne tylko dla pojedynczej autentykacji
  • token jest zastępowany przy każdej wizycie na stronie
  • gdy niezalogowany użytkownik odwiedza strona podpis, token i nazwa użytkownika są weryfikowane
  • Zapamiętaj mnie login powinien mieć ograniczony dostęp i nie zezwalać na modyfikację hasła, danych osobowych itp.

Przykładowy Kod

// 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());
}

Klasa Używana

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);
    }
}

testowanie w Firefoksie i Chrome

Tutaj wpisz opis obrazka

korzyść

  • Lepsze Bezpieczeństwo
  • ograniczony dostęp dla atakującego
  • gdy cookie jest kradziony jest tylko ważny dla pojedynczego dostępu
  • Kiedy następny użytkownik wejdzie na stronę, możesz automatycznie wykryć i powiadomić użytkownika o kradzieży.]}

wada

  • nie obsługuje stałego połączenia przez wiele przeglądarek (mobilnych i internetowych)
  • plik cookie może zostać skradziony, ponieważ użytkownik otrzymuje powiadomienie dopiero po następnym zalogowaniu.

Quick Fix

  • wprowadzenie homologacji system dla każdego systemu, który musi mieć stałe połączenie
  • Użyj wielu plików cookie do uwierzytelniania

Podejście Wielu Plików Cookie

Gdy atakujący ma zamiar ukraść gotuje tylko skupić się na konkretnej stronie internetowej lub domenie np. example.com

Ale tak naprawdę można uwierzytelnić użytkownika z 2 różnych domen ( example.com & fakeaddsite.com ) i sprawić, by wyglądało to jak " reklamowe ciasteczko"

  • użytkownik zalogowany na example.com with remember me
  • nazwa użytkownika, token, odniesienie w pliku cookie
  • Nazwa Użytkownika Sklepu, token , odniesienie w bazie danych np. Memcache
  • Wyślij refrence id poprzez get i iframe do fakeaddsite.com
  • fakeaddsite.com używa referencji do pobrania user & token z bazy danych
  • fakeaddsite.com przechowuje podpis
  • gdy użytkownik zwraca fetch signature information with iframe od fakeaddsite.com
  • Połącz dane it i wykonaj walidację
  • ..... znasz pozostałe

Niektórzy mogą się zastanawiać, jak można używać 2 różnych plików cookie ? To możliwe, wyobraź sobie example.com = localhost i fakeaddsite.com = 192.168.1.120. Jeśli przejrzysz pliki cookie, wyglądałoby to tak

Tutaj wpisz opis obrazka

Z obrazka powyżej

    W tym celu należy skontaktować się z Działem obsługi klienta.]}
  • zawiera również pliki cookie ustawione z 192.168.1.120

192.168.1.120

  • akceptuje tylko zdefiniowane HTTP_REFERER
  • akceptuje tylko połączenie z podanego REMOTE_ADDR
  • bez JavaScript, bez treści, ale nie składają się z niczego, zamiast podpisywać informacje i dodawać lub pobierać je z pliku cookie

korzyść

  • 99% procent czasu, kiedy oszukałeś napastnika
  • możesz łatwo zablokować konto przy pierwszej próbie ataku
  • atak może być uniemożliwione nawet przed następnym logowaniem, podobnie jak inne metody

wada

  • wielokrotne żądanie do serwera tylko dla jednego logowania

Poprawa

  • Done use iframe use ajax
 67
Author: Baba,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-12 12:49:03

Są dwa bardzo ciekawe artykuły, które znalazłem szukając idealnego rozwiązania problemu "Zapamiętaj mnie":

 24
Author: Stefan Gehrig,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-31 06:38:23

Zadałem jedno pytanie tutaj , A odpowiedzi poprowadzą Cię do wszystkich potrzebnych linków do plików cookie opartych na tokenie.

Zasadniczo nie przechowujesz identyfikatora użytkownika w pliku cookie. Przechowujesz jednorazowy token (ogromny ciąg znaków), którego użytkownik używa do odebrania swojej starej sesji logowania. Następnie, aby było naprawdę bezpieczne, prosisz o hasło do ciężkich operacji (takich jak zmiana samego hasła).

 6
Author: Dan Rosenstark,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:33

Polecam podejście wspomniane przez Stefana (tj. postępuj zgodnie z wytycznymi w Improved Persistent Login Cookie Best Practice), a także zalecam, aby upewnić się, że Twoje pliki cookie są HttpOnly cookies, aby nie były dostępne dla, potencjalnie złośliwego, JavaScript.

 5
Author: Walter Rumsby,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-20 22:40:25

Wygeneruj hash, może z tajemnicą, którą znasz, a następnie przechowuj go w DB, aby mógł być powiązany z użytkownikiem. Powinno zadziałać całkiem nieźle.

 4
Author: Jani Hartikainen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-30 21:52:54

Stary wątek, ale nadal ważny problem. Zauważyłem kilka dobrych odpowiedzi na temat bezpieczeństwa i unikania stosowania "bezpieczeństwa przez ciemność", ale rzeczywiste metody techniczne nie były wystarczające w moich oczach. Rzeczy, które muszę powiedzieć, zanim wniosę swój wkład w moją metodę:

  • nigdy nie przechowuj hasła w czystym tekście...Nigdy!
  • nigdy nie przechowuj hashowanego hasła użytkownika w więcej niż jednym miejscu w bazie danych. Backend serwera jest zawsze w stanie wyciągnąć haszowane hasło z tabeli użytkowników. Nie jest bardziej wydajne przechowywanie nadmiarowych danych zamiast dodatkowych transakcji DB, odwrotność jest prawdziwa.
  • Twój identyfikator sesji powinien być unikalny, więc żaden użytkownik nie mógł kiedykolwiek udostępnić identyfikatora, stąd cel ID (czy numer Twojego prawa jazdy mógłby kiedykolwiek pasować do innej osoby? Nie.) Tworzy to dwuczęściową unikalną kombinację, opartą na 2 unikalnych strunach. Twoja tabela sesji powinna używać ID jako PK. Aby umożliwić zaufanie wielu urządzeniom w przypadku auto-signin użyj innej tabeli dla zaufanych urządzeń, która zawiera listę wszystkich zweryfikowanych urządzeń (patrz mój przykład poniżej) i jest mapowana przy użyciu nazwy użytkownika.
  • nie służy do hashowania znanych danych do pliku cookie, plik cookie można skopiować. To, czego szukamy, to zgodne urządzenie Użytkownika, które dostarcza autentycznych informacji, których nie można uzyskać bez naruszenia komputera użytkownika przez osobę atakującą (zobacz mój przykład). Oznaczałoby to jednak, że uprawniony użytkownik, który zabrania informacje statyczne jego komputera (tj. adres MAC, Nazwa hosta urządzenia, useragent, jeśli jest ograniczona przez przeglądarkę, itp.) z pozostających spójnych (lub fałszywych w pierwszej kolejności) nie będzie mógł korzystać z tej funkcji. Ale jeśli jest to problemem, rozważ fakt, że oferujesz auto-signin użytkownikom, którzy identyfikuj się wyjątkowo, więc jeśli nie chcą być znani przez fałszowanie ich MAC, fałszowanie ich useragent, fałszowanie / zmienianie nazwy hosta, ukrywanie się za proxy, itp., wtedy nie są one możliwe do zidentyfikowania i nigdy nie powinny być uwierzytelniane dla usługi automatycznej. Jeśli tego chcesz, musisz przyjrzeć się dostępowi do kart inteligentnych w pakiecie z oprogramowaniem po stronie klienta, które ustala tożsamość używanego urządzenia.

To wszystko jest powiedziane, istnieją dwa świetne sposoby, aby mieć auto-signin w systemie.

Po pierwsze, tani, łatwy sposób, który zrzuca wszystko na kogoś innego. Jeśli sprawisz, że Twoja witryna będzie obsługiwać logowanie za pomocą, powiedzmy, konta google+, prawdopodobnie mieć usprawniony przycisk google+, który zaloguje użytkownika, jeśli są już zalogowani w google(zrobiłem to tutaj, aby odpowiedzieć na to pytanie, ponieważ zawsze jestem zalogowany w google). Jeśli chcesz, aby użytkownik zalogował się automatycznie, jeśli jest już zalogowany za pomocą zaufanego i obsługiwanego uwierzytelniania i zaznaczone pole, aby to zrobić, niech skrypty po stronie klienta wykonają kod za odpowiednim przyciskiem "Zaloguj się za pomocą" przed załadowaniem, po prostu upewnij się, że serwer przechowuje unikalny identyfikator w tabela auto-signin z nazwą użytkownika, identyfikatorem sesji i authenticatorem używanym dla użytkownika. Ponieważ te metody logowania używają AJAX, i tak czekasz na odpowiedź, a ta odpowiedź jest albo zatwierdzoną odpowiedzią, albo odrzuceniem. Jeśli otrzymasz potwierdzoną odpowiedź, użyj jej normalnie, a następnie kontynuuj Ładowanie zalogowanego użytkownika jak zwykle. W przeciwnym razie logowanie nie powiodło się, ale nie mów użytkownikowi, po prostu kontynuuj jako niezalogowany, zauważą. Ma to zapobiec atakującemu, który ukradł pliki cookie (lub sfałszowane je w celu eskalacji uprawnień) z wiedzy, że Użytkownik automatycznie loguje się na stronę.

To jest tanie, a także może być uznane za brudne przez niektórych, ponieważ stara się zweryfikować potencjalnie już zalogowany w siebie z miejsc takich jak Google i Facebook, nawet nie mówiąc ci. Nie należy go jednak używać u użytkowników, którzy nie poprosili o Automatyczne logowanie na twojej stronie, a ta konkretna metoda służy tylko do zewnętrznego uwierzytelniania, jak w przypadku Google+ lub FB.

Ponieważ zewnętrzny authenticator został użyty do poinformowania serwera za kulisami, czy użytkownik został zweryfikowany, czy nie, atakujący nie może uzyskać niczego innego niż unikalny identyfikator, który sam w sobie jest bezużyteczny. Rozwiążę:

  • użytkownik " joe "odwiedza witrynę po raz pierwszy, identyfikator sesji umieszczony w pliku cookie "session".
  • użytkownik " joe "loguje się, zwiększa uprawnienia, otrzymuje nowy identyfikator sesji i odnawia "sesję" pliku cookie.
  • użytkownik " joe " wybiera auto-signin używając google+, dostaje unikalny identyfikator umieszczony w pliku cookie "keepmesignedin".
  • użytkownik " joe " ma google keep them login in, umożliwiając Twojej witrynie Automatyczne logowanie użytkownika za pomocą google w Twoim backendzie.
  • atakujący systematycznie próbuje unikalnych identyfikatorów dla 'keepmesignedin' (jest to wiedza publiczna przekazywana każdemu użytkownikowi) i nie jest zalogowany nigdzie indziej; próbuje unikalnych identyfikatorów dla 'joe'.
  • serwer otrzymuje unikalny identyfikator dla 'joe', pobiera dopasowanie w DB dla konta google+.
  • serwer wysyła atakującego do logowania strona, która uruchamia żądanie AJAX do google, aby się zalogować.
  • serwer Google otrzymuje żądanie, używa swojego API, aby zobaczyć, że atakujący nie jest aktualnie zalogowany.
  • Google wysyła odpowiedź, że nie ma aktualnie zalogowanego użytkownika przez to połączenie.
  • strona atakującego otrzymuje odpowiedź, skrypt automatycznie przekierowuje na stronę logowania z wartością posta zakodowaną w adresie url.
  • strona logowania pobiera wartość POST, wysyła plik cookie dla "keepmesignedin" do pustej wartości i ważnego do daty 1-1-1970, aby powstrzymać automatyczną próbę, powodując, że przeglądarka atakującego po prostu usunie plik cookie.
  • atakujący otrzymuje normalną stronę logowania po raz pierwszy.

Bez względu na wszystko, nawet jeśli atakujący użyje identyfikatora, który nie istnieje, próba powinna zakończyć się niepowodzeniem we wszystkich próbach, z wyjątkiem sytuacji, gdy otrzymana zostanie potwierdzona odpowiedź.

Ta metoda może i powinna być używana w połączeniu z twoim wewnętrznym uwierzytelniaczem dla tych, którzy logują się do twojej witryny za pomocą zewnętrznego authenticator.

=========

Teraz, dla Twojego własnego systemu authenticator, który może automatycznie podpisywać użytkowników, tak to robię:

DB ma kilka tabel:

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

Zauważ, że nazwa użytkownika może mieć długość 255 znaków. Mój program serwera ogranicza nazwy użytkowników w moim systemie do 32 znaków, ale zewnętrzne uwierzytelniacze mogą mieć nazwy użytkowników ze swoją domeną@.tld być większy niż to, więc po prostu obsługuję maksymalną długość adresu e-mail dla maksymalnej kompatybilność.

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

Zauważ, że w tej tabeli nie ma pola user, ponieważ nazwa użytkownika, po zalogowaniu, znajduje się w danych sesji, a program nie zezwala na dane null. Session_id i session_token mogą być generowane przy użyciu losowych skrótów md5, skrótów sha1/128/256, znaczników datetime z losowymi ciągami dodanymi do nich, a następnie hashowanymi, lub cokolwiek chcesz, ale Entropia twojego wyjścia powinna pozostać tak wysoka, jak tolerowana, aby złagodzić ataki brute-force z nawet wysiadania grunt i wszystkie hasze generowane przez klasę sesji powinny być sprawdzane pod kątem dopasowań w tabeli sesji przed próbą dodania ich.

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

Adresy MAC ze swojej natury mają być unikalne, dlatego ma sens, że każdy wpis ma unikalną wartość. Z drugiej strony nazwy hostów mogą być legalnie powielane w oddzielnych sieciach. Ile osób używa "Home-PC" jako nazwy komputera? Nazwa użytkownika jest pobierana z danych sesji Przez zaplecze serwera, więc manipulowanie tym jest niemożliwe. Jeśli chodzi o token, ta sama metoda generowania tokenów sesji dla stron powinna być używana do generowania tokenów w plikach cookie dla użytkownika auto-signin. Na koniec, kod datetime jest dodawany, gdy użytkownik będzie musiał ponownie potwierdzić swoje poświadczenia. Albo zaktualizuj tę datę po zalogowaniu użytkownika, zachowując ją w ciągu kilku dni, lub Wymuś jej wygaśnięcie niezależnie od ostatniego logowania, zachowując ją tylko przez miesiąc lub dłużej, niezależnie od tego, co dyktuje Twój projekt.

To uniemożliwia komuś systematyczne fałszowanie MAC i nazwy hosta dla użytkownika, który zna Automatyczne logowanie. nigdy niech użytkownik zachowa plik cookie z hasłem, wyraźnym tekstem lub w inny sposób. Niech token zostanie zregenerowany podczas każdej nawigacji po stronie, tak jak token sesji. To znacznie zmniejsza prawdopodobieństwo, że atakujący może uzyskać poprawny token cookie i użyć go do zalogowania. Niektórzy ludzie będą próbowali powiedzieć, że atakujący może ukraść pliki cookie ofierze i powtórzyć sesję atak, aby się zalogować. Jeśli atakujący mógłby ukraść pliki cookie( co jest możliwe), z pewnością naraziłby całe urządzenie, co oznacza, że mógłby po prostu użyć urządzenia do zalogowania się, co całkowicie zaprzecza celowi kradzieży plików cookie. Tak długo, jak twoja witryna działa przez HTTPS (co powinno się robić w przypadku haseł, numerów CC lub innych systemów logowania), zapewniłeś użytkownikowi pełną ochronę, jaką możesz uzyskać w przeglądarce.

Jedna rzecz, o której należy pamiętać: dane sesji nie powinno wygasnąć, jeśli używasz auto-signin. Można wygasnąć możliwość kontynuowania sesji fałszywie, ale Walidacja do systemu powinna wznowić dane sesji, jeśli oczekuje się, że są to dane trwałe, które mają być kontynuowane między sesjami. Jeśli chcesz mieć zarówno trwałe, jak i nietrwałe dane sesji, użyj innej tabeli dla trwałych danych sesji z nazwą użytkownika jako PK i poproś serwer o pobranie ich tak, jak normalne dane sesji, po prostu użyj innej zmiennej.

Gdy login ma w ten sposób serwer powinien nadal sprawdzać poprawność sesji. W tym miejscu można kodować oczekiwania dotyczące skradzionych lub skompromitowanych systemów; wzorce i inne oczekiwane wyniki logowania do danych sesji często mogą prowadzić do wniosków, że system został porwany lub pliki cookie zostały sfałszowane w celu uzyskania dostępu. W tym miejscu technologia ISS może wprowadzić reguły, które spowodowałyby zablokowanie konta lub automatyczne usunięcie użytkownika z systemu auto-signin, utrzymując atakujących wystarczająco długo aby ustalić, w jaki sposób atakujący odniósł sukces i jak go odciąć.

Na zakończenie należy upewnić się, że wszelkie próby odzyskania, zmiany hasła lub błędy logowania po przekroczeniu progu skutkują wyłączeniem funkcji auto-signin, dopóki użytkownik nie potwierdzi poprawności i nie potwierdzi tego.

Przepraszam, jeśli ktoś spodziewał się, że kod zostanie podany w mojej odpowiedzi, to tutaj się to nie stanie. Powiem, że używam PHP, jQuery i AJAX do uruchamiania moich stron i nigdy nie używam Windows jako serwer... nigdy.
 3
Author: user253780,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-07 22:31:29

Moje rozwiązanie jest takie. Nie jest w 100% kuloodporny, ale myślę, że zaoszczędzi ci na większości przypadków.

Gdy użytkownik zalogowany pomyślnie Utwórz łańcuch z tą informacją:

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

Szyfruj $data, Ustaw typ na HttpOnly i ustaw plik cookie.

Kiedy użytkownik powróci na Twoją stronę, wykonaj następujące kroki:

  1. Pobierz dane cookie. Usuń niebezpieczne znaki wewnątrz pliku cookie. Explode it with : character.
  2. Sprawdź ważność. Jeśli plik cookie jest starsze niż X dni następnie przekierować użytkownika do strony logowania.
  3. Jeśli plik cookie nie jest stary; uzyskaj czas ostatniej zmiany hasła z bazy danych. Jeśli hasło zostanie zmienione po ostatnim zalogowaniu użytkownika, przekieruj użytkownika na stronę logowania.
  4. Jeśli pass nie został ostatnio zmieniony; Pobierz aktualnego agenta przeglądarki użytkownika. Sprawdź czy (currentUserAgentHash == cookieUserAgentHash). Jeśli agenci są tacy sami, przejdź do następnego kroku, w przeciwnym razie przekieruj na stronę logowania.
  5. Jeśli wszystkie kroki pomyślnie przeszły autoryzację nazwa użytkownika.

Jeśli użytkownik wylogowuje się, usuń ten plik cookie. Utwórz nowy plik cookie, jeśli użytkownik ponownie się zaloguje.

 2
Author: trante,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-04 00:06:21

Nie rozumiem koncepcji przechowywania zaszyfrowanych rzeczy w pliku cookie, gdy jest to zaszyfrowana wersja tego, że trzeba zrobić hacking. Jeśli coś przeoczyłem, proszę o komentarz.

Myślę o podjęciu takiego podejścia, aby "zapamiętać mnie". Jeśli widzisz jakieś problemy, prosimy o komentarz.

  1. Utwórz tabelę do przechowywania danych "Zapamiętaj mnie" - oddzielona od tabeli użytkownika, abym mógł zalogować się z wielu urządzeń.

  2. Przy pomyślnym logowaniu (z Zapamiętaj mnie):

    A) Wygeneruj unikalny losowy ciąg znaków, który będzie używany jako identyfikator użytkownika na tej maszynie: bigUserID

    B) Wygeneruj unikalny losowy ciąg znaków: bigKey

    C) przechowuje plik cookie: bigUserID: bigKey

    D) w tabeli "Remember Me" Dodaj rekord z: UserID, IP Address, bigUserID, bigKey

  3. Jeśli próbujesz uzyskać dostęp do czegoś, co wymaga logowania:

    A) sprawdź plik cookie i wyszukaj bigUserID & bigKey z pasującym adresem IP adres

    B) Jeśli go znajdziesz, Zaloguj się, ale ustaw flagę w tabeli użytkownika "soft login" , aby w przypadku jakichkolwiek niebezpiecznych operacji można było poprosić o pełne logowanie.

  4. Po wylogowaniu Zaznacz wszystkie rekordy "Zapamiętaj mnie" dla tego użytkownika jako wygasłe.

Jedyne luki jakie widzę to;

    Możesz chwycić czyjś laptop i sfałszować jego adres IP za pomocą pliku cookie.
  • za każdym razem można podmienić inny adres IP i zgaduj całość - ale z dwoma dużymi strunami do dopasowania, to by było...wykonując podobne obliczenia jak powyżej...Nie mam pojęcia...wielkie szanse?
 2
Author: Enigma Plus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-21 11:07:24

Przeczytałem wszystkie odpowiedzi i nadal trudno było wydobyć to, co miałem zrobić. Jeśli obraz jest wart 1K słów, mam nadzieję, że pomoże to innym zaimplementować bezpieczne trwałe przechowywanie w oparciu o najlepsze praktyki Barry ' ego Jaspana Improved Persistent Login Cookie

Tutaj wpisz opis obrazka

Jeśli masz pytania, opinie lub sugestie, postaram się zaktualizować diagram, aby odzwierciedlić dla nowicjusza próbującego zaimplementować bezpieczne trwałe logowanie.

 2
Author: Josh Woodcock,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-28 13:29:30

Implementacja funkcji "bądź zalogowany" oznacza, że musisz dokładnie określić, co to będzie oznaczać dla użytkownika. W najprostszym przypadku użyłbym tego, aby oznaczać, że sesja ma znacznie dłuższy czas oczekiwania: 2 dni (powiedzmy) zamiast 2 godzin. Aby to zrobić, potrzebujesz własnego magazynu sesji, prawdopodobnie w bazie danych, dzięki czemu możesz ustawić niestandardowe czasy wygaśnięcia danych sesji. Następnie należy upewnić się, że ustawiono plik cookie, który pozostanie na kilka dni (lub dłużej), a nie wygaśnie po zamknięciu przeglądarka.

Słyszę, jak pytasz " dlaczego 2 dni? dlaczego nie 2 tygodnie?". Dzieje się tak dlatego, że użycie sesji w PHP automatycznie przesunie wygaśnięcie. Dzieje się tak dlatego, że wygaśnięcie sesji w PHP jest w rzeczywistości bezczynnym timeoutem.

Teraz, powiedziawszy to, prawdopodobnie zaimplementowałbym trudniejszą wartość timeout, którą przechowuję w samej sesji, a na około 2 tygodnie, i dodał kod, aby to zobaczyć i siłą unieważnić sesję. Albo przynajmniej je wylogować. Oznacza to, że użytkownik zostanie poproszony o okresowe logowanie. Yahoo! czy to.

 0
Author: staticsan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-31 06:00:10