2013-07-23 2 views
-1

J'ai eu des problèmes avec les attaques par injection mySQL, j'ai donc écrit un nouveau script de connexion en utilisant des instructions préparées par PDO. Je serais très reconnaissant si quelqu'un peut y jeter un coup d'oeil et me faire savoir si c'est assez sécurisé pour utiliser sur mes sites.Quelqu'un peut-il me dire si mon script de connexion est sécurisé?

code

est la suivante:

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"); 
} 

Sur ma page index.php au sein de l'administration, j'ai un appel à la fonction suivante:

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

* "Déclaration préparée par PDO" * D'où cette déclaration préparée par PDO dont vous parlez? – NullUserException

+1

Non, ce n'est pas sécurisé; vous ajoutez $ _POST ["nom d'utilisateur"] dans votre requête, sans l'échapper. C'est une énorme vulnérabilité d'injection SQL. Si vous utilisez PDO, pourquoi n'utilisez-vous pas une instruction préparée et des paramètres liés? – andrewsi

+1

On dirait que quelqu'un pourrait faire l'injection sql avec leur nom d'utilisateur – StephenTG

Répondre

4

Pour répondre à votre question, mec, votre code est toujours vulnérable à l'injection SQL. Il n'utilise même pas une déclaration préparée. (On ne sait pas que vous comprenez ce qu'est une déclaration préparée est.)

Alors, voici un exemple d'une déclaration préparée:

$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 
    } 
} 

Notez la méthode « prepare » et la méthode « bindParam ». Nous nous référons à $stmt comme "instruction préparée". (Cela peut avoir quelque chose à voir avec le fait que c'est le retour d'un appel à une méthode appelée "prepare", mais qui sait vraiment?)

(De toute évidence, ceci est juste un exemple, le rendement réel de préparer devrait Vérifié pour vérifier que la méthode a réussi et n'a pas généré d'erreur.)

Étant donné votre nouvelle tentative, vous ne semblez même pas comprendre ce qu'est réellement une vulnérabilité d'injection SQL, ni comment l'identifier.

Pour illustrer le fonctionnement d'injection SQL, nous allons prendre un exemple très simple, et considèrent ces valeurs:

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

le contenu de $sql est évaluée à

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

Quand cela est envoyé à la base de données , tout ce qui suit le -- sera vu comme un commentaire, donc c'est vraiment équivalent à:

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

Lorsque cette instruction est exécutée, s'il y a au moins une ligne dans la table d'administration (et que la table admin existe et que nous avons un privilège select sur la table, la colonne username existe dans la table) déclaration retournera au moins une ligne.


De plus, prenons un exemple encore plus familier:

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

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


l'aide d'une instruction préparée est une façon de limiter ce type de vulnérabilité d'injection SQL.

De l'instruction préparée (en l'échantillon en haut de la question), le texte SQL envoyé à la base de données (*) est:

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

C'est une constante chaîne. Et les valeurs fournies pour :p1 et :p2 (lorsque l'instruction est exécutée) peuvent UNIQUEMENT être interprétées comme des valeurs. Il n'est pas possible que le contenu de ces valeurs soit évalué en tant que syntaxe SQL, comme les mots-clés, les identificateurs ou les délimiteurs. (Cela n'est vrai que dans le contexte de cette instruction SQL préparée.Dans le cas d'autres instructions, comme un INSERT, les valeurs assignées aux colonnes pourraient être accédées par un TRIGGER, et il est possible que quelqu'un ait créé une vulnérabilité dans le trigger.

(*) Dans le cas de MySQL, ce n'est pas tout à fait vrai; le serveur n'accepte pas réellement les instructions préparées, de la même manière que les autres bases de données. Avec MySQL, la bibliothèque cliente gère l'instruction préparée et effectue une substitution sûre (correctement échappée) des espaces réservés de rattachement.

+0

Ceci est extrêmement utile! Merci beaucoup. –

+0

@Pete Naylor: Je suis content que cela vous ait été utile. Cela devrait vous donner un moyen de regarder le code qui génère du SQL, et d'évaluer s'il est vulnérable à l'injection SQL. Ce ne sont pas seulement les variables $ _POST [] qui sont vulnérables, il s'agit simplement de cibles faciles à partir d'une page Web. Sachez que les tableaux Little Bobby peuvent se cacher dans une banque de données autre que les variables $ _POST. – spencer7593

0

Merci pour vos commentaires (bien certains d'entre eux)

J'ai modifié mon code, voir ci-dessous. Ai-je encore besoin d'ajouter mysql_real_escape_string aux valeurs $ _POST? Je vous remercie!

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

L'instruction SELECT dans ce code est une instruction préparée. Ce n'est pas vulnérable à l'injection SQL. – spencer7593

+0

Merci pour votre aide, je l'apprécie vraiment. –

+1

Avez-vous toujours besoin d'intégrer les variables '$ _POST []' dans les appels à mysql_real_escape_string'? ** Non. ** Comme vous utilisez des instructions PDO et préparées, vous n'avez pas besoin (ou ne voulez pas) d'utiliser mysql_real_escape_string. Cette fonction faisait partie de l'ancienne interface mysql_, qui est obsolète et remplacée par votre choix de deux interaces différents: ** mysqli ** et ** AOP **. La fonction 'mysql_real_escape_string' était la fonction que nous appelions qui faisait des valeurs" safe "(en termes de SQL Injection) à inclure dans le texte SQL. – spencer7593

Questions connexes