Який найкращий спосіб запобігти викрадення сеансу?


124

Зокрема, це стосується використання файлу cookie сеансу клієнта для ідентифікації сеансу на сервері.

Це найкраща відповідь на використання шифрування SSL / HTTPS для всього веб-сайту, і ви маєте найкращу гарантію того, що жоден чоловік, що перебуває в атаці посередині, не зможе обнюхати існуючий файл cookie сеансу клієнта?

І, можливо, друге найкраще використовувати якесь шифрування для самого значення сеансу, яке зберігається у вашому сеансовому файлі cookie?

Якщо шкідливий користувач має фізичний доступ до машини, він все ще може переглядати файлову систему, щоб отримати дійсне cookie сеансу та використовувати його для викрадення сеансу?

Відповіді:


140

Шифрування значення сеансу матиме нульовий ефект. Файл cookie сесії вже є довільним значенням, шифрування його просто генерує ще одне довільне значення, яке можна обнюхати.

Єдине справжнє рішення - HTTPS. Якщо ви не хочете робити SSL на своєму веб-сайті (можливо, у вас є проблеми з роботою), можливо, ви зможете позбутися лише SSL, що захищає чутливі зони. Для цього спочатку переконайтеся, що на вашій сторінці входу є HTTPS. Коли користувач входить у систему, встановіть захищений файл cookie (тобто браузер передасть його лише через посилання SSL) на додаток до звичайного файлу cookie сеансу. Потім, коли користувач відвідує одну з ваших "чутливих" областей, перенаправляйте їх на HTTPS та перевіряйте на наявність цього безпечного файлу cookie. Реальний користувач матиме його, викрадач сеансу не буде.

EDIT : Ця відповідь спочатку була написана у 2008 році. Зараз це 2016 рік, і немає причин не мати SSL на всьому веб-сайті. Більше немає простого HTTP!


28
HTTPS запобігає лише обнюхуванню. Але якщо у вас є XSS, або ідентифікатори сеансу можна легко здогадатися, або ви вразливі до фіксації сеансу, або зберігання вашого ідентифікатора сеансу слабке (ін'єкція SQL?), SSL взагалі не покращиться.
Калімо

5
@Josh Якщо шкідливий користувач має фізичний доступ до машини, вони все ще можуть переглядати файлову систему, щоб отримати дійсне cookie сеансу та використовувати його для викрадення сеансу?
Pacerier

72
Якщо шкідливий користувач має фізичний доступ до файлової системи, їм не потрібно викрадати сеанс.
Джош Гінман

25
@Josh. Неправда, іноді користувач має обмежений час фізичного доступу до файлової системи. Уявіть собі ноутбук, який залишив розблокований колегою, що мчить у туалет, тепер все, що мені потрібно зробити, - це зайти до цього ноутбука, встановити плагін EditThisCookie, взяти його куки на plus.google.com за допомогою функції експорту EditThisCookie, і тепер у мене є його акаунт . Час зайняття: 18 секунд.
Pacerier

1
Я впевнений, що в Google буде вбудована функція захисту, оскільки це, очевидно, перше, про що ви могли б подумати, розмовляючи про викрадення сеансу
xorinzor

42

SSL допомагає лише при нюхаючих атаках. Якщо зловмисник має доступ до вашої машини, я вважаю, що він може скопіювати і ваш захищений файл cookie.

Як мінімум, переконайтеся, що старі файли cookie через деякий час втрачають свою цінність. Навіть успішна атака викрадення буде зірвана, коли печиво перестане працювати. Якщо у користувача є файл cookie з сеансу, який увійшов більше місяця тому, змусьте його повторно ввести пароль. Переконайтесь, що кожен раз, коли користувач натискає посилання «Вийти» на ваш сайт, старий UUID сеансу більше не можна використовувати.

Я не впевнений, чи спрацює ця ідея, але ось що: додайте серійний номер у файл cookie сесії, можливо, такий рядок:

СесіяUUID, серійний номер, поточна дата / час

Зашифруйте цей рядок і використовуйте його як ваше cookie сеансу. Регулярно змінюйте серійний номер - можливо, коли файлу cookie виповнилося 5 хвилин, а потім повторно видайте файл cookie. Ви можете навіть перевидати його на кожному перегляді сторінки, якщо хочете. На стороні сервера зберігайте останній серійний номер, який ви видали за цей сеанс. Якщо хтось коли-небудь надсилає файл cookie з неправильним серійним номером, це означає, що зловмисник може використовувати печиво, яке вони перехопили раніше, таким чином недійсне UUID сеансу та попросить користувача повторно ввести свій пароль, а потім повторно випустити новий файл cookie.

Пам’ятайте, що у вашого користувача може бути більше одного комп'ютера, щоб у них було більше одного активного сеансу. Не робіть чогось, що змушує їх знову входити в систему щоразу, коли вони переключаються між комп'ютерами.


Я знаю, що це стара публікація, але я просто хотів включити, що якщо зловмисник захопить сеанс у вікні, відведеному "серійним номером", це не вплине на нього.
розчавити

@crush, але тоді зловмисника заблокують після відведеного вікна, правда? Так що принаймні вікно атаки невелике (ер).
Йоганнеке

2
Проблема полягає лише в тому, що якщо користувач покине ваш веб-сайт на 5 хвилин, йому доведеться знову ввійти
elipoultorak

21

Чи думали ви читати книгу про безпеку PHP? Настійно рекомендується.

Я мав великий успіх у наступному методі для не сертифікованих SSL сайтів.

  1. Відключіть кілька сеансів під одним обліковим записом, переконайтесь, що ви не перевіряєте це виключно за IP-адресою. Швидше перевірити маркер, згенерований при вході в систему, який зберігається під час сеансу користувача в базі даних, а також IP-адреса, HTTP_USER_AGENT тощо

  2. Використання гіперпосилань на основі відносин Створює посилання (наприклад, http://example.com/secure.php?token=2349df98sdf98a9asdf8fas98df8 ) Посилання додається випадково засоленою рядком MD5 x-BYTE (бажаний розмір), після перенаправлення сторінки довільно генерується маркер відповідає потрібній сторінці.

    • Після перезавантаження робиться кілька перевірок.
    • Вихідна IP-адреса
    • HTTP_USER_AGENT
    • Секен токена
    • ви отримаєте бал.
  3. Файли аутентифікації із коротким терміном служби сеансу. як було розміщено вище, хороша ідея - файл cookie, що містить захищену рядок, яка є однією з прямих посилань на термін дії сеансів. Здійснюйте термін дії кожні х хвилин, перевидаючи цей маркер і повторно синхронізуючи сеанс з новими Даними. Якщо в даних є будь-які невідповідні збіги, вийдіть користувача або вийміть їх повторно автентифікуючи сеанс.

Я жодним чином не фахівець з цього питання, я мав трохи досвіду в цій конкретній темі, сподіваюся, що щось із цього допоможе комусь там.


4
Чи є якісь книги, які ви б порекомендували?
Рікі

1
Особливо з огляду на те, що в ОП конкретно нічого не було сказано про PHP, я б сказав, що краще переглянути лише загальну книгу безпеки (тим більше, що безпека між різними мовами відрізняється лише деталями реалізації, але концепції залишаються однаковими).
matts1

у 2017 році навіть facebook / gmail тощо дозволяє проводити кілька сеансів за одним обліковим записом (особливо з мобільними пристроями), якщо ви не ненавидите своїх користувачів, номер 1 трохи застарів.
ковбер

20
// Collect this information on every request
$aip = $_SERVER['REMOTE_ADDR'];
$bip = $_SERVER['HTTP_X_FORWARDED_FOR'];
$agent = $_SERVER['HTTP_USER_AGENT'];
session_start();

// Do this each time the user successfully logs in.
$_SESSION['ident'] = hash("sha256", $aip . $bip . $agent);

// Do this every time the client makes a request to the server, after authenticating
$ident = hash("sha256", $aip . $bip . $agent);
if ($ident != $_SESSION['ident'])
{
    end_session();
    header("Location: login.php");
    // add some fancy pants GET/POST var headers for login.php, that lets you
    // know in the login page to notify the user of why they're being challenged
    // for login again, etc.
}

Для цього потрібно зафіксувати «контекстуальну» інформацію про сеанс користувача, інформацію, яка не повинна змінюватися протягом життя одного сеансу. Користувач не буде одночасно за комп’ютером у США та Китаї, правда? Отже, якщо IP-адреса раптово змінюється в межах одного сеансу, що сильно передбачає спробу викрадення сеансу, ви захищаєте сеанс, припиняючи сеанс і змушуючи користувача повторно пройти автентифікацію. Це перешкоджає спробі злому, нападник також змушений увійти, замість того, щоб отримати доступ до сеансу. Повідомте користувача про спробу (відмовляйте її трохи), і vola, Трохи роздратований + поінформований користувач, і їх сеанс / інформація захищена.

Ми використовуємо User Agent та X-FORWARDED-FOR, щоб зробити все можливе, щоб захопити унікальність сеансу для систем за проксі-серверами / мережами. Можливо, ви зможете використовувати більше інформації, ніж це, сміливо проявляйте творчість.

Це не на 100%, але досить чортово ефективно.

Ви можете зробити більше, щоб захистити сеанси, втратити чинність, коли користувач покине веб-сайт і повернеться змусити їх знову ввійти. Ви можете виявити, що користувач залишає і повертається назад, захопивши порожній HTTP_REFERER (домен був введений у рядку URL-адреси) або перевірити, чи значення в HTTP_REFERER дорівнює вашому домену чи ні (користувач натиснув зовнішню / створену посилання, щоб перейти до свого сайт).

Закінчіть сеанси, не дозволяйте їм залишатись дійсними нескінченно.

Не покладайтеся на файли cookie, вони можуть бути викрадені, це один з векторів нападу для викрадення сесії.


3
Я зіткнувся з ситуацією, коли певний (досить великий, але технічно відсталий) провайдер час від часу змінює IP-адресу браузера користувача на основі перенаправлення з'єднань своїх користувачів. Це зробило перевірку REMOTE_ADDR поверненням помилкових негативів для нас.
goofballLogic

Навіщо турбуватися створювати хеш? $_SESSION['ident'] = $aip . $bip . $agent;було б так само безпечно.
Ден Брей

2
Якщо у вас є користувачі мобільних пристроїв, які користуються вашим веб-сайтом у дорозі та переходять від однієї точки доступу до іншої, їхні IP-адреси будуть постійно змінюватися, і вони продовжуватимуть виходити зі свого акаунта.
Kareem

А як щодо проксі та VPN? Усі, хто використовує проксі-сервер TOR, будуть постійно виходити зі своїх облікових записів .. фактично кожні кілька хвилин.
Бредлі

Навіть якщо ви не помічаєте це, IP-адресою клієнт може маніпулювати IP-адресами, тож це не дуже допоможе відвернути зловмисника.
Бредлі

9

Спробуйте протокол захищеного файлу cookie, описаний у цьому документі Лю, Ковач, Хуанг та Гауда:

Як зазначено в документі:

Протокол безпечного файлу cookie, який працює між клієнтом і сервером, повинен надавати наступні чотири послуги: автентифікацію, конфіденційність, цілісність та антивідтворення.

Що стосується простоти розгортання:

З точки зору ефективності наш протокол не передбачає будь-якого пошуку бази даних або криптографії відкритого ключа. Що стосується можливості розгортання, наш протокол може бути легко розгорнутий на існуючому веб-сервері, і він не потребує змін у специфікаціях cookie в Інтернеті.

Якщо коротко: він безпечний, легкий, працює для мене просто чудово.


9
Ваше посилання є специфікацією протоколу - чи є у вас посилання на реалізацію? Це було б чудово - дякую.
Адам

9

Немає можливості запобігти викрадення сеансу на 100%, але при певному підході ми можемо скоротити час, коли зловмисник захопить сеанс.

Спосіб запобігання викрадення сеансу:

1 - завжди використовувати сеанс із сертифікатом ssl;

2 - надсилати файли cookie сеансу лише із httpsly, встановленою на true (запобігати JavaScript для доступу до файлу cookie сеансу)

2 - використовувати ідентифікатор відновлення сеансу при вході та виході (зверніть увагу: не використовуйте для відновлення сеансу при кожному запиті, тому що якщо у вас є послідовний запит ajax, ви маєте шанс створити кілька сеансів.)

3 - встановити тайм-аут сеансу

4 - зберігайте агент користувача браузера у змінній $ _SESSION порівняння з $ _SERVER ['HTTP_USER_AGENT'] при кожному запиті

5 - встановіть cookie-маркер і встановіть час його дії на 0 (поки браузер не закриється). Відновлюйте значення файлу cookie для кожного запиту. (Для запиту ajax не відновлюйте файл cookie). EX:

    //set a token cookie if one not exist
    if(!isset($_COOKIE['user_token'])){
                    //generate a random string for cookie value
        $cookie_token = bin2hex(mcrypt_create_iv('16' , MCRYPT_DEV_URANDOM));

        //set a session variable with that random string
        $_SESSION['user_token'] = $cookie_token;
        //set cookie with rand value
        setcookie('user_token', $cookie_token , 0 , '/' , 'donategame.com' , true , true);
    }

    //set a sesison variable with request of www.example.com
    if(!isset($_SESSION['request'])){
        $_SESSION['request'] = -1;
    }
    //increment $_SESSION['request'] with 1 for each request at www.example.com
    $_SESSION['request']++;

    //verify if $_SESSION['user_token'] it's equal with $_COOKIE['user_token'] only for $_SESSION['request'] > 0
    if($_SESSION['request'] > 0){

        // if it's equal then regenerete value of token cookie if not then destroy_session
        if($_SESSION['user_token'] === $_COOKIE['user_token']){
            $cookie_token = bin2hex(mcrypt_create_iv('16' , MCRYPT_DEV_URANDOM));

            $_SESSION['user_token'] = $cookie_token;

            setcookie('user_token', $cookie_token , 0 , '/' , 'donategame.com' , true , true);
        }else{
            //code for session_destroy
        }

    }

            //prevent session hijaking with browser user agent
    if(!isset($_SESSION['user_agent'])){
        $_SESSION['user_agent'] = $_SERVER['HTTP_USER_AGENT'];
    }

    if($_SESSION['user_agent'] != $_SERVER['HTTP_USER_AGENT']){
      die('session hijaking - user agent');
    }

Примітка: не регенеруйте файли cookie токена за допомогою запиту ajax: код, наведений вище, є прикладом. Примітка: якщо користувачі виходять, маркер cookie повинен бути знищений, а також сеанс

6 - не дуже корисно використовувати ip користувача для запобігання викрадення сеансу, оскільки деякі користувачі ip змінюються з кожним запитом. ЩО ВПЛИВАЮТЬ ВАЛІДНІ КОРИСТИКИ

7 - я особисто зберігаю дані сеансу в базі даних, саме від вас залежить, який метод ви застосуєте

Якщо ви виявите помилку в моєму підході, будь ласка, виправте мене. Якщо у вас є більше способів запобігти сеансовому походженню, будь ласка, скажіть мені.


привіт, я намагаюся запобігти викрадення сеансу (в ASP.NET) і розглянув усі запропоновані вище кроки u. Це приблизна робота, але коли я використовую режим InPrivateBrowsing / інкогніто браузера, сеанс викрадено. Чи можете ви, будь ласка, запропонувати будь-яку додаткову річ, яку потрібно додати в рядок sessionId?
Vishwanath Mishra

4

Переконайтесь, що ви не використовуєте цілісні цілі числа для ідентифікаторів сеансу. Набагато краще використовувати GUID або інший довгий випадково створений символьний рядок.


3

Існує багато способів створити захист від викрадення сеансу, проте всі вони або знижують задоволеність користувачів, або не є безпечними.

  • Перевірки IP та / або X-FORWARDED-FOR. Вони працюють і досить безпечні ... але уявіть собі біль користувачів. Вони приходять в офіс з WiFi, отримують нову IP-адресу і втрачають сесію. Перейдіть у систему знову.

  • Перевірки агента користувача Як і вище, нова версія браузера відсутня, і ви втрачаєте сеанс. Крім того, їх справді легко "зламати". Хакерам банально надсилати фальшиві рядки UA.

  • localStorage маркер. Під час входу генеруйте маркер, зберігайте його у сховищі браузера та зберігайте його в зашифрованому файлі cookie (зашифрованому на стороні сервера). Це не має побічних ефектів для користувача (localStorage зберігається через оновлення браузера). Це не так безпечно - як просто безпека через неясність. Крім того, ви можете додати деяку логіку (шифрування / розшифрування) до JS, щоб ще більше її приховати.

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


1

Звернемо увагу, що під час фази входу клієнт і сервер можуть домовитися про таємне значення солі. Після цього сервер надає значення підрахунку з кожним оновленням і очікує, що клієнт відповість хешем (секретна сіль + кількість). Потенційний викрадач не має жодного способу отримати це таємне значення солі і, таким чином, не може генерувати наступний хеш.


3
Але як ви хочете зберігати цю сіль на стороні клієнта, щоб ніхто не міг її вкрасти?
Dcortez

1

AFAIK об'єкт сеансу недоступний клієнту, оскільки він зберігається на веб-сервері. Однак ідентифікатор сеансу зберігається як Cookie, і він дозволяє веб-серверу відстежувати сеанс користувача.

Щоб запобігти викрадення сеансу за допомогою ідентифікатора сеансу, ви можете зберігати хешовану рядок всередині об’єкта сеансу, зроблений за допомогою комбінації двох атрибутів, віддаленого додавача та віддаленого порту, до яких можна отримати доступ на веб-сервері всередині об'єкта запиту. Ці атрибути прив'язують сеанс користувача до браузера, де користувач увійшов.

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

Нижче наведено код, який я реалізував і протестував, копіюючи ідентифікатор сесії з одного сеансу в інший. Це працює досить добре. Якщо є лазівка, дайте мені знати, як ви її моделювали.

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    HttpSession session = request.getSession();
    String sessionKey = (String) session.getAttribute("sessionkey");
    String remoteAddr = request.getRemoteAddr();
    int remotePort = request.getRemotePort();
    String sha256Hex = DigestUtils.sha256Hex(remoteAddr + remotePort);
    if (sessionKey == null || sessionKey.isEmpty()) {
        session.setAttribute("sessionkey", sha256Hex);
        // save mapping to memory to track which user attempted
        Application.userSessionMap.put(sha256Hex, remoteAddr + remotePort);
    } else if (!sha256Hex.equals(sessionKey)) {
        session.invalidate();
        response.getWriter().append(Application.userSessionMap.get(sessionKey));
        response.getWriter().append(" attempted to hijack session id ").append(request.getRequestedSessionId()); 
        response.getWriter().append("of user ").append(Application.userSessionMap.get(sha256Hex));
        return;
    }
    response.getWriter().append("Valid Session\n");
}

Я використовував алгоритм SHA-2 для хешування значення на прикладі, наведеному в SHA-256 Hashing at baeldung

Чекаємо ваших коментарів.


@zaph Вибачте, але я не додав відповіді, щоб отримати респ. Справа не в шифруванні SHA-2. Але той факт, що мені вдалося виявити використання ідентифікатора cookie сеансу іншого користувача в сеансі іншого користувача, тобто викрадення сеансу, як у вихідному питанні. Я перевірив своє рішення і виявив, що він працює. Але я не є експертом з цього питання, тому я хотів би, щоб громада перевірила, чи достатньо хороша моя відповідь. Можливо, ви можете побачити, що робить мій фрагмент коду, і вирішити, чи відповідає він на це питання. Дякую!
Jzf

@zaph Дякую за вказівку на помилку. Я оновив свою відповідь відповідно до вашої пропозиції. Будь ласка, зніміть свій голос, якщо ви вважаєте, що відповідь корисна.
Jzf

0

Щоб зменшити ризик, ви також можете пов’язати початковий IP з сеансом. Таким чином зловмисник повинен знаходитися в одній приватній мережі, щоб мати можливість використовувати сеанс.

Перевірка референтних заголовків також може бути варіантом, але вони легше підробляються.


7
ні, ви не можете використовувати початковий IP, оскільки він може змінюватися - або через динамічні IP-адреси, змінені під час тимчасового відключення користувача, або через (неявне або явне) використання проксі-ферми. Крім того, викрадачі сеансу, що надходять від одного і того ж провайдера, можуть використовувати той самий проксі-сервер і IP-адресу як законний користувач ...
Олаф Кок

1
PHP-Nuke має хорошу сторінку про підхід до сеансу, і вони детально розмовляють про те, як підключення до ІР не працює з усіма провайдерами phpnuke.org/…
Sembiance

4
Зміна Ip часто зустрічається у провайдерів мобільного Інтернету. З Vodafone, мій IP змінюється ВСІМ запитом.
Блез

1
Якийсь старий пост, але щоб продовжити це. Як згадується, ІР - це погана ідея. Як вже згадувалося, користувачі мобільних телефонів схильні переходити в IP-адреси. Деякі Інтернет-провайдери в минулому також мали роумінгові IP-адреси (наприклад, AOL), однак цей підхід стає все більш популярним зараз через дефіцит IPv4 IP-адрес. До таких провайдерів належать Plus net та BT
Пітер

-15

Захистити:

$ip=$_SERVER['REMOTE_ADDER'];
$_SESSEION['ip']=$ip;

12
Я не бачу, що ти тут робиш.
samayo
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.