70%以上的站点存在SQL Injection漏洞,包括国内大部分安全站点。
sql注入:利用数据库的缺陷
/*
Navicat MySQL Data Transfer
Source Server : localhost_3306
Source Server Version : 50516
Source Host : localhost:3306
Source Database : spdb
Target Server Type : MYSQL
Target Server Version : 50516
File Encoding : 65001
Date: 2012-08-01 10:29:35
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for `users`
-- ----------------------------
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
`userid` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(64) NOT NULL,
`password` varchar(64) NOT NULL,
`email` varchar(64) CHARACTER SET utf8 NOT NULL,
`job` varchar(64) CHARACTER SET utf8 NOT NULL,
`sal` float NOT NULL DEFAULT '0',
PRIMARY KEY (`userid`),
UNIQUE KEY `username` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;
-- ----------------------------
-- Records of users
-- ----------------------------
INSERT INTO `users` VALUES ('1', 'admin', '111111', 'admin@qq.com', '经理', '10000');
INSERT INTO `users` VALUES ('2', 'guest', '111111', 'guest@qq.com', '职员', '5000');
<html>
<head>
<title>用户验证</title>
<meta http-equiv="content-type" content="text/html;charset=utf-8"/>
</head>
<?php
//这里我们就可以编写php代码
//接收用户提交的用户名和密码
$username=$_REQUEST['username'];
$password=$_REQUEST['password'];
//echo $username,$password;
//现在我们看到数据库验证,要怎样写出安全的代码,防止用户攻击
//1 连接数据库
$conn=mysql_connect("localhost","root","root");
//die等价于exit() 退出
if(!$conn){
die("连接数据库失败".mysql_error());
}
//2 选择数据库
mysql_selectdb("spdb",$conn) or die("连接数据库失败".mysql_error());
//3 编写sql语句,并查询
$sql="select * from users where username='$username' AND password='$password'";
$res=mysql_query($sql,$conn);
//4 查看结果
if(mysql_num_rows($res)!=0)
{
//跳转到管理页面
header("Location:ManageUsers.php");
}else{
echo "您的用户名和密码不对,<a href='Login.php'>返回</a>";
}
/*if($username=='admin'&&$password='111111'){
//跳转到管理页面
header("Location:ManageUsers.php");
}else{
//提示
echo '您的用户名和密码不对';
}*/
?>
</html>
用万能密码
select * from users where username='admin ' AND password='adfasf' or 1='1'
select * from users where username='admin1asdf ' AND password='adfasf'' or 1='1'
输入da' or 1='1
绕过登录成功
用万能用户名
select * from users where username='admin1asdf ' union select * from users;/* AND password='adfasf''
万能用户名 注入失败
select * from users where username='fa' union select * from users; /*' ' AND password=''
( ! ) Warning: mysql_num_rows() expects parameter 1 to be resource, boolean given in F:\xampp\htdocs\phptest\LoginCl.php on line 31 | ||||
---|---|---|---|---|
Call Stack | ||||
# | Time | Memory | Function | Location |
1 | 0.0033 | 339016 | {main}( ) | ..\LoginCl.php:0 |
2 | 0.0121 | 345472 | mysql_num_rows ( bool ) | ..\LoginCl.php:31 |
但是此句却能在数据库执行
select * from users where username='fa' union select * from users; /*' ' AND password=''
在用where语句中不用 ',万能密码失效
mysql中有一个特点:
会把这种语句认为是数字,会有另外一种 数字注入。
会把你的输入当成数字,输入字母会报错,仍然会被注入。
select * from users where username=78 and password=89 union select * from users
用户名输入数字:54
密码使用万能密码:89 union select * from users
照样可以注入。
万能用户名注入仍然存在问题:
select * from users where username=89 union select * from users;/* AND password=
数据库可以执行
界面无法绕过
如何解决注入问题?
————————————————————————————————————————————————————————————————————
1 服务器入手
magic_quotes_gpc 设置为on 有引号的万能用户名和万能密码失效,启用为on时,服务器就会对所有的'加入\转义。
高手仍然可以用 select char(96) from dual 来代替单引号'
但是数字的注入还是无法解决。
综上所述 写成单引号要安全些。
display_errors 设置为off
2 对于程序员来说,不一定有权限来修改服务器的设置。
我们现在使用第一种方案来防止登录用户注入
a 密码比对
首先通过用户输入的用户名,去查询数据库,如果查到了这个用户对应的密码。则和用户提交的密码比对,相同则说明该用户合法,反之则说明该用户非法。
$sql="select * from users where username='$username'";
$res=mysql_query($sql,$conn);
//取出密码
if($row=mysql_fetch_array($res)){
//说明用户存在
if($row[0]==$password){
//该用户是合法的
header("Location:ManageUsers.php");
}else{
echo "您输入的密码不正确,<a href='Login.php'>返回</a>";
}
}else{
//err
echo "您的用户名和密码不对,<a href='Login.php'>返回</a>";
}
b 用pdo方式解决防范注入
PDO php data boject 相当于是一个数据库抽象层,不同的数据库使用相同的方法名,解决数据库连接不统一的问题。
使用pdo来解决注入
first 在php.ini中启动pdo extension=php_pdo_mysql.dll 前面的分号去掉
second 可以通过名字或者?号来绑定
//pdo 1 创建一个pdo对象
$sql="select * from users where username=? and password=?";
$my_pdo=new PDO("mysql:host=localhost;port=3306;dbname=spdb", "root","root");
//pdo 2 设置编码 网页时utf-8 数据库是utf8
$my_pdo->exec("set names utf8");
//pdo 3 预处理sql
$pdoStatment=$my_pdo->prepare($sql);
//pdo 4 把接收到的用户名和密码填入
$pdoStatment->execute(array($username,$password));
//pdo 5 取出结果
$res=$pdoStatment->fetch();
if(empty($res)){
echo "您的用户名和密码不对,<a href='Login.php'>返回</a>";
}else{
header("Location:ManageUsers.php");
}
IDS 入侵检测系统