首先来看下不做任何处理的php登录,首先是HTML页面代码
<html> <head><title>用户登录</title></head> <body> <fieldset> <legend><h3>用户登录</h3></legend> <form action="user_login_pro.php" method="post"> 用户账号:<input type="text" name="name"><br><br> 用户密码:<input type="password" name="password"><br><br> <input type="submit" value="登录"> </form> </fieldset> </body> </html>
其次是php处理代码:
//引入PDO连库文件 require './database/db.php'; $name = $_POST['name']; $password = $_POST['password']; $sql = "select * from user where name ='{$name}' and password ='{$password}'"; $res = $pdo->query($sql); $row = $res->fetch(PDO::FETCH_ASSOC); if($row){ echo "login success"; }else{ echo "login error"; }
页面效果:
从上面的代码可见,我们输入账户名密码后,进入处理页面,与数据库作对比,如果账号密码都正确的情况之下,输出login success ,错误则输出login error。运行效果也正常,但如果我们在账户名处输入如下代码【' or 1=1 #】也会输出login success。这就是sql注入,通过一些代码改变了我们的sql语句,我们输出一次sql语句是什么样子的呢?select * from user where name ='' or 1=1 #' and password ='';可以发现这条sql语句变成了恒成立的语句,诸如此类的方式其实有很多,那么我们怎么防止sql注入呢?
1.使用pdo预处理
//1.准备预处理语句 $sql = "select * from user where name =? and password =?"; $res = $pdo->prepare($sql); //2.绑定参数 $name = $_POST['name']; $password = $_POST['password']; $res->bindParam(1,$name); $res->bindparam(2,$password); //3.执行预处理语句 $res->execute(); //4.转成一条结果 $row = $res->fetch(PDO::FETCH_ASSOC); //5.判断 if($row){ echo "login success"; }else{ echo "login error"; }
我们用?占位符把公共的操作部分 与 可变的数据部分相分离。根据上面的步骤执行一遍,再用 【' or 1=1 #】去测试,输出login error。成功防止。
2.addslashes()函数转义
$name = addslashes($_POST['name']); $password = $_POST['password']; $sql = "select * from user where name ='{$name}' and password ='{$password}'"; //print_r($sql);die(); $res = $pdo->query($sql); $row = $res->fetch(PDO::FETCH_ASSOC); if($row){ echo "login success"; }else{ echo "login error"; }
还用上面的sql注入,结果也是失败的。证明防止成功。addslashes() 函数在指定的预定义字符前添加反斜杠。这些字符是单引号(')、双引号(")、反斜线(\)与NUL(NULL字符)。在使用这种方式后,sql语句就变为了:select * from user where name ='\' or 1=1 #' and password ='1234567';
3.intval()
在很多时候我们要用到类似xxx.php?id=xxx这样的URL,一般来说$id都是整型变量,为了防范攻击者把$id篡改成攻击语句,我们要尽量强制变量,PHP防范SQL注入的代码$id=intval($_GET['id']);
//intval() 防止整数类型被改变 $id="abc123"; echo intval($id);
输出结果为0;可以知道intval()可以将字符串转成整数,故而可以防止整数类型被改变。