2016-01-02 2 views
1

Я очень новичок в mysqli раньше, я пишу запросы в mysql, но mysqli более продвинутый, поэтому я впервые использую его. Ниже приведен мой PHP-код.предотвратить SQL-инъекцию в mysqli

function clean($str) { 
     $str = @trim($str); 
     if(get_magic_quotes_gpc()) { 
      $str = stripslashes($str); 
     } 
     return mysql_real_escape_string($str); 
    } 

     $email = clean($_POST['email']); 
     $password = clean($_POST['password']); 
     //$password =md5($password); 


    if(empty($res['errors'])) { 
     $result = $mysqli->query("SELECT uid FROM users where email='$email' and password = '$password'"); 
     if($result->num_rows == 1){ 
      $res['success'] = true; 
     } 
     else{ 
      array_push($res['errors'], 'Invalid login details'); 
      $res['success'] = false; 

     } 
    }else{ 
     $res['success'] = false;   
    } 
    echo json_encode($res); 
} 

Функция очистки не работает должным образом, потому что sql-запросы возвращают false, если я правильно ввожу имя пользователя и пароль. Итак, похоже, что это неверно в случае с mysqli.

Я проверил эту ссылку PHP MySQLI Prevent SQL Injection и узнал, что мы должны подготовить запрос.

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

Спасибо за ваше время.

обновленный код

$result = $mysqli->prepare("SELECT uid FROM users where email=:email and password = :password"); 
     $result->execute([ 
':email' => $email, 
     ':password' => $password]); 
     //$result->execute(); 
     if($result->num_rows == 1){ 
     //if(mysqli_num_rows($result) === 1) { 
      $res['success'] = true; 

     } 
     else{ 
      array_push($res['errors'], 'Invalid login details'); 
      $res['success'] = false; 

     } 
+0

использование redbeanphp, который построен на pdo. – jewelhuq

+0

Причина в том, что вы смешиваете API-интерфейсы MySQL, вы не можете этого сделать, если вы все еще используете 'return mysql_real_escape_string ($ str);' с вашим текущим/новым кодом. Просто избавитесь от всего этого и используйте подготовленное заявление. Кроме того, мы не знаем, есть ли какие-либо значения в ваших массивах POST, так как вы не разместили свою HTML-форму. –

+0

мы также не знаем, с каким API вы (сейчас) используете для связи. 'Mysql_'? 'Mysqli_'? PDO? Другие? Тогда у вас есть 'if ($ result-> num_rows == 1) {' это синтаксис 'mysqli_' и ваш' where email =: email и password =: password' - PDO. Опять же, они НЕ смешивают. –

ответ

1

Как уже указано в комментариях, вам необходимо быть в соответствии с вашим выбором API. You can't mix APIs in PHP.

Вы начали с mysqli_*, поэтому я продолжу это. У вас было mysql_* и PDO там, и неплохо было бы использовать PDO над mysqli_*, но если ваш сервер поддерживает mysqli_*, нет ничего плохого в использовании этого. См. Choosing an API и решите для себя (просто держитесь подальше от mysql_*, он устарел).

Используя mysqli_*, вы подключаетесь к базе данных следующим образом (вы не показывали подключение).

$mysqli = new mysqli("host", "username", "password", "database"); 
if ($mysqli->connect_errno) { 
    echo "Failed to connect to MySQL: (".$mysqli->connect_errno.") ".$mysqli->connect_error; 
} 
$mysqli->set_charset("utf8"); 

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

Вам также необходимо знать, сохранены ли ваши пароли в базе данных. Они действительно должны быть, и вы должны использовать password_hash($password, $algorithm) и password_hash($password, $hash), если вы на PHP5.5 и выше (если нет, посмотрите на что-то вроде password_compat).

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

Я показываю вам пример использования password_hash(), поэтому это означает, что пароль, хранящийся в базе данных, также должен быть сохранен с password_hash() (или ваш запрос не работает).

$email = $_POST['email']; 
$password = password_hash($_POST['password'], PASSWORD_DEFAULT); 

if ($stmt = $mysqli->prepare("SELECT uid FROM users where email=? and password=?")) { 
    $stmt->bind_param("ss", $email, $password);  // Bind variables in order 
    $stmt->execute();        // Execute query 
    $stmt->bind_result($userID);     // Result 'id' from database is set to $userID 
    $stmt->fetch();         // ...and fetch it 
} 

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

2

Вы можете связать несколько переменных следующим образом:

Как вы можете видеть, вы можете расширить функции bind_param(). Вы также можете добавить различные типы переменных:

i corresponding variable has type integer 
d corresponding variable has type double 
s corresponding variable has type string 
b corresponding variable is a blob and will be sent in packets 

От: http://php.net/manual/en/mysqli-stmt.bind-param.php

+0

Спасибо за ваш ответ. Я попробую. Проголосовали. – Ironic

+0

Все еще это дает мне такую ​​же ошибку. Неверное имя пользователя/пароль. – Ironic

1

Прежде всего, я предлагаю вам научиться PDO вместо MySQLi, только потому, что она поддерживает больше водителей.

Во-вторых, вы можете использовать mysql_real_escape_string, как вы могли видеть, это функция MySQL, а не функция MySQLi.

Так где у вас есть:

$result = $mysqli->query("SELECT uid FROM users where email='$email' and password = '$password'"); 

Вы должны сделать что-то вроде:

<?php 
$stmt = $dbConnection->prepare("SELECT uid FROM users where email = :email AND password = :password"); 
try{ 
$stmt->execute([ 
    ':email' => $email, 
    ':password' => $password 
]); 
} 
catch(Exception $e){ 
    echo $e->getMessage(); //Remove when putting online 
} 

if($stmt->num_rows){ 
    $res['success'] = true; 
} 
?> 
+0

Спасибо за ваш ответ. Сначала я узнаю mysqli, тогда я перейду к PDO. Проголосовал. – Ironic

+0

@ 404 Если это вам помогло, нажмите кнопку под кнопкой V, чтобы отметить ее как ответ. Это поможет другим людям и в будущем. Я также хочу отметить, что вам больше не нужно использовать функцию clean() с этим, насколько я знаю. – Tom

+0

Не могли бы вы посоветовать мне использовать электронную почту и пароль как в запросе. вы дали мне пример только электронной почты. – Ironic

2

Вы в настоящее время смешивания MySQL API-интерфейсы/функции с mysql_real_escape_string(), затем num_rows, а затем ПДО метод where email=:email and password = :password связывания который, как представляется, был взят из другого ответа, данного для вашего вопроса.

  • Эти различные функции НЕ смешивают.

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

Похоже, вы желая настроить Войти сценарий.Я предлагаю вам использовать следующую команду и вытащил из одного из ответов ircmaxell в:

Вытащил из https://stackoverflow.com/a/29778421/

Просто используйте библиотеку. Шутки в сторону. Они существуют по какой-то причине.

  • PHP 5.5+: использовать password_hash()
  • PHP 5.3.7+: использовать password-compat (пакет обеспечения совместимости для выше)
  • Все остальные: использовать phpass

Не делайте это сами , Если вы создаете свою соль, ВЫ МОЖЕТЕ НЕПРАВИЛЬНО. Вы должны использовать библиотеку, которая обрабатывает это для вас.

$dbh = new PDO(...); 

$username = $_POST["username"]; 
$email = $_POST["email"]; 
$password = $_POST["password"]; 
$hash = password_hash($password, PASSWORD_DEFAULT); 

$stmt = $dbh->prepare("insert into users set username=?, email=?, password=?"); 
$stmt->execute([$username, $email, $hash]); 

А на входе:

$sql = "SELECT * FROM users WHERE username = ?"; 
$stmt = $dbh->prepare($sql); 
$result = $stmt->execute([$_POST['username']]); 
$users = $result->fetchAll(); 
if (isset($users[0]) { 
    if (password_verify($_POST['password'], $users[0]->password) { 
     // valid login 
    } else { 
     // invalid password 
    } 
} else { 
    // invalid username 
} 

Это безопаснее и использует безопасный метод хэширования паролей, а не то, что вы, кажется, хотят использовать не MD5 $password =md5($password); и больше не считается безопасным для использования в настоящее время.

Ссылки:

Sidenote: Если вы идете по этому маршруту, не забудьте прочитать руководства и что ваш парольный столбец достаточно длинный, чтобы удерживать хэш. Минимальная длина составляет 60, но они рекомендуют 255.

Также неясно, есть ли у вашей HTML-формы атрибуты имени для массивов POST, поэтому убедитесь, что форма использует метод POST.

Я считаю, что я дал вам достаточно информации, чтобы начать.


Что вы НЕ ДОЛЖНЫ делать, заключается в том, чтобы использовать вышеуказанный код и просто его исправлять. Вам нужно начать все сначала.


Добавить error reporting в верхней части файла (ов), который поможет найти ошибки.

<?php 
error_reporting(E_ALL); 
ini_set('display_errors', 1); 

// rest of your code 

Sidenote: Отображение ошибок не должно быть сделано только в постановке, и никогда производства.

+0

Спасибо за ваш ответ.Я изучаю его и буду пытаться улучшить свои знания. – Ironic

+0

@ 404 Добро пожаловать. –

+0

Какова обратная связь, если мы создадим собственную функцию hasing? – Ironic

Смежные вопросы