Пользователь
0,0
рейтинг
24 сентября 2008 в 02:41

Разработка → Засаливание паролей

Итак, каким же образом обеспечивается безопасность на нынешних веб-ресурсах? Хешированием паролей алгоритмом md5. Вроде бы всё здорово и замечательно — md5 есть функция необратимая и пароли, хранимые в виде таких хэшей, взломать нельзя, даже если злоумышленник получил доступ к базе. Ан нет! Вспоминаем про Rainbow-таблицы и прощаемся с мыслью о полной безопасности хранения паролей в таком виде. Та как же их тогда шифровать? Алгоритмы востановимого шифрования с ключами тоже не панацея, да и системных ресурсов сии функции кушают немало...
Вопрос: Так как же, не в ущерб производительности, обезопасить md5 хэши от Rainbow-таблиц?
Ответ: соль.
Суть метода заключается в следующем. А кто нам мешает при генерации хэша, помимо голого md5, ввести ещё каки-либо операции над паролем? Правильно, никто :) Тогда новый, "засоленый", хэш определяем следующим образом (классическая схема; используется, например, в *nix'ах ):
хэш = соль + md5(соль+пароль)
или на PHP:
function md5WithSalt($pass, $salt = "someDefaultSalt"){<br>
$hash = $salt;<br>
$hash .= md5($salt.$pass); <br> return $hash;<br>}

Таким образом мы получаем хэш, увеличенной длинны с конкатенацией пароля с той же самой солью. Естественно, что в таком случае генерацией Rainbow-таблиц, именно для этой соли, никто заниматься не будет. В принципе, достаточно ограничиться конкатенацией соли с паролем и от этого брать md5 — всё равно результат взломать, даже зная соль, практически невозможно.

Дальше -больше


"Подперчить" сей метод можно добавив динамики в генерацию соли т.е. при правильном вводе пользователем его пароля, динамически заменять соль на новую, например, при каждом 10-ом логине или каждую неделю. Кстати, если соль сделать из 8-ми абсолютно случаных символов, то при взломе такого хэша, система взлома может распознать его как SHA-хэш и априорно начнёт двигаться в ложном направлении.
А можно, коли руки чешутся поминусовать, это как-то обосновывать в комментариях? Спасибо.
Алексей Матвеев @mms
карма
17,4
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

Комментарии (186)

  • НЛО прилетело и опубликовало эту надпись здесь
    • +38
      Понял, в чем соль, %username%? :)
    • +1
      Существует отличная библиотека phpass, которая уже интегрирована в phpBB, WP, а также модуля для Drupal.
      Полное название: Portable PHP password hashing framework
      www.openwall.com/phpass/
  • +2
    Ответ: соль.
    Может SHA? Или другое? На md5 жизнь не кончается.
    • НЛО прилетело и опубликовало эту надпись здесь
      • +1
        А при чем здесь туннелирование? ;)
        • НЛО прилетело и опубликовало эту надпись здесь
          • 0
            Сорри, не знал, что это называют туннелированием. Встречал только «поиск коллизий».
          • 0
            можно какой-то материал про етот способ?
            • НЛО прилетело и опубликовало эту надпись здесь
      • +1
        вот и я не понял, причем здесь туннелирование? Алгоритмы SHA (SHA1, SHA256, SHA384, SHA512) дают точно такой же хэш, как и md5, только не 128 битный, а 160, 256, 284 512.
        • НЛО прилетело и опубликовало эту надпись здесь
    • –3
      А чем SHA лучше md5? Только тем, что занимает больше места в БД? Да и Rainbow-таблицы для SHA не вчера появились…
  • +6
    статья ни о чем…

    >каким же образом обеспечивается безопасность на нынешних веб-ресурсах
    уж необязательно, в том же ВКонтакте пароли хранятся в открытом виде, никто не страдает. цель применения salt для хэширования — не дать возможности взломать хэш при сливе базы за приемлимое время (для веб-приложений)

    >Хешированием паролей алгоритмом md5
    не только md5, есть sha1 и еще куча других хэшей.

    > «Подперчить» сей метод можно добавив динамики в генерацию соли
    разумная идея

    > если соль сделать из 8-ми абсолютно случаных символов
    не любыми, а только буквами a-f и цифрами 0-9

    >система взлома может распознать его как SHA-хэш априорно начнёт двигаться в ложном направлении.

    скажите, а в каком направлении двигаться для этого хэша xMpCOKC5I4INzFCab3WEmw?
    • +1
      > система взлома может распознать его
      обычно не система взлома выбирает тип хэша, а человек.
      для популярных движков известны алгоритмы хэширования. если их не знать, то перебор не имеет смысла
    • НЛО прилетело и опубликовало эту надпись здесь
      • 0
        str_replace(«=», «», base64_encode(md5(«1», true)))
        • 0
          Вот кстати я про base64 и подумал, но вы внаглую паддинг стырили; Р
    • –1
      >в том же ВКонтакте пароли хранятся в открытом виде
      Вот это очень интересно… И зачем они тогда в куки их md5-хэш пишут?

      >есть sha1 и еще куча других хэшей.
      Ага, и MySQL 64 и 160 битные. Только тут одна проблема — для них тоже существуют Rainbow-таблицы.

      >не любыми, а только буквами a-f и цифрами 0-9
      Простите великодушно — суть статьи не в том, что бы, разбрасываясь кучей терминов и подробностей, объяснять нормальные вещи. Если быть снобом и заниматься «распальцовокой» (простите, но другого не подобрал), то статья могла получиться нечитаемой. Поэтому здесь и не описывается ни способ генерации Rainbow-таблиц, ни отличия между симметричным и асимметричным шифрованием, ни оценка процессорного времени для того или иного алгоритма.

      >скажите, а в каком направлении двигаться для этого хэша xMpCOKC5I4INzFCab3WEmw
      Алгоритмов с 88 битным шифрованием, лично я не знаю.
      • 0
        >>в том же ВКонтакте пароли хранятся в открытом виде
        >Вот это очень интересно… И зачем они тогда в куки их md5-хэш пишут?
        Если честно, не знаю как хранятся пароли в их базе, но отличие между куками и базой весьма существенное — второе не гуляет по сети в открытом виде. И куки намного легче стащить. Поэтому вполне логично, что в куки должен попадать только хэш. А в базе — пока её не стащат, вообще всё равно, что там хранится.
        • 0
          Вообще то логично, что в куки не должно попадать хеша пароля ни при каких условиях
      • 0
        если восстанавливать пароль в контакте, то он приходит в открытом виде.
        только не говорите, что они восстанавливают из хэша пароль…

        > И зачем они тогда в куки их md5-хэш пишут?
        уж сложилась у них такая схема авторизации. а хэш лежит, чтобы нельзя было зайти под аккаунтом, если сперли куки. хотя это не спасает.
        • 0
          Вот если б кто-то написал статью про авторизацию по кукам, я знаю что там кроме соли можно добавить юзер-агента и т.д. Как лучше всего реализовать такую авторизацию?
          • +1
            Лучше всего в куках хранить случайно сгенерированный ключ, однозначно позволяющий определить сессию. конкретного пользователя. Причём менять его после нескольких запросов или по прошествии определённого времени.
            • 0
              случайно сгенерированный ключ, однозначно позволяющий определить сессию. конкретного пользователя.
              Это такой длинный синоним для «Идентификатор сессии»? Стандартный механизм для любого web-фреймворка же!
              На вКонтакте эта кука называется remixsid (remix session id).
  • +4
    Про соль я и так знал в тех же общих терминах, значительно интереснее было бы узнать различные способы её применения. А так получается статья «оказывается, есть такая технология!». Это вполне годится для личного блога, но не для блога Web-разработка. Тут уже хочется чего-то более развёрнутого и обоснованного.
    Чем данная статья полезнее коротенькой заметки в Википедии?
    • 0
      А что тут расписывать? «Всё гениальное — просто» ©
      • +4
        Я же не о соли говорю, а о статье. А она не проста и не гениальна.
        Тут надо рассуждать так: есть разработчики, которые знают о соли и, возможно, используют её, им ничего не надо писать, есть разработчики, которые ничего не знают о соли, им надо описать её достоинства и способы использования. Заденет ли эта статья сердца последних? Достаточна ли она для того, чтобы понять, в чём соль?
        • –1
          по-моему тут как раз написано, как ее можно использовать. а где — и так понятно. Достоинства тоже по-моему очевидны.

          я вот, если честно, только сейчас узнал, что это называется «соль»
          • –1
            Ещё это называется «закваска» или «затравка», классический перевод буквальный — «соль». Можно встретить «вектор шифра».
    • 0
      Вот тут еще более подробно описано про хранение паролей с солью
      Даже с картиками:)

      Знакомая принимала участие в разработке одной небольшой системы для Билайна.
      Так вот там пароли хранились в открытом виде, но потом их вроде засолили.
    • +2
      Я про соль уже писал в habrahabr.ru/blogs/infosecurity/39653/
      Там есть и про пароли, и про соль, и про ее применение.
  • +2
    Лю-ю-юди. Обьясните мне — почему все забивают на crypt()?
    • 0
      Цитата:
      «Стандартная функция crypt() на основе DES копирует salt в начало возвращаемой строки. Кроме того, она использует только первые восемь символов строки str, поэтому для различных строк, первые восемь символов в которых совпадают, будет возвращаться один и тот же результат (при использовании одинаковых salt-последовательностей).»
  • +2
    я и сам никогда чистый md5 не применял, как минимум дважды или добавлять что-то свое к паролю. Не знал что это называется солением.
    +
  • 0
    Блин, а я даже не догадался.
  • 0
    В дефалтовом IPB толку от этой соли немного. Да, для каждого пользователя она генериться своя, но храниться то рядышком в той же таблице users. С одной стороны, если враги уперли только базу, а сорс остался недоступен, то ворогам будет довольно сложно подобрать пасс к тому или иному пользователю, но только при условии что сама маска генерации хэша с сальтом изменена программистом. Т.е. по дефалту, например, md5($salt.$pass); а хитрый программер залез в сорсы и поменял md5(md5($pass.$salt).'Я ЛЮБЛЮ ЛЮДЕЙ'); в этом случае можно долго биться головой о стену, а если не поменял, то тупо качается версия форума, там мы смотрим как там генериться хэш, подставляем сальт, и ага! никто ничего не менял. Берем эту маску генерации вставляем в свой брутфорс софт и уезжаем в отпуск. Ну а если увели и сорс и базу, к слову, так бывает в большинстве случаев, то ничего не спасет, кому надо, тот запариться и найдет искомый пасс. Вопрос стоит ли оно того, если ломают пасс к мылу нефтяного магната, дабы его разволплотить из магнатов, пасс найдут, а чудо-хацкоры пытающиеся подобрать пасс к аське подружки вспотеют.

    Извините если слишком витиевато, 9 утра как-никак.
    • +3
      Нет. Соль априори публична на столько же на сколько и сами хеши. Поэтому в никсовом варианте она и добавляется к хешу.
      Суть только в том, что по общей базе хешей прогнать пароли уже не получится.
      • 0
        Не совсем понятна причина, зачем нужно добавление соли к хэшу? Внутрь хэша — это ясно. А зачем ее в явном виде приписывать?
        Или имеется ввиду что она для каждой записи своя и случайным образом сгенерированная?
    • +4
      Берем эту маску генерации вставляем в свой брутфорс софт

      Соль не от брутфорса спасает, а от rainbow таблиц, которые позволяют узнать пароль по хэшу практически мгновенно.
  • +14
    Для вашей функции для пароля «111»,
    хеш получится «someDefaultSalt9b461ab103da1d343aa043d6145a5198».

    Как вы думаете где тут соль? ))
    • 0
      Я аж как-то немного в ступор вогнался, увидев такую запись :)
    • 0
      Какие проблемы? У хешей, как правило, фиксированная длина. Достаточно отрезать нужное кол-во символов с конца строки.
      • 0
        попробуйте хэш от «mypass» и «mypasswithsalt» взять. Не получится.
        • 0
          то есть взять-то получится, но совершенно разные хэши
          • 0
            Ну вообще при «прилиплении» соли _только_ к началу или к концу хеша мы можем взять первые 32 символа и последние 32, тем самым чуть усложняя задачу.
      • –1
        Если солить в одном месте, то и насолено будет только в одном месте. Чтобы все получилось очень вкусно — соль НЕОБХОДИМО перемешать с остальными ингридиентами! =)
        • 0
          это я к тому, что можно соль приписывать не только к началу, но и к концу, или вообще разбить на куски, или символы перемешать, и вставить через 1 =)
    • 0
      Как уже выше писали и не раз, суть соли не в сокрытии ее, а в защите от некоторых методов взлома.
      Кроме того, если уже по серьезному, соль используется не в human-readable форме, а бинарной строкой, и никто не мешает ее тоже перевести в шестнадцатеричную текстовую запись, как обычно хранится хеш.
    • 0
      Пусть мой пароль 12345 и он закодировался после добавления соли как раз то в 9b461ab103da1d343aa043d6145a5198.
      Если бы не добавляли соль то мы бы прогнали мд5 по rainbow таблицам. А так не можем. Вот в чем суть соли. нам не обязательно ее скрывать.
    • –1
      Это значение по-умолчанию, если на вход функции соль не подаётся (правила хорошего тона при написании функций).
  • +4
    Лучше бы поподробнее написали про метод «радужных таблиц».

    Я обычно использую md5( md5(pass) + salt )
    • +1
      Делать md5 два раза и думать что так секъюрнее, все равно что архивировать архивы, чтобы они побольше сжались…

      Если уж хотите добавить изюминку, чтобы для перебора понадобился ваш серверный код, то пишите
      md5($pass. $salt. $secret); где $secret, некая строка известная только на сервере.
      • +1
        Какой смысл в $secret? $salt известна за пределами сервера?
        • +4
          $salt в базе, а $secret в коде, ведь стырить могут что-то одно. Там выше коммент от zercool про это же.
          • +1
            Я обычно юзаю только $secret под видом $salt.
            Результат тот же, но злоумышленник не узнает соль, не получив доступ к исходникам.
            Таким образом, пароли защищаются не только от rainbow tables, но и от обычного брутфорса.
            • 0
              Да, но тогда вся эта статья идет в сад :-((( обидно.
            • 0
              В таком случае у одинаковых паролей будет один и тот же хеш.
              Что это дает? Ну к примеру, злоумышленник может зарегистрировать несколько аккаунтов с наиболее популярными паролями, потырить базу, обнаружить там пользователей с такими же паролями и проверить пароли на их почтовых ящиках, вдруг совпадают.
              • 0
                Если пользователь использует пароль «qwerty», то вы сами знаете, что исправит горбатого.
                Ну а если он ещё и такой же пароль на своей почте использует… в общем, я думаю вы поняли.
                • 0
                  Что пользователь с популярным паролем камикадзе, это понятно, но предоставлять хакеру возможность выявить таких пользователей все же не стоит.
      • +3
        В результате получится HMAC по сути :>
        Изюминка, для защиты от брутфорса, заключается в применении хеша не два раза, а нескольких тысяч раз.
      • 0
        Двойной md5 может появиться если нужно добавить поддержку «соления» в систему с чистым md5.
        Там исходные данные md5(pass), в результате получается хеш md5( md5(pass) + salt ), мне кажется на безопасность это не должно повлиять.
    • +1
      может я параноик, но вот мой вариант
      md5( md5( salt )+ md5( md5( pass ) + md5( salt ) ) );
      • 0
        Так чего мелочиться, раз 20 такое же повторить — в самый раз будет! =)
        • +2
          можно, это увеличит время перебора… :) 20 раз нужно будет брать хеш от строки… :)
          • +1
            тогда и поперчить не забудьте =)
            создайте еще $perec и, медленно помешивая, добавляйте в пароль =))
      • 0
        В целях оптимизации заменяем «md5( salt )» сразу на результат, т.к. salt — константа. Если salt берется из базы и уникален для каждого пользователя, то опять же считаем сначала md5(salt), а результат уже записываем в БД.
        • 0
          хм, не думаю что подсчет хеша, в штатной ситуации, является местом где что-то нужно оптимизировать…
          мы же берем хеш от строки, а не от файла…
  • +3
    Я помню была информация что можно найти коллизию для md5 очень и очень быстро, только я так и не понял — в итоге это была действительно правдивая информация, или просто математические выкладки и никто так и не реализовал этот алгоритм?
    • +1
      помоему md5 как раз и используеться повсеместно что это коллизеустойчивый алгоритм. Хотя может ошибаюсь. А так, да, сам процесс хеширования подразумевает наличие коллизий.
      • 0
        Да, разумеется устойчив, но в том году была новость где-то что разработан алгоритм быстрого нахождения коллизий, вот не могу вспомнить где это было =( как раз было бы интересно узнать реализовали алгоритм этот или нет, на сколько помню была дана математическая выкладка решения, но дальше дело не пошло… Может кто-то владеет более полной информацией?
  • –2
    Десятикратный md5 наше всё.
  • +5
    >> взломать нельзя, даже если злоумышленник получил доступ к базе.

    если злоумышленник получит доступ к базе, то ему уже никакая соль не помешает посмотреть связки user_id с данными в других таблицах :-))
    • +1
      Просмотреть не помешает, но пароля не выдаст.

      Во-первых, это вежливость по отношению к юзерам. К сожалению, многие из них используют один пароль на все сразу — почту, форумы, даже кошельки. Можно конечно сказать что они сами виноваты, если база «утечет», но все-таки надо делать работу качественно.

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

  • 0
    Я вобще догадывался что люди напрямую md5 делают без изменений… но сам так никогда не делал… потому как находил это не правильным… и то, что человек называется солью… всегда так делал. Наверное когда учился программировать у меня были хорошие примеры.
  • 0
    Может кому-то и пригодится, функции php для «подсаливания» хешей.
    Алгоритм, кстати, называется SSHA

    function ssha_crypt($clear, $salt = '') {
        if ($salt == '') $salt = _ssha_generate_hex_salt();
        return "{SSHA}".base64_encode(pack("H*",ha1($clear.$salt)).$salt); 
    }
    
    function ssha_validate($hash, $clear, $salt_len = 4) {
        $hash_pass = __ssha_get_pass_hash($hash);
        $salt = __ssha_extract_salt($hash_pass, $salt_len);
        $hash_test = ssha_crypt($clear, $salt);
        return $hash_test == $hash;
    }
    
    function __ssha_generate_hex_salt($length = 4) {
        $length *= 2;
        $keychars = Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f");
        $salt = '';
        $max = count($keychars);
        for ($i=0; $i<$length; $i++) {
            $skip = ($i == 0) ? 1 : 0;
            $salt .= $keychars[$skip + rand(0, $max - $skip - 1)];
        }
        return pack("H*", $salt);
    }
    
    function __ssha_get_pass_hash($secret) {
        return preg_replace("/^{\w+}/", "", "$secret");
    }
    
    function __ssha_extract_salt($hash, $salt_len = 4) {
        $binhash = base64_decode($hash);
        $binsalt = substr($binhash, strlen($binhash) - $salt_len);
        return $binsalt;
    }
    
    • 0
      SSHA — это походу Salted SHA? :>
    • +3
      Вот написали бы статью, где рассказали бы о том, почему тут всё именно так. То есть, что происходит, и так можно разобраться, но из чего вырос этот алгоритм в таком виде?

      Успехов.
    • 0
      >return «{SSHA}».base64_encode(pack(«H*», ha1($clear.$salt)).$salt);
      случаем не return «{SSHA}».base64_encode(pack(«H*», sha1($clear.$salt)).$salt);?
      • 0
        да, вы правы, буква при вставке съелась
    • 0
      Ну, и вот это мне не понятно, зачем $secret в кавычки?
      function __ssha_get_pass_hash($secret) {
      return preg_replace(«/^{\w+}/», «», «$secret»);
      }
      • 0
        И здесь правы, можно и без кавычек
  • –1
    Когда делал подобную систему использовал в качестве соли регистрационные данные пользователя которые. В жуткой комбинации битовых масок и хешей:) Если есть необходимость периодически менять засоленый пароль, можно использовать время последнего логина.
    • 0
      Неплохая идея.
      Только вот что делать если пользователь решит поменять свои данные? Каждый раз запрашивать у него пароль для перегенерации?
      • 0
        Услышь слова, |«данные которые не меняются», напр логин и время регистрации)
      • 0
        Опс, сори, НЛО съело мой коммент)
  • +2
    Идея очень старая. Подобное было предложено ещё в 90е, к тому моменту как я стал активным пользователем интернета(2003г) она уже применялась в популярных движках. По-крайней мере в это время я об этом узнал.

    Ну классика в общем. :)
  • 0
    Я так и не понял, почему все на md5 зациклились?
    • 0
      Можно sha, какая разница? если не использовать дополнительные средства для шифрования, любой публичный алгоритм не будет по настоящему безопасным
  • 0
    В журнале «Хакер» была статья на эту тему.
    Предложенный там алгоритм: md5($salt.md5(pass)), потом замена символов по таблице, известной только автору. Внешне хеш ни чем не отличается от обычного md5, а подобрать его практически невозможно (при условии, что злоумышленник не получит таблицу)
    • 0
      А зачем дважды хешировать?
      • 0
        Это вопрос к автору статьи (К. Касперски).
        Просто лишний шаг… на случай «а если злоумышленник узнает..».
        Я в качестве соли использую информацию из базы. Уникальную для каждого пользователя + вставляю не перед первым символом, а между некоторыми.
        Т.о. даже украв таблицу с паролями и правилами замены, вору потребуется лишнее время на дешифровку, за которое я успею отреагировать на кражу и принять соответствующие меры (сменить пароль, закрыть дыру)
  • +4
    эм, думаю опоздание поста на несколько лет тут вышло…
  • –1
    %username% какбе знает, в чем соль :)
  • +5
    Каждый разработчик проходит несколько стадий. (не обязательно все и не обязательно в указанном порядке)
    Сначала тупо использует md5(), потому что популярно и достаточно безопасно.
    Потом ему мало такой безопасности и он открывает для себя кучу других хеш-алгоритмов.
    Потом его накрывает параноей и он придумывает всякие маразмы ru2.php.net/manual/ru/function.md5.php#85116 (там ниже столько всего веселого).
    Если разработчик выживает после всего этого, то у его проектов растут нагрузки, появляется желание оптимизировать. Тут обнаруживается, что все эти чудо алгоритмы трехэтажные отжирают нехило процессорного времени и их приходится упрощать (как правило тут разработчик про соль знает все).
    Однажды мегапроект хакают. (Кто-то говорит «хачат», но мне это слово совсем не нравится). Это может случиться до предыдущей стадии. Если нет, то неграмотный разработчик пожертвует производительностью и пройдет предыдущую стадию еще раз (на этот раз грамотности прибавится).
    Далее разработчик начинает думать, узнаёт много о взломах и начинает уделять больше внимания проверке входящих данных. Как правило на этой стадии приходит полное понимание бесполезности шифрования паролей и полезности изучения аспектов безопасности.

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

    Пишите безопасные проекты и соль вам не понадобится ;)
    • –2
      «Пишите безопасные проекти и шифрование данных вам не понадобится»

      Есть еще человеческий фактор, или вы на 200% процентов уверены, что ни вы, ни ваши коллеги ни где ничего не пропустили? А в других проектах, которые лежат на одном сервере с вашим?
      • –1
        Человеческий фактор — это когда ошибаешься в цитатах ;)
        С опытом приходит уверенность и в себе и в коллегах ;) Команде надо доверять. печальный опыт тоже полезен.
        Когда делаешь серьезный проект, то, как правило, на том же сервере не лежат другие проекты ;)
        • 0
          Это не ошибка…
          Если проект безопасный, то и шифровать ничего не надо, т.к. без права доступа ни кто информацию не посмотрит.
          Как говорится доверяй, но проверяй.
          Не всегда есть возможность выделить отдельный сервер. Да и не всегда это нужно. Если ваш проект не мега-серьезный, но и на пароли пользователей можно наплевать?
          • 0
            опечатался…
            *_то_ и на пароли пользователей…
          • –1
          • 0
            Вот что будет, если ты узнаешь мой пароль от хабра? Я должен дрожать?
            Это вроде серьезный проект, тут все дрожат за свою карму. Мне по барабану.
            Мне наплевать на пароли пользователей.
            Мне проще в случае чего сгенерировать всем новые пароли и выслать на почту.
            Если проект серьезный, то в нем есть данные поважнее паролей, и если его будут ломать, то уж точно не ради паролей.
            Мой пароль от хабра «xuntaka». Все, теперь мой пароль знают все! Плакала моя карма? Кто-то угонит мой аккаунт? Кто-то напишет гадость от моего имени?
            Кому нужен мой пароль?
            Пароли никому не нужны! Ради паролей проекты не ломают!
            • 0
              уффф… вы не поняли о чем я. Разберем на примере:
              Допустим, на форуме группы «Блестящие» есть пользователь user с паролем qwertyuiop123.
              Представим, что пароли там лежат в открытом виде (или чистый md5/sha/ит.п.).
              Там нет секретной информации.
              Мы знаем, что этот пользователь является администратором the Bank of America.
              Получаем доступ к базе данных, смотрим пароль, идем на сайт банка, о чудо(!) он использует один пароль в системе tBoA и на форуме «Блестящих».
              Вот так мы получили root access к зарубежному банку.
              кто виноват?
              пользователь? почему? он думал, что ваш проект не взломают, т.к. в новой песне «Блестящие» пели о их новом мега-защищенном форуме.
              разработчик сайта блестящих? почему? он думал, что пользователи форума не будут использовать пароли от серьезных систем.

              может виноваты оба? и пользователь, с одним паролем везде; и разработчик, халатно отнесшийся к вопросу защиты информации.
              • 0
                Да все я понял. Это вы не понял.
                ВСЁ рано или поздно можно взломать.
                Виноваты оба!
                1й в том, что использует один пароль для банка и для чего угодно еще.
                2й в том, что не обеспечил достаточную защиту информации и ее сперли.

                Только разница в том, что оба не виноваты в проблемах друг друга!!!

                У меня на всех форумах один и тот же пароль (вернее два), и на вконтакте в том числе. Но на доступ к банку почему-то специальная программа для обеспечения защищенного соединения и два разных пароля, которые больше нигде не использую. И на вебмани пароль, который я не в силах запомнить, и на ЯД отдельный.
                • 0
                  Забудьте про «у меня»! У меня вообще на всех сервисах разные пароли.
                  Все поддается взлому, но чем дольше времени на это необходимо, тем лучше.
                  При получении некорректного запроса (а ля SQL-инъекции) можно админу отправить мыло, мол хакнуть пытаются. При частых попытках подобрать пароль брутфорсом — блокировать учетку. И администратор системы должен будет принять меры: попросить пользователя сменить пароль, и т.п.
                  Здесь рассматривается проблема rainbow таблиц.
                  ЗЫ: вопрос реализации защиты от взлома тоже выходит за рамки этой темы. И писать, что админ захлебнется в потоке писем, типа «вас пытались взломать» не нужно. нужно просто продумать систему защиты.
                  • 0
                    когда-нибудь вы меня поймете, а пока этот диалог бесполезен.
                    Удачи ;)
                    • 0
                      Надеюсь мы оба поймем друг-друга.
                      и вам не хворать)
                      • 0
                        Пару лет назад я был так же убежден в вашей точке зрения ;)
                        • 0
                          и что заставило вас считать, что лучше хранит пароли открытыми?
                          • 0
                            эволюция )))))))))
            • 0
              не соврал на счёт пароля :)
              • +7
                Я клёвый ^^
    • +1
      Нужно обязательно шифровать пароли. Всегда существует вероятность пасть жертвой непрямого взлома. Например, взломали хостинг, на котором крутится ваш супер-защищенный проект. Вот тут не раз скажешь спасибо себе, что уделил внимание сохраности конфедициальных данных.
      • +1
        Из конфиденциальных данных на суперзащищенном проекте пароль имеет наименьшую ценность. Или шифровать все или ничего.
        Если упрут базу целиком, то о паролях будешь плакаться, только если у тебя был форум ;) А если у тебя был банк то даже зашифрованные пароли придется менять ВСЕМ и останавливать работу всей организации. А потом можно смело сворачивать свою деятельность ;)
        • 0
          Если то, если это…
          Пароль — средство идентификации пользователя. Буть то домашняя страничка Васи Пупкина с форумом, или серьезная банковская система.
          Пользователь — человек. Он может использовать один и тот же пароль на разных сайтах. Правильно это или нет — судить не нам. Коли мы заставляем пользователя регистрироваться в системе (по каким-либо причинам), то мы должны обеспечить сохранность и неразглашение его личной информации, даже если в базе кроме пароля уводить-то нечего, есть наша обязанность. Т.к. используя этот пароль злоумышленник может украть у человека учетные записи на других сервисах.
    • 0
      Всё верно, но с заключительным выводом не согласен.
      Шифрование паролей — это не панацея, а одна из составляющих «безопасного проекта».

      Успехов.
      • 0
        Спасибо.
        Меня тут посетила мысль.
        Я администратор одной популярной интернет игры. Пароли у нас хранятся открыто и пользователи об этом в большей своей части знают. Очень часто для решения проблем приходится войти тем или иным пользователем в игру и посмотреть на проявление проблемы своими глазами. Да и лог посмотреть во время возникновения ошибки. При постоянном количестве игроков более 1000 и кластере о двадцати серверах искать проявление неизвестной ошибки в гигабайтах логов занятие не самое приятное.
        Так вот, о чем мы здесь. Я могу зайти в админку, взять пароль перса и войти им. А если бы пароль был шифрованным? Пришлось бы просить его у пользователя. В данном случае зашифрованный пароль открывает простор действия лжеадминам на поле социального инжиниринга ;) Т.к. пользователь знает о том, что админ всегда знает его пароль, он никому его не отдаст по первой просьбе ;)
        А социальный инжиниринг пострашнее любого взлома ;)

        Все сказанное сугубо IMHO. Я с полной ответственностью понимаю, что пользователь может быть дураком и отдать свой пароль, но это уже его проблемы.
        • 0
          Если у вас есть доступ к БД, что мешает хеш его пароля на свой, а по завершении рабо вернуть обратно?
          • 0
            А вы когда-нибудь работали с распределенной архитектурой и кешированием данных?
            Может мне еще проще будет написать один раз админку, которая без авторизации будет вводить меня в игру под любым пользователем?
            • 0
              По большому счету — да, будет лучше написать еще один скрипт.
              Когда пользователь авторизуется в системе, система в этот момент что-то пишет в cookie (или хранит в сессии), что мешает сделать скрипт, который из админа сделает любого пользователя?
              Не зря в той же Windows Server админ не может посмотреть чей-либо пароль, а может только сменить.
              В вашей же ситуации (если пользователи используют один пасс и на игру и на мыло) вам ничего не мешает посмотреть его личную переписку.
              • 0
                Скрипт мешает сделать то, что придется выкинуть пользователя из игры, а это обычно не приятно. Еще придется учесть много нюансов по подмене сессии и много чего еще. В итоге этот способ окажется невыгодным.
                У меня миллион пользователей, читать личную переписку каждого как-то не с руки. И потом я не фетишист и это не доставит мне удовольствия.
                • 0
                  а когда вы заходите от имени другого пользователя, посмотрев пароль в БД, его не выкидывает? O.o
                  • 0
                    Пока игрок в игре, второй раз его не пустят. В смысле пока игрок в игре, под его аккаунтом с другого компьютера не войдешь. В рамках данного проекта это правильно.
                • 0
                  про переписку это я к слову.
            • 0
              Наверно это и есть будет самый лучший случай.
              Я в в своем проекти так и делал что рут имел возоможность зайти как любой пользователь.
              • 0
                Это не всегда хорошо и не всегда удобно. Хотя на первый взгляд выглядит просто супер )
                • 0
                  > Это не всегда хорошо и не всегда удобно
                  контрпримеры? )

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

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

                  успехов! )
                  • 0
                    Я не за советами пришел ;)
        • 0
          1. почему бы на уровне движка игры не разрешить админам работать «от имени» пользователей?
          2. можно скопировать старое значение хеша, затем задать новый пароль, поработать под новым, после этого вернуть старый. если это автоматизировать, то получится реализация п.1 ))
          3.
          > Т.к. пользователь знает о том, что админ всегда знает его пароль, он никому его не отдаст по первой просьбе ;)
          Юзер должен знать, ЧТО НИКТО И НИКОГДА не попросит у него пароль. Только форма авторизации ))

          > А социальный инжиниринг пострашнее любого взлома ;)
          Согласен, но это отдельная тема :-)

          Успехов.

          PS: Ух, сначала написал ответ, а затем прочитал комменты ниже. Ну да уж повторюсь тогда ))
        • 0
          >Пароли у нас хранятся открыто и пользователи об этом в большей своей части знают.
          В большей свое части? т.е. не все пользователи знают, что если он использует один и тот же пароль для вашей игры и своего почтового ящика то у вас есть доступ к его почте, а оттуда еще черт знает какому количеству сервисов.
          А если вашу базу получат третьи лица? Конечно, там все безопасно у вас, но могут просто забрать/украсть/конфисковать сервер. Кто дальше будет гарантировать безопасность паролей?
          • 0
            Ога. Из миллиона пользователей будут искать Васю Пупкина, чтобы прочитать его секс по емейлу. Смешно.
            • 0
              Не смешно. Я верю, что вы не будете читать почту Пупкина, но меня волнует наличие такой возможности.
              Выше вы написали:
              >ВСЁ рано или поздно можно взломать.
              Отсюда следует, что ваш безопасный проект тоже, а кто гарантирует, что, взломавший, не любопытнее вас.

              >Пишите безопасные проекты и соль вам не понадобится ;)
              О какой безопасности можно говорить если вы упорно пренебрегаете одним из ее элементов, откуда мне знать чем еще вы пренебрегаете. Проект хранящий пароли пользователей и есть НЕбезопасный проект.

              Посмотрите вокруг в каком вменяемом ПО хранятся открытые пароли?
              Везде хранятся «засоленые» хеши, например: *nix, apache, mysql, открытые CMS.

              >Пароли никому не нужны!
              Да ну! Мой или ваш, может быть и не нужны. А вот пароль Сары Пелин (не уверен, что так пишется) пригодился ведь кому-то.
              • 0
                *nix, apache, mysql
                тут просто файлики с паролями доступны все пользователям системы ;) Кстати, пароли расшифровываются очень быстро ;)

                Пароль Сары Пелин никто так и не узнал. В системе Yahoo дырка дает возможность попасть в ящик в обход пароля ;)

                Как ни соли пароль, а его взлом вопрос времени и ресурсов.
    • 0
      > (Кто-то говорит «хачат», но мне это слово совсем не нравится).

      «Хакают» — чужое, а «хачат» — свое… :)
      • 0
        «Хачат» — это откуда-то с самого юга Необъятной.
  • –2
    Все то же самое «от авторов»:
    crypt, md5, sha1, mhash, etc.

    А вот тут — совсем уж предел игр разума.
    Вообщем — за обработку текста в худшую сторону — жирный кол. Ничего личного.
  • –3
    Дешево и сердито — по-советски и работает
    По крайней мере пока что — пока «RainBow DeSalt» tables не придумали!: D
  • НЛО прилетело и опубликовало эту надпись здесь
    • 0
      скажите пожалуйста, а sault это на каком языке?
      • НЛО прилетело и опубликовало эту надпись здесь
      • 0
  • –1
    Я обычно делаю так:
    md5(md5($username) . $salt . md5($password))
    
    • –3
      А зачем так много? Аж 3 раза считаем «тяжелый» md5…
      • 0
        Не думаю что md5 критично тяжелый. Тяжелее его любая выборка из базы.
        • 0
          Возможно для ваших проектов он не критично тяжелый, и, конечно, выборка из базы тяжелее.
          Но, я к тому, что применение его несколько раз не увеличивает стойкость вашего алгортима, разве что запутывает и усложняет перебор :)
          • +1
            md5 и прочие хеш-алгоритмы ниразу не тяжелые, попробуйте вставить в коде тысячекратное применение алгоритма и посмотрите на сколько это повлияет на производительность.
            В реальных ситуациях (а не в веб-песочнице), как то в PGP, PKI, etc используется несколько тысяч итераций.
  • +7
    Кстати, если соль сделать из 8-ми абсолютно случаных символов, то при взломе такого хэша, система взлома может распознать его как SHA-хэш и априорно начнёт двигаться в ложном направлении.

    Пара замечаний. Коль уже пишите про криптографию надо педантично относиться к терминам.

    — Абсолютно случаные последовательности генерировать крайне сложно. А используя только вычислительные мощности компьютера невозможно. Нам доступны только псевдослучайные последовательности. А случайные, это, например, математический «белый шум»

    — По принципу Кирхгоффа предполагается что противнику полностью известны все используемые вами алгоритмы. А значит рассчитывать, что вместо md5 противник подумает, что у вас sha — глупо.
    • –1
      Это ведь веб-разработка ;-)
      • +1
        это ещё не значит что в этой области поголовно все идиоты (-:
        • 0
          Отнюдь, такого я не говорил :)
  • НЛО прилетело и опубликовало эту надпись здесь
    • +3
      обычно просто делают каждому паролю случайную соль, которую хранят в базе в открытом виде.
  • –2
    боян!
  • +2
    Хорошая статься, вот только заголовок подкачал.

    Если пароль использовать слишком часто, то он будет потрёпаный и засаленый. (-:

    А добавление соли по-русски, насколько я понимаю, правильнее будет называть засолкой.
    • 0
      а с учётом «перца» — и вовсе «пряный посол» получается, ммм…
      *** ушёл за пивом и селёдочкой
  • +1
    наступила пора солянок!
    компьютерщики на зиму солят пароли)) пойду банок трехлитровых куплю…

    зы
    за статью спасибо. лично для меня оказалось полезным.
  • –1
    >Кстати, если соль сделать из 8-ми абсолютно случаных символов, то при взломе такого хэша, система взлома может распознать его как SHA-хэш и априорно начнёт двигаться в ложном направлении.

    Поправьте меня если я неправ, но SHA — хеш длиной 40 символов, а md5 — 32, или 160 и 128 бит соответственно. Из этого следует, что какой бы соль длины не была код md5($salt.$pass) вернет всё те же 32 символа. А вот когда $salt отвечает /^[0-9a-f]{8}$/i и записать её, например так $salt.md5($salt.$pass), тогда да.
    • –1
      saltstringaekfngy4i6ygh8dk0oe3rtn3pz5ldh3r
      saltstringvoiuret3jngsdf45oieq09rtugdskkef
      

      В таком случае можно получить $salt и тогда теряется смысл md5($salt.$pass) (ведь мы знаем $salt).
      Ну или использовать динамический $salt, разный для каждой записи
      • 0
        Согласен. Это не только моя ошибка, посмотрите внимательно на код автора. Я, к примеру, использую встроенный механизм засаливания в cakePHP.

        К сожалению, я сам просмотрел код автора бегло, тогда мой предыдущий комментарий вообще не в тему.
      • 0
        Интересно конечно, что я сказал неверного здесь :)
    • 0
      >записать её, например так $salt.md5($salt.$pass), тогда да.

      Именно это и имелось в виду. Это классический алгоритм использования соли.
  • 0
    можно вместе рандомной соли использовать в качестве нее логин пользователя. тогда не придеться еще прибавлять саму соль в открытом виде
  • 0
    Подвиды MD5, в т.ч. и «соленые»:
    — md5(md5($pass)): 50c1fffdd9cce739fe68d84da224adb8
    — md5($salt.$pass): 6ac0bfb7a0a4e2e3a36d0bf6eadd9d21
    — md5($pass.$salt): 94e4e6b840a2b4c9c64c94f73cb83971 (применяется в Joomla)
    — md5($salt.$pass.$salt): 754fe69c29752e35c4326c6e2f03cb4e
    — md5(md5($pass).$salt): 1c852dee259fe82906f11c03fc09c32c (применяется в vBulletin)
    — md5(md5($salt).md5($pass)): 119295263dd6a8ceeb5ea3feb248d8f1 (применяется в новых IP.Board)
  • –1
    деСоль плз… :)
  • –1
    «Засолка» или «Засол» тогда уж. «Засаливание» — это от слова «сало».
  • –1
    Захотят получить доступ — получат.
    Так к чему лишние головоломки?=)
    Базовые действия предпринять от школьников нуна.
    Больше… для до — энтерпрайз, приложений. смысла не вижу.
  • –1
    Хорошая статья, полная в ][akep'е была.
  • 0
    у меня для каждого юзера своя «соль», генерируемая по определенному алгоритму из его уникального id
  • 0
    У меня такой вопрос, если я правильно понимаю что такое rainbow таблица:

    Если у нас есть out = salt + hash(pass+salt), где в out мы можем явно выделить salt и hash. Почему нельзя найти пароль (множество паролей) для этого hash в rainbow таблице и убрать из этого пароля (паролей) salt.
    • 0
      Всё дело в коллизиях т.е. это когда при разных, поданных на вход алгоритма, данных получается один и тот же результат (в нашем случае — md5-хэш). Т.е. на самом деле вероятность того, что с помощью Rainbow-таблицы найдётся именно пароль с солью довольно не велика (хотя исключать её не стоит), а вот вероятность найти коллизию куда больше и полученный результат уже ничего не даст.
      • 0
        так коллизии будут всегда, для одного хэша в теории существует огромное множество паролей. главное что сервер получив такой «пароль» будет вычислять его хэш и сравнивать с тем что в базе, и естественно разницы не заметит. если rainbow таблица содержит хэши от всех возможных битовых комбинаций (т.е. не только словарные слова и т.п.) будет найдены хэш (или хэши) равный hash(pass+salt) при том что мы знаем salt. с учетом таких недостаков хэш функций, как «удлинение сообщения» (описано в книжке шнайера «практическая криптография) это может значительно упростить нахождение пароля, который подойдет серверу.
        • 0
          >такой «пароль» будет вычислять его хэш и сравнивать с тем что в базе, и естественно разницы не заметит

          Стоп. Получив такой «пароль» он будет сравнивать хэш отпароля с солью (он же для проверки пароля пропустит его через тот же алгоритм «засолки») и результат получиться совсем не такой.

          А вообще, даже зная соль, для неё необходима генерация своих rainbow-таблиц. Сейчас такие таблицы существуют для «чистого» md5 и паролей до 8-ми символов. Создайте соль хотя бы из 7-ми символов и найти конструкцию соль+пароль в современных Rainbow-таблицах будет невозможно. Даже если использовать Hybrid Rainbow таблицы то добавлением соли, состоящей из большого числа случайных символов, можно также свести на нет вероятность его отыскания.
          • 0
            результат получиться совсем не такой

            Я тоже так думал, но вышеупомянутая глава из книжки шнаера посеяла сомнения. насколько я понял, если у нас есть hash(pass1) = x и hash(pass2) = x, то hash(pass1+salt) вполне может быть равен hash(pass2+salt), что кстати вполне объяснимо если на вход алгоритма поступает битовый поток, а не блоки.
            • +1
              Не поленился и прочитал таки эту главу :)

              Во-первых, на вход алгоритма md5 всегда поступают блоки по 512 бит т. е. поток всегда не битовый, а блочный.

              Во-вторых, это свойство (hash(pass1+salt) == hash(pass2+salt) если hash(pass1) == hash(pass2)) относиться не к удлинению сообщения, а к коллизиям алгоритма md5 хэширования, а точнее — к способу их отыскания (т. е. по найденной одной коллизии мы можем найти ещё их неограниченное число) (Глава «Коллизия при частичном хэшировании сообщения»)

              В-третьих (и по теме «удлинения сообщения»), как Вы заметили, удлинение сообщения действительно является большим недостатком функций хэширования. Но посмотрим с другой стороны, что же практически необходимо сделать, что бы воспользоваться этим недостатком. Суть проблемы удлинения сообщения заключается как раз в «потоковости» алгоритма т. е. что на n-ом шаге алгоритма хэширования получается хэш (n-1) предыдущих блоков сообщения. Что это означает в теории: мы имеем hash(pass), далее, мы можем получить hash(pass+salt), не пробегая весь алгоритм хэширования, а запустив его с момента, когда алгоритм уже «предвычислил» до hash(pass) и осталось лишь «довычислить» salt. Вот и всё, что даёт этот «недостаток». К тому же соль мы дописываем в начало сообщения, а не в конец. (если бы она дописывалась в конец, то да — зная соль можно перехватить исходный, «незасоленный», пароль и попытаться отыскать его (или коллизию) в Rainbow-таблицах).

              Теперь вернёмся с небес на землю и от теории перейдём к практике. Авторы сами указывают на то, что для реализации данного недостатка необходима система аутентификации, при которой злоумышленник может дописывать в исходное сообщение свой текст. Но для того, что бы это реализовать в веб-проектах, необходимо сломать веб-сервер и перехватывать сообщения на уровне исполнения функции md5 в PHP. Но если уж дело дошло до взлома сервера и получения к нему неограниченного доступа (ну или хотя бы перехвата сервисных сообщений интерпретатора PHP), то тут вряд ли помогут какие-либо ухищрения в шифровании информации и дальнейшие изыскания становятся бессмысленными ;)
              • +1
                agree

                но все равно «запустив его с момента, когда алгоритм уже «предвычислил» до hash(pass) и осталось лишь «довычислить» salt» это на мой взгляд серьезная проблема, правда только для потоковых алгоритмов. Хотя все широко распространенные на данный момент (md5, sha) — блочные.
        • 0
          Hybrid Rainbow таблицы составляют слова, которые могут быть паролем не из отдельных символов (как в классических), а с помощью словарей, что позволяет сделать по объему почти такие же таблицы, но уже отыскивать пароле и более 8-ми символов. Понятно, что если соль будет состоять из полной белеберды, то и не один словарь её воспроизвести не сможет.
  • 0
    В любом случае — это все танцы с бубнами, а значит не есть хорошо.
    • 0
      Если не хочешь чтобы твой проект взломали, то без танцов с бубнами не обойтись!
      • 0
        Если я не ошибаюсь сначало надо БД спереть, чтобы было по чему ломать
  • 0
    Получается, что выделить соль из такого хеша — как 2 пальца?
    $hash = 12345e1ff032d792e585d736aaaaea68b00b4
    $salt = substr(0, -32);

    и дальше на перебор в процессор?
    • 0
      Вполне логично. В *nix системах так пароли и хэшируются — смысл в том, что пропадает необходимость хранить соль и хэш — достаточно хранить только хэш. А вот с «дальше на перебор в процессор» уже вряд ли что-то выйдет — основа метода как раз таки в md5($salt.$pass).

      Как я говорил в статье, для этой соли ещё нужно сгенерировать свою Rainbow-таблицу — а это дело неблагодарное :)
  • 0
    Предположим, на сервере мы научились хранить пароль так, что восстановить его нельзя. Вопрос — а как этот пароль проверять? Если клиент передаёт пароль в открытом виде — пароль можно перехватить. Если добавить salt и на клиентской стороне, то клиент должен получить salt, сложить со своим паролем и результат передать на сервер. Там сравнить с сохранённым вариантом. Но если перехватить переданный засальтованный хэшированный пароль — результат тот же, что и в первом случае, то есть надо обеспечить как -то уникальность salt для каждого запроса пароля. Как это сделать? Передавать два salt?

    Регистрация пароля: сохраняем salt1, md5(salt1+password).
    Проверка пароля: передаём клиенту salt1, md5(salt+password), salt2 — где salt2 — временная одноразовая соль.
    Клиент должен вернуть salt2 и md5(md5(salt1+password)+salt2) — тогда мы можем проверить правильность пароля и при этом его по сети не передавать.

    Есть ли в такой схеме недостатки?
    • 0
      Недостатки тут разве что в сложности: хэширование на клиенте через JS, по 2 запроса и ответа от сервера (опять таки, время). А в целом, Вы описали логику аутентификации по Kerberos :)

      Кстати, если у злоумышленника есть таки возможность перехватывать Ваши пакеты, то и salt1, md5(salt+password), salt2 он может перехватить. Да, тут встаёт вопрос, может ли он это после обработки дописывать в ответ серверу или, грубо говоря, полностью сэмитировать сессию (в Kerberos ещё помимо проверок паролей идёт шифрование по открытым ключам и выдача всяких посторонних значений для идентификации пользователей и их сессий — не буду подробно расписывать т. к. темы вопроса это не касается :) ).

      Но зачем всё усложнять — передавайте пароль по https и никаких лишних ухищрений делать не придётся. Не панацея, конечно, но усложнять веб-системы подобным образом — не самый разумный подход, помоему :)
      • 0
        https сразу в голову приходит, но он не всегда реализуем, к сожалению. Только сейчас браузеры начали поддерживать больше одного на ip адресе, а адресов не хватает. Да и производительность падает.

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