【代码实现】防止SQL注入解决办法,sql注入
文章来源:PHP开发学习门户
地址:http://www.phpthinking.com/archives/494
SQL注入是我们在程序开发过程中经常要注意的问题,属于发生于应用程序之数据库层的安全漏洞,通过构建特殊的输入作为参数传入Web应用程序,而这些输入大都是SQL语法里的一些组合,通过执行SQL语句进而执行攻击者所要的操作,其主要原因是程序没有细致地过滤用户输入的数据,致使非法数据侵入系统。
简而言之,是在输入的字符串之中注入SQL指令,在设计不良的程序当中忽略了检查,那么这些注入进去的指令就会被数据库服务器误认为是正常的SQL指令而运行,因此遭到破坏。
这是一个简单的数据表:
CREATE TABLE `user` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
`password` varchar(50) NOT NULL,
`age` smallint(3) NOT NULL,
`is_admin` tinyint(1) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
INSERT INTO `user` VALUES (’1′, ‘tom’, ’2313sdf’, ’10′, ’0′);
INSERT INTO `user` VALUES (’2′, ‘lucy’, ‘sdff234′, ’5′, ’0′);
INSERT INTO `user` VALUES (’3′, ‘teacher wang’, ‘salfdjlkvjaldf’, ’24′, ’1′);
请看下面这些sql语句:
$sql=”SELECT * from user WHERE name=’$name’ and password=’$password’;”;
情况一:
若用户通过表单提交的信息是:
$name = “tom’ or ’1′=’1″;
$password = “test”;
数据在未经检验处理的情况下,导致原本的SQL字符串被解析为:
SELECT * from user WHERE name=’tom’ or ’1′=’1′ and password=’test’;
sql执行结果为:
我们在没有输出正确密码的情况下,拿到了“tom”的信息,即用“tom”的身份登录了网站。
情况二:
若用户通过表单提交的信息是:
$name = “‘ or name!=” and is_admin=1 or ’1′=’1″;
$password = “test”;
数据在未经检验处理的情况下,导致原本的SQL字符串被解析为:
SELECT * from user WHERE name=” or name!=” and is_admin=1 or ’1′=’1′ and password=’test’;
sql执行结果为:
我们在没有输出正确用户名及密码的情况下,拿到了“teacher wang”的信息,即用“teacher wang”的身份登录了网站。
情况三:
若用户通过表单提交的信息是:
$name = “‘ ; DELETE FROM user;’”;
$password = “test”;
数据在未经检验处理的情况下,导致原本的SQL字符串被解析为:
SELECT * from user WHERE name=” ; DELETE FROM user;” and password=’test’;
sql执行结果为:
悲剧了,user表数据被清空了
如何防范SQL注入攻击:
- 在组合SQL字符串时,先针对所传入的参数作字符转义
- 如果使用PHP开发网页程序的话,亦可打开PHP的Magic quote功能自动将所有的网页传入参数,将单引号字符取代为连续2个单引号字符。
- 如果可能应该过滤以下字符:分号“;”,两个减号“–”,单引号“’”,注释“/* … */”。
- 更换危险字符。例如在PHP通过addslashes()函数保护SQL注入。
- 限制用户输入的长度,限制用户输入的取值范围。
- 为当前应用建立权限比较小的数据库用户,这样不会导致数据库管理员丢失。
php代码实现:
function mysql_prepare_for_request($value, $type = “string”) {
$return = $value;
switch ($type) {
case “string” :
// 去除斜杠
if (get_magic_quotes_gpc ()) {
$return = stripslashes ( $return );
}
//配置连接有效数据库
$con = mysql_connect ( ‘localhost’, ‘root’, ‘root’ );//填写正确的用户名,密码
if (! $con) {
die ( ‘Could not connect: ‘ . mysql_error () );
}
$return = mysql_real_escape_string ( $return );
mysql_close ( $con );
break;
case “number” :
if (! is_numeric ( $return )) {
$return = 0;
}
break;
default :
$return = “”;
break;
}
return $return;
}
//情况一:用户输入
$name = “tom’ or ’1′=’1″;
$password = “test”;
$sql=”SELECT * from user WHERE name=’$name’ and password=’$password’;”;
echo “危险:”.$sql.”<br/>”;
//数据转义过滤
$name = mysql_prepare_for_request ( $name, ‘string’ );
$password = mysql_prepare_for_request ( $password, ‘string’ );
$sql=”SELECT * from user WHERE name=’$name’ and password=’$password’;”;
echo “安全:”.$sql.”<br/><br/>”;
//情况二:用户输入
$name = “‘ or name!=” and is_admin=1 or ’1′=’1″;
$password = “test”;
$sql=”SELECT * from user WHERE name=’$name’ and password=’$password’;”;
echo “危险:”.$sql.”<br/>”;
//数据转义过滤
$name = mysql_prepare_for_request ( $name, ‘string’ );
$password = mysql_prepare_for_request ( $password, ‘string’ );
$sql=”SELECT * from user WHERE name=’$name’ and password=’$password’;”;
echo “安全:”.$sql.”<br/><br/>”;
//情况三:用户输入
$name = “‘ ; DELETE FROM user;’”;
$password = “test”;
$sql=”SELECT * from user WHERE name=’$name’ and password=’$password’;”;
echo “危险:”.$sql.”<br/>”;
//数据转义过滤
$name = mysql_prepare_for_request ( $name, ‘string’ );
$password = mysql_prepare_for_request ( $password, ‘string’ );
$sql=”SELECT * from user WHERE name=’$name’ and password=’$password’;”;
echo “安全:”.$sql.”<br/><br/>”;
输出结果:
危险:SELECT * from user WHERE name=’小明’ or ’1′=’1′ and password=’test’;
安全:SELECT * from user WHERE name=’小明\’ or \’1\’=\’1′ and password=’test’;
危险:SELECT * from user WHERE name=” or name!=” and is_admin=1 or ’1′=’1′ and password=’test’;
安全:SELECT * from user WHERE name=’\’ or name!=\’\’ and is_admin=1 or \’1\’=\’1′ and password=’test’;
危险:SELECT * from user WHERE name=” ; DELETE FROM user;” and password=’test’;
安全:SELECT * from user WHERE name=’\’ ; DELETE FROM user;\” and password=’test’;
下载源码 (点击地址最下面即可)
防不了啥. 要防SQL 注入的最好办法,是用存储过程.
1、对,限制用户输入肯定有效
2、应该也可以做到,但正则不是一种高效的方法,用HtmlEncode的方法可以有效防止空格等被DBMS解释,但注意别把编码、解码搞反了;存储过程是DBMS执行的一段程序,把数据操纵交给存储过程执行,而不是提交SQL语句,可以有效防止SQL注入。
3、地址栏的Sql攻击,下面我引用了一段资料解释,他关于机制说的较清楚,关于解决,只是从客户端考虑的,实际上用存储过程等都可以防范。
资料:
首先,入侵者会对一个网站确定可不可以进行注入,假设一篇文章的地址为:www.naohou.cn/show.asp?id=325一般会以提交两个地址来测试,如:
www.naohou.cn/show.asp?id=325 and 1=1
www.naohou.cn/show.asp?id=325 and 1=2
第一个地址后面加了 and 1=1,构成的SQL语句也就变为了:Select * from 表单名 where id=1 and 1=1这句话要成立就必须and前后语句都成立。那么前面的文章地址是可以访问的,后面的1=1也是客观成立的,那么第一个地址就可以正常显示;相反1=2是显然不成立的,关键就看这步了,如果提交and 1=2页面还是正常显示说明他并没有将and 1=2写入SQL语句,此站也就不存在注入漏洞;但如果提交and 1=2之后返回了错误页面则说明此站点将后面的语句带入了SQL语句并执行了,也就说明他可以进行SQL注入。(注:如果地址后面跟的是news.asp?id='1'就得变为news.asp?id=1' and '1'='1来补全引号了)
那么,知道可以注入后入侵者可以做什么呢?
这里就简单的说一下,比如提交这样的地址:
www.naohou.cn/show.asp?id=325 and exists (select * from 表名 where 列名=数据)
根据返回的正确或错误页面来判断猜的表名和列名是否正确,具体实现时是先猜表名再猜列名。当猜出表名和列名之后还可以用ASC和MID函数来猜出各列的数据。MID函数的格式为:mid(变量名,第几个字符开始读取,读取几个字符),比如:mid(pwd,1,2)就可以从变量pwd中的第一位开始读取两位的字符。ASC函数的格式为:ASC("字符串"),如:asc("a")就可以读出字母a的ASCII码了。那么实际应用的时候就......余下全文>>