Пример кода входа в систему, который был взломан с помощью SQL-инъекции, хотя mysql_real_escape_string ... - PullRequest
6 голосов
/ 29 марта 2010

Я использую CodeIgniter, и у меня проблемы со взломом. Можно ли сделать SQL-инъекцию для кода входа ниже:

    function process_login()
{
    $username = mysql_real_escape_string($this->input->post('username'));    
    $password  = mysql_real_escape_string(MD5($this->input->post('password')));

    //Check user table
    $query = $this->db->getwhere('users', array('username'=>$username, 'password'=>$password));

    if ($query->num_rows() > 0)
    {
        // success login data

Я использую mysql_real_escape_string неправильно или как?

Ответы [ 8 ]

7 голосов
/ 30 марта 2010

Нет, что опубликовано, вероятно, не уязвимы для инъекций sql. Хотя getwhere () может выполнять полоску (), я не уверен.

Вероятно, если SQL-инъекция была в другой части вашего приложения. Злоумышленник может использовать эту уязвимость, чтобы получить ваш чрезвычайно слабый md5 () хеш, взломать его и войти в систему. Используйте любой член семейства sha2, sha-256 - отличный выбор.

Если ваш сайт был испорчен, то я серьезно сомневаюсь, что это инъекция SQL. Трудно автоматизировать использование SQL-инъекций для порчи веб-сайтов, но это возможно. Я хотел бы убедиться, что все библиотеки и установленные приложения полностью обновлены. Особенно если у вас есть CMS или форум. Вы можете запустить сканирование OpenVAS на вашем сайте, чтобы выяснить, находит ли оно какое-либо старое программное обеспечение.

5 голосов
/ 12 июня 2011

База данных

Судя по вашему коду, я вижу, что вы не используете последнюю версию CI (2.0.2 по состоянию на 06/12).

Как указано в changelog , функция getwhere() (которая теперь называется get_where()) была заброшена, как и в версии 2.0.
Что касается вечных приложений, вам настоятельно рекомендуется обновить текущую версию, поскольку в то же время было много исправлений, и вы всегда должны полагаться на самую безопасную версию.

mysql_real_escape_string обычно считается «достаточным», чтобы обеспечить хороший уровень безопасности в ваших запросах, но, поскольку это происходит с предшественником (mysql_escape_string), он не на 100% безопасен от всех видов атак, поэтому полагаться на это не лучшая практика. Хотя это безопасно, все еще существуют атаки, которые могут пройти этот фильтр.
Проверьте, среди многих, этот вопрос на SO для получения дополнительной информации об этом.

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

Но мы находимся в контексте структуры, и Codeigniter предлагает 3 отличных способа безопасного запроса вашей базы данных, применяя правильный инструмент для правильного ввода, не беспокоясь об этом. Я говорю о привязках запросов и ручном экранировании с помощью семейства $ this-> db-> escape () и Active Record Class
Вы можете найти примеры использования по ссылкам, которые я только что связал, или прочитать ответы других коллег здесь, поэтому я не буду вдаваться в подробности каждой процедуры в этом посте.

Пароль

Что касается вашего пароля, как уже было сказано другими пользователями, md5() является теперь ошибочным алгоритмом хеширования. Существуют радужные таблицы, которые могут взломать ваш пароль md5 за относительно короткое время, поэтому вам лучше использовать алгоритмы хеширования с более высоким уровнем безопасности, например sha1 () или sha256, sha512 и другие

В коде: Codeigniter поставляется с классом помощника по безопасности , который предоставляет вам удобную функцию do_hash() (может быть dohash() в вашей более старой установке), которой можно присвоить хэш-код. как параметр (в настоящее время я думаю, что он поддерживает только MD5 и Sha1) и по умолчанию Sha1 () в любом случае.

Другие наблюдения

Мне не совсем понятно, почему вы обвиняете свой логин в инъекциях SQL. Это единственные 2 формы во всей вашей заявке?
Вы не предоставили информацию, чтобы сказать, используете ли вы параметры $ _GET, или вы следуете сегментации URI, но я полагаю, что вы делаете это так, поэтому я предполагаю, что вы в безопасности с этой точки зрения.

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

Кроме того, может существовать другой источник вторжения, например, взломанный файл cookie. В качестве совета, всякий раз, когда вы решаете использовать фреймворк (а вы делаете себе больше пользы, чем разработку с нуля и все самостоятельно), вы должны стремиться использовать БОЛЬШЕ его функций, особенно когда речь идет о безопасности. Это огромный и очень деликатный вопрос, поэтому вы ДОЛЖНЫ уделите этой теме первоочередное внимание, а хорошо разработанная структура с огромным сообществом и частыми обновлениями - самая близкая к безопасности, которую вы можете получить.
Поэтому вам рекомендуется обновить вашу установку CI (руководства можно найти здесь в их руководстве. Выберите вашу версию и следуйте инструкции), всегда используйте верхнюю инструменты, которые вам дают для каждой задачи, и не думайте, что закрытие вашей двери защитит вас от вторжения из ваших окон. Всегда тщательно проверяйте и исследуйте все возможные причины.

Позднее добавление: Не забудьте XSS, CSRF, фиксации сеансов и другие горячие проблемы безопасности.

4 голосов
/ 29 марта 2010

Посмотрите на этот старый вопрос SO.
Я бы использовал:

$sql = "SELECT * FROM users WHERE username = '?' AND password= '?'";
$dbResult = $this->db->query($sql, array($this->input->post('username')),array($this->input->post('password')));
3 голосов
/ 30 марта 2010

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

В любом случае, помните, что mysql_real_escape_string () охватывает только метасимволы mysql: одинарную кавычку, двойную кавычку, точку с запятой и т. Д. Все еще вполне возможно взломать функцию входа в систему с помощью искажения логического параметра. Невозможно сказать, уязвима ли ваша функция «getwhere», но рассмотрим случай, когда введенный пароль «xyz OR (1 = 1)». Сгенерированный запрос может выглядеть примерно как

 SELECT id FROM users WHERE users=someusername AND password=xyz OR (1=1);

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

1 голос
/ 10 июня 2011

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

Что касается того, правильно ли вы используете mysql_real_escape_string ... да и нет. Да, у вас есть правильная идея, но вы на самом деле используете ее чрезмерно. Если вы используете пароль MD5, то этот ввод теперь чистый и не может быть использован для инъекции, поэтому вызов mysql_real_escape_string является излишним. Так что это было бы хорошо:

$username = mysql_real_escape_string($this->input->post('username'));    
$password  = MD5($this->input->post('password'));

Как упоминалось ранее, MD5 сам по себе является довольно слабым алгоритмом хеширования. Изучите SHA и посолите хеш.

Чтобы противостоять предыдущему опубликованному ответу, если пользователь вводит «xyz OR (1 = 1)» в качестве пароля, это абсолютно не угрожает его сценарию по двум причинам.

1) Хеширование MD5 преобразует это в безвредный хеш (например, 'd131dd02c5e6eec4693d9a0698aff95c'), делая запрос чем-то похожим на SELECT id FROM users WHERE users='username' AND password='d131dd02c5e6eec4693d9a0698aff95c';

2) mysql_real_escape_string предотвращает «строковые» инъекции, то есть инъекции, которые потребуют одинарную или двойную кавычку для выхода из ожидаемого SQL-запроса, но не предотвращают (например) инъекцию с числовым вводом, который вам потребуется используйте приведение типа к блоку.

Все зависит от вашего вызова "$ this-> db-> getwhere". Если это просто строит запрос нормально, не делая ничего прикольного (например, разбирая кавычки или обрабатывая строки как целые числа [которые в любом случае выдают ошибку) и т. Д.), Вы просто не уязвимы в этом сценарии. Если бы вы могли дать более подробную информацию о «типе» взлома, с которым вы столкнулись, мы, вероятно, могли бы дать вам некоторое руководство, где искать. Вы были испорчены?

Я не играл с CodeIgnitor, но ожидаю, что их встроенные функции ввода / базы данных не сделают ничего странного, поэтому, если вы сами не отредактировали функцию getwhere, вам, вероятно, будет хорошо в этом конкретном месте.

1 голос
/ 10 июня 2011

Насколько я понимаю, Active Records будет правильно экранировать значения для вас. Таким образом, с $query = $this->db->getwhere() вам НЕ нужно использовать mysql_real_escape_string().

Но вы всегда должны использовать какую-то проверку контроллера. В частности, вы можете ограничить имя пользователя и пароль определенными символами с помощью регулярного выражения. Это всегда предлагается.

Кроме того, если вы часто сталкиваетесь с типичными атаками, тогда попробуйте PHPIDS. Это система обнаружения вторжений, которая поможет вам не допустить, чтобы атаки действительно нанесли какой-либо ущерб, поскольку вы можете выдать ошибку или уведомление какого-либо рода.

Вы также можете просмотреть это руководство по вопросам безопасности. http://net.tutsplus.com/tutorials/php/codeigniter-from-scratch-security/

0 голосов
/ 13 июня 2011

Код кажется устойчивым к инъекционным атакам. Вы берете md5 поля пароля, которое исключает любую инъекционную атаку на это поле. Уязвимое поле - это имя пользователя, которое вы все равно экранируете. Вы уверены, что это инъекционная атака?

Есть ли какие-либо другие поля, такие как поля access_token, переданные для предотвращения CSRF

Ниже приведены возможные причины странного поведения:

  • Вы используете драйвер mysqli в конфигурации базы данных и экранирующую строку согласно mysql lib. Попробуйте указать $this->db->conn_id в качестве второго параметра для mysql_real_escape_string и проверьте в журналах php предупреждения.
  • mysql_real_escape_string нуждается в connection link identifier в качестве второго параметра. Если вы не предоставите это, вы будете испытывать странное поведение. Я перенес это с codeigniter. В моем случае mysql_real_escape_string возвращал пустые строки. Если с вами такой же случай, убедитесь, что в вашей таблице пользователей нет пустых паролей и имен пользователей (очень маловероятно).
0 голосов
/ 11 июня 2011

Код, который вы предоставили, не уязвим для внедрения SQL, но вы никогда не должны вводить пароли в запросы, даже хэшировать, потому что вы не можете быть уверены, сохранен ли запрос в журнале сервера или нет, и вы обычно этого не делаете. иметь контроль над тем, кто может иметь доступ к этому.
Запросите / загрузите запись пользователя по имени пользователя, а затем сравните с ней хеш пароля в $ _POST.

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