2013-07-23 2 views
-1

У меня были проблемы в прошлом с mySQL-инъекциями, поэтому я написал новый скрипт входа с использованием подготовленных инструкций PDO. Я был бы очень благодарен, если бы кто-то мог их ослепить и сообщить мне, если он достаточно безопасен для использования на моих сайтах.Может ли кто-нибудь сказать, защищен ли мой скрипт входа?

код выглядит следующим образом:

if(isset($_POST['login'])&& !empty($_POST['username']) && !empty($_POST['password'])) 
{ 

$username=$_POST['username']; 
$password=sha1($_POST['password']); 

$sql = "SELECT * FROM admin WHERE username ='".$username."' AND password = '".$password."'"; 

$result = $PDOdbh->query($sql)->fetchAll(); 

$check = count($result); 

if($check > '0') { 
$_SESSION['loggedin'] = "1"; 
$_SESSION['username'] = "".$username.""; 
header("Location: index.php"); 
} 

else { 
$_SESSION['loggedin'] = "0"; 
$_SESSION['username'] = ""; 
header ("Location: login.php?error"); 
} 

} 

if(isset($_POST['login'])&& empty($_POST['username']) && empty($_POST['password'])) 
{ 
header ("Location: login.php?missing"); 
} 

На моей странице index.php в админке у меня есть вызов следующей функции:

function checkloggedin() { 
if($_SESSION['loggedin'] == "0" || $_SESSION['loggedin'] !== "1" || $_SESSION['username'] == "") { 
header("Location: login.php"); 
exit; 
} 
} 
+5

* «подготовленный отчет PDO» * Где это подготовленное заявление PDO, о котором вы говорите? – NullUserException

+1

Нет, это не безопасно; вы добавляете $ _POST ['username'] в свой запрос, не избегая его. Это огромная уязвимость SQL-инъекций. Если вы используете PDO, почему вы не используете подготовленный оператор и связанные параметры? – andrewsi

+1

Похоже, что кто-то может сделать инъекцию sql со своим именем пользователя – StephenTG

ответ

4

Чтобы ответить на ваш вопрос, чувак, ваш код все еще уязвим для SQL Injection. Он даже не использует подготовленное заявление. (Это не ясно, что вы понимаете, что подготовленное утверждение.)

Итак, вот пример подготовленного заявления:

$stmt = $PDOdbh->prepare("SELECT 1 FROM admin WHERE username = :p1 AND password = :p2"); 
$stmt->bindParam(':p1', $username); 
$stmt->bindParam(':p2', $password); 
if ($stmt->execute()) { 
    while ($row = $stmt->fetch()) { 
     // we got a row back 
    } 
} 

Обратите внимание на «prepare» метод и метод «bindParam». В качестве «подготовленного заявления» мы ссылаемся на $stmt. (Возможно, это связано с тем, что это возврат от вызова метода «prepare», но кто действительно знает?)

(Очевидно, что это всего лишь пример, фактический доход от подготовки должен быть проверен, чтобы проверить, что метод преуспел, и не выдал ошибку.)

Учитывая вашу новую попытку, вы даже не понимаете, что такое уязвимость SQL Injection, как ее идентифицировать.

Чтобы проиллюстрировать, как SQL Injection работы, давайте рассмотрим очень простой пример, и рассмотрим эти значения:

$user = "a' OR 1=1 -- "; 
$pass = "doodah"; 
$sql = "SELECT * FROM admin WHERE username = '".$user."' AND password = '".$pass."'"; 

содержимое $sql вычисляется в

SELECT * FROM admin WHERE username ='a' OR 1=1 -- ' AND password = 'doodah' 

Когда что отправляется в базу данных , все, что следует за --, будет рассматриваться как комментарий, так что это действительно эквивалентно:

SELECT * FROM admin WHERE username ='a' OR 1=1 

Если этот оператор выполнен, если в таблице администратора есть хотя бы одна строка (а таблица администратора существует, и у нас есть привилегия выбора в таблице, а столбец имени пользователя существует в таблице и т. Д.), То это оператор вернет хотя бы одну строку.


Далее, рассмотрим еще более знакомый пример:

$username = "Robert'; DROP TABLE students; -- "; 

"Little Bobby Tables we call him" http://xkcd.com/327/:


Используя подготовленное заявление, является одним из способов уменьшения этого типа SQL Injection уязвимости.

Из подготовленного оператора (в образце в верхней части вопроса), текст SQL отправляется в базу данных (*) является:

SELECT 1 FROM admin WHERE username = :p1 AND password = :p2 

Это постоянная строка. И значения, указанные для :p1 и :p2 (при выполнении оператора), могут ТОЛЬКО интерпретироваться как значения. Невозможно, чтобы содержимое этих значений оценивалось как синтаксис SQL, например ключевые слова, идентификаторы или разделители. (Это справедливо только в контексте этой подготовленной инструкции SQL. В случае других операторов, таких как INSERT, значения, назначенные столбцам, могут быть доступны TRIGGER, и, возможно, кто-то создал уязвимость в триггере .)

(*) В случае с MySQL это не совсем так; сервер фактически не принимает подготовленные операторы так же, как это делают другие базы данных. В MySQL клиентская библиотека обрабатывает подготовленный оператор и делает безопасную (правильно экранированную) замену заполнителей связывания.

+0

Это чрезвычайно полезно! Большое спасибо. –

+0

@Pete Naylor: Я рад, что это было полезно для вас. Это должно дать вам возможность взглянуть на код, который генерирует SQL, и оценить, является ли он уязвимым для SQL Injection. Это уязвимы не только переменные $ _POST [], они просто становятся объектами с веб-страницы. Имейте в виду, что Маленькие Таблицы Бобби могут скрываться в другом хранилище, в котором переменные $ _POST. – spencer7593

0

Спасибо за ваши комментарии (Ну некоторые из них)

Я изменил мой код, смотрите ниже. Должен ли я по-прежнему добавлять mysql_real_escape_string к значениям $ _POST? Спасибо!

if(isset($_POST['login'])&& !empty($_POST['username']) && !empty($_POST['password'])) 
{ 

$username=$_POST['username']; 
$password=sha1($_POST['password']); 

$stmt = $PDOdbh->prepare("SELECT * FROM admin WHERE username = :p1 AND password = :p2"); 
$stmt->bindParam(':p1', $username); 
$stmt->bindParam(':p2', $password); 
if ($stmt->execute()) { 
$row = $stmt->fetch(); 
    if($row) { // Entry found in DB 
     $_SESSION['loggedin'] = "1"; 
     $_SESSION['username'] = "".$username.""; 
     header("Location: index.php"); 
    } 
    else { // Entry not found in DB 
     $_SESSION['loggedin'] = "0"; 
     $_SESSION['username'] = ""; 
     header ("Location: login.php?error"); 
    } 
} 
} 

if(isset($_POST['login'])&& empty($_POST['username']) && empty($_POST['password'])) 
{ 
header ("Location: login.php?missing"); 
} 
+1

Оператор SELECT в этом коде является подготовленным оператором. Это не уязвимо для SQL Injection. – spencer7593

+0

Благодарим вас за помощь, я очень благодарен. –

+1

Вам все равно нужно обернуть переменные '$ _POST []' в вызовы 'mysql_real_escape_string'? ** Нет **. Поскольку вы используете PDO и подготовленные операторы, вам не нужно (или хотите) использовать 'mysql_real_escape_string.'. Эта функция была частью старого интерфейса mysql_, который устарел и заменен вашим выбором два разных интерфейса: ** mysqli ** и ** PDO **. Функция 'mysql_real_escape_string' была функцией, которую мы назвали, что сделало значения« безопасными »(с точки зрения SQL-инъекций) включенными как часть текста SQL. – spencer7593

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