Безопасность на хабре

    А расскажу я вам сегодня про фичу, которую совсем недавно мне понадобилось сделать в одном проекте. А именно о функции «Запомнить меня на этом компьютере». Смешно не правда ли? Что же тут сложного? Сохраняй куки на две недели, месяц, потом вытаскивай и восстанавливай сессию. Ага, всё просто. А я встал в тупик. Меня часто ставят в тупик самые простые вещи.Так что же меня смутило…

    А какие куки хранить, задумался я. Id пользователя и хэш пароля? Именно эти данные хранятся в куках, например, на vkontakte.ru. Как-то для меня слишком в лоб и по-детски. Для чего же тогда в базе хранить хэш пароля? Правильно, чтобы злоумышленник, заполучив этот самый хэш, не смог им воспользоваться или, по крайней мере, очень долго бы его расшифровывал. Получается vkontakte — рай для злоумышленников. Украл хэш, загнал его в куки и улыбнулся=)

    И решил посмотреть я, как же это реализовано на хабре. И нашёл только одну куку PHPSESSID. Получается, хабр хранит только идентификатор сессии (время жизни куки истекает где-то в 2047 году), а сама сессия на сервере имеет увеличенное время жизни (около месяца, насколько я понял). Вот то что мне нужно, подумал я. Просто, лаконично и со вкусом. Одна стандартная кука.

    Но кое-что меня опять смутило. И я провёл эксперимент. Я разлогинился с хабра и создал ручками в браузере эту самую куку PHPSESSID со значением 1111111111. Потом залогинился. Кука и её значение остались такими же, т.е. PHPSESSID=1111111111. Дальше на другом компьютере с другим ip и в другом браузере я опять создал куку PHPSESSID=1111111111. И опаньки, я залогинен на хабре=))

    А теперь маниакальный сценарий использования этого метода злоумышленником. Приходит злоумышленник в общественную точку доступа (интернет-кафе) и прописывает на комьютере (или на всех) куку PHPSESSID с известным ему значением. Потом идёт домой и пишет простой скрипт, который обращается к хабру и проверяет сессию с этой кукой раз в n минут. И идёт пить пиво. В интернет-кафе приходит активный хабраюзер Вася и логинится на хабре. Через n минут он обнаруживает, что его выкинуло с сайта и обратно войти он уже не может. А злоумышленник покупает себе ещё пива. Занавес.

    Может сценарий ну просто чересчур маниакальный, да и кому может понадобиться чей-то аккаунт на хабре? Ну во-первых, недовольных своей кармой много (например, я=))). Во-вторых, такой метод хранения сессии может быть реализован и на более серьёзных сервисах.

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

    А ты перестраховался, %username%?

    Similar posts

    Ads
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More

    Comments 68

    • UFO just landed and posted this here
        +2
        Старая поговорка «Все замкИ — от добрых людей».
        Битва меча и щита не нами начата и не при нас завершится, и в случаях, если выбирать между безопасностью и удобством пользования, ИМХО, стоит все-таки думать об удобстве (безотносительно к этому способу).
        А за бдительность — респект :)

          +3
          Напоминает байку о хакере и солонках с авторизацией, дозатором, пропусканием соли только в одну сторону.
          • UFO just landed and posted this here
              +1
              Да фиг его знает — как-то не приходилось особо сталкиваться с ними, меня и моя убунта вполне устраивает :)
                0
                Они не удобные (по край ней мере не все)
              0
              Занятно.

              Но если бы я был Васей, я поставил бы кейлоггер.
                0
                в смысле, если бы вы были злоумышленником? но тут даже кейлоггер не нужен=)
                • UFO just landed and posted this here
                    +2
                    Вообще я за прозрачную параноидальную безопасность. Это интересно. Надо будет заняться
                    • UFO just landed and posted this here
                    0
                    Храни хеш IP
                      0
                      А если у меня он динамический? Прощай автологин?
                        +1
                        не, хеш ip не вариант
                      –7
                      Спасибо за наблюдения, но, я к примеру интернет-кафе не пользуюсь, да и не прижились они особо в нашем городе. А хабр читаю в RSS и только с домашнего компа.
                        –6
                        Как вариант — можно хранить в сессии IP и сравнивать его с IP машины, от которой пришел запрос. Если разные — логаут автоматом. Так во всех своих проектах делаю.
                          0
                          Насколько я помню раньше на хабре можно было привязать сессию к ip, но потом эта функция пропала. Ещё есть прокси сервера через которые могут сидеть десятки хабраюзеров=) А ещё ip машины можно подделать. Ничему нельзя доверять. IP и User Agent это просто дополнительные методы защиты.
                            +2
                            Спасибо, но в мире динамических IP и постоянных сбросов Vist'ой wi-fi соединения я задолбаюсь логиниться каждый раз =)
                              0
                              Ну так как раз ради таких целей подобный функционал и делаю опциональным
                            +2
                            Я в своем проекте храню в куках идентификатор сессии, а на стороне сервера в сессии прописан хэш IP и user-agent. Таким образом, на другом компе или в другом браузере сессия не будет действительна.
                              –1
                              Я по user_agent смотрю и регенерю id сессии через три запроса. Вот только проблема, при ajax запросах куку поменять нельзя, так что нада акуратно.
                                +9
                                setcookie('remember', $user['id'].'|'.md5($user['email'].$user['pass'].$user['name']), ...);

                                я так делаю :)
                                  0
                                  Галочки «запомнить мой IP» теперь нету — безопасность ниже. Но спасает постоянная привязка к почтовому ящику.
                                    +1
                                    Долгое время я работал с mysql сессиями.
                                    Но на одном небольшом проекте решил использовать php сессии и озадачился проблемой безопастности.
                                    Нарисовалось такое решение
                                    if($_SESSION['user_browser']!=$_SERVER['HTTP_USER_AGENT'])
                                    {
                                    //$_SESSION = array();
                                    session_unset();
                                    //session_destroy();
                                    session_regenerate_id();
                                    //$ids=session_id();
                                    $_SESSION['last_time']=time();
                                    $_SESSION['user_ip']=$_SERVER['REMOTE_ADDR'];
                                    $_SESSION['user_browser']=$_SERVER['HTTP_USER_AGENT'];
                                    $_SESSION['count'] = 1;
                                    }
                                    сравнивать можно и другие параметры, но мне важнее браузер.
                                      +1
                                      Эта защита имеет смысл до тех пор, пока злоумышленник не знает что надо подделывать HTTP_USER_AGENT
                                        0
                                        у меня спецефический wap-сайт и мне этой защиты хватает, благо узнать какой юзер агент у пользователя очень проблематично
                                          0
                                          Обратите внимание на Wurfl.
                                            0
                                            обращал и что? как это связано с проблемами авторизации?
                                              0
                                              благо узнать какой юзер агент у пользователя очень проблематично

                                              Я имел ввиду, что определять юзер агент станет гораздо легче. Вы же на трудности жаловались.
                                                +1
                                                я не жаловался, я это сказал к тому, что мир wap- браузеров более обширный чем WEB — браузеров. И подделать его сложнее потому что злоумышленнику сложнее узнать какой у пользователя был браузер
                                                  –1
                                                  злоумышленнику достаточно перебрать все браузеры, пускай их будет для всех операционок около 100, это совсем не много
                                                    0
                                                    вот Вам то как раз и надо скачать wurfl и посмотреть сколько там мобильных браузеров
                                                      0
                                                      спорить не буду, я не знаю сколько всего мобильных браузеров. в любом случае их не так много, чтобы при особом желании их нельзя было подобрать
                                                        0
                                                        ага, только это список в основном поисковых роботов, спам ботов и другой нечисти
                                        0
                                        А вообще, если пользователь хочет запомнить себя на сайте, то он должен оставить у себя на компьютере какую-то информацию, по которой сервер будет его авторизовывать. Раз эта инфа на его компьютере — значит злоумышленник может ее всегда получить, если у него есть доступ к компьютеру. Не надо быть параноиками, если надо будет украсть логин и пароль — всегда украдут.
                                          0
                                          Разьве?! Инфа, по которой сервер авторизует (кука «SID», например) и пароль — разные вещи. И по SID'у выяснить пароль в проектах с грамотной безопасностью, как правило, невозможно.
                                            0
                                            Только в данном случае, правильно не «авторизует», а «аутентифицирует».
                                          +2
                                          Для своего проекта я однозначно решил — можно использовать аккаунт одновременно только с одного компьютера (в отличии от того же вконтакта). Именно поэтому при ре-логине прописывается новое значение сессии.
                                          А в куках хранится только ID и значение сессии.
                                          Проверяется просто — значение сессии и IP в БД в записи с ID из куков.

                                          А-ля
                                          select * from table where session = '...' and ip = '...' where id = '...'

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

                                          Даже при использовании соли в хеше, имея несколько хешей от паролей, есть теоритическая возможность достать пароли. Вопрос во времени. Если организовать динамическую соль — невозможно достать пароль, не зная механизм образования соли.
                                          ИМХО, все равно хранение пароля в куках не приводит ни к чему хорошему.
                                            0
                                            Вот то же самое на «вподземке». Приходится перелогиниваться дома, на работе, в институте и с ноутбука.
                                              +1
                                              а что мешает вам хранить пароль в браузере?
                                                0
                                                Храню, просто мне свой аккаунт там не так дорог.
                                                0
                                                Я не спорю, что это зависит от специфики проекта.
                                                Но если в первую очередь безопасность, а не юзабилити — то приходится делать именно так )
                                              0
                                              А разве продолжительное хранение сессии на сервере в течении месяца это просто и лаконично??? Особенно если к сессии какие-нибудь объекты привязаны… По идее за такое должны по рукам бить.
                                                +1
                                                Возможно, если бы сессия создавалась для любого, даже незарегенного пользователя. Если же сессия создается только для зарегестирировавшихся юзеров, то почему нет. Мне этот вариант нравится. Так кстати реализовано не только на хабре.
                                                +3
                                                Да, обычно в куку/сессию кладут какой-нить уник юзера(id, например), и обязательно USER_AGENT. Опционально в голову приходила идея вытаскивать с помощью whois подсеть текущего ip-адреса и хранить эту подсеть вместо ip, таким образом злоумышленнику помимо знания значения куки нужно будет иметь идентичный user agent и при этом находится в той же подсети, что и юзер. А это уже почти что «ломом ломать».
                                                  0
                                                  красота.
                                                    0
                                                    Иногда еще полезно хранить не просто IP, а еще вдобавок и X-FORWARDED-FOR ибо буквально недавно наткнулся что например nichost.ru REMOTE_ADDR указывает на какой-то IP их внутренней сети (да еще и с динамическим портом каждый запрос). И если хранить просто ip — для всех сессий он будет совпадать.
                                                      0
                                                      Не все прокси оставляют x-forwarded-for =( А вообще конечно, при любой работе с IP все грамотные люди проверяют x-forwarded-for а уж потом remote_addr.
                                                      +1
                                                      Я тоже когда то так завис. Сделал просто:
                                                      1. Генерится рандомный хеш
                                                      2. Хеш заносится в базу данных и в куку
                                                      3. Если не существует сессионной переменной, из куки вытягивается хеш, сравнивается с хешем из базы данных.
                                                      4. Все ок! Создается новый хеш. Не ок — отсылаешься на страничку логина.

                                                      Как то так
                                                        +1
                                                          +2
                                                          https + любая аутентификация (даже тупейшая basic) или куки спасут отца русской демократии

                                                          http по-дефолту лох
                                                            0
                                                            согласен. сам в свое время перебирал разные способы запоминания пользователей.
                                                            если нужна действительно защита, то без https не обойтись.
                                                            +2
                                                            Такие параноики как я делают например так:

                                                            $hash1=md5($login+microtime(true));
                                                            $hash2=crypt($uid+$_SERVER['REMOTE_ADDR'],$uid+$_SERVER['REMOTE_ADDR']);

                                                            $db = myPDO:: getInstance();

                                                            $query = $db->prepare('UPDATE `users` SET `user_hash`=: user_hash, `last_ip`=: last_ip WHERE id=: uid');
                                                            $query->bindParam(': uid',$uid);
                                                            $query->bindParam(': user_hash',$hash1);
                                                            $query->bindParam(': last_ip', $_SERVER['REMOTE_ADDR']);

                                                            if ($query->xcute(null,'update_user_data',__LINE__,__FILE__))
                                                            {
                                                            setcookie('uid', $uid,(time()+24*14*3600), '/','.'.SITE_DOMAIN);
                                                            setcookie('unh', $hash1,(time()+24*14*3600),'/','.'.SITE_DOMAIN);
                                                            setcookie('uih', $hash2,(time()+24*14*3600),'/','.'.SITE_DOMAIN);
                                                            }
                                                            • UFO just landed and posted this here
                                                              • UFO just landed and posted this here
                                                                  0
                                                                  проверка логина по регулярке есть в скрипте выше, просто сюда не стал выносить :)
                                                                  • UFO just landed and posted this here
                                                                      0
                                                                      Вы правы, и об этом написано в комментарии ниже :)
                                                                      • UFO just landed and posted this here
                                                                    0
                                                                    а про стринг+флоат, вы правы, поправлю.
                                                                    Век живи, век учись :)
                                                                +1
                                                                Надо просто вводить двойной пароль(PIN и PUK вроде). Один закрытый, другой открытый. По открытому осуществляться авторизация, по закрытому изменение критичных настроек(те настройки, с помощью которых можно получить закрытый пароль) и открытого пароля. Закрытый пароль нигде, на стороне клиента не храниться. Даже если открытий пароль похищен, это можно исправить залогиневшись по закрытому паролю.

                                                                Как только вы используете куки для авторизации вы автоматически даете способ похитить пароль. Не даром ведь все сервисы предупреждают о том, что лучше не логиниться по кукам из интернет кафе…
                                                                • UFO just landed and posted this here
                                                                    +1
                                                                    Хранить в куке только идентификатор сессии это нормально. Это из моего программистского детства ) Но если от пользователя пришла кука с сессией, а в базе ее нет, то звиняйте, вводите пароль. Ввели пароль — получите НОВУЮ сессию с НОВЫМ идентификатором и, соответственно, НОВУЮ куку. Этот велосипед я для себя открыл сам. phpBB хранил и хранит, наверное, логин и пароль пользователя (шифрованный), а когда получает куку, логинит пользователя автоматом. Не оживляет сессию, а именно логинит. Я это не одобрил и придумал свое. А так как не понимал как работает встроенный в РНР механизм сессий, то придумал свой.

                                                                    Если вы не ошиблись и хабр работает именно так, то это просто пипец.
                                                                      +1
                                                                      Интересно.
                                                                      Ещё интересней было бы узнать, как с этим борются другие крупные сервисы и движки CMS/форумов, фреймворки.

                                                                      Радует, что разработчики на Хабре постепенно погружаются в темы и начинают выкапывать вещи, которые всем надо бы знать. Фактически, сообщество повторяет эволюционный путь развития Программирования вцелом. Англоязычный интернет ушёл далеко вперёд, теперь русскоязычный идёт следом :-)
                                                                      Кажется Хабр становится полезней ))

                                                                      PS: Кстати, хорошим тоном является передача информации разработчикам за день-два до публикации уязвимости (а это на мой взгляд таки уязвимость).
                                                                        +4
                                                                        ШОЙТАНАМА!!!
                                                                        Тут интересная дискуссия проскочила, и я там показательно спалил свой пароль )
                                                                        Кто-то решил проверить. Зашел под моим аккаунтом и написал коммент.
                                                                        Вся шутка в том, что меня не выкинуло, моя сессия не обнулилась.
                                                                        Товарищи!!! Так нельзя!!!
                                                                          +2
                                                                          Но и это фигня. После того как тот товарищ разлогинился, моя сессия до сих пор жива! Я в шоке!!!
                                                                          Я в криком кричу: АХТУНГ!!!
                                                                            +1
                                                                            ЧТО Я НАДЕЛАЛ!!!

                                                                        Only users with full accounts can post comments. Log in, please.