Web安全之SQL注入攻击技巧和防范。php web开发安全之sql注入及防范:(一)简单的select语句注入及预防。

Web安全之SQL注入攻击技巧和防范。php web开发安全之sql注入及防范:(一)简单的select语句注入及预防。

Web安全简史

当Web1.0期,人们还多是关心服务器端动态脚本语言的安康问题,比如用一个而实施脚本(俗称Webshell)通过脚本语言的纰漏上传到服务器上,从而获得服务器权限。在Web发展最初,随着动态脚本语言的提高以及普及,以及早期工程师对平安问题认知不足导致群”安全血案”的发出,至今仍遗留下许多史问题,比如PHP语言至今还无法从言语本身杜绝「文件包含漏洞」(参见这里),只能借助工程师可以的代码规范和安全意识。

陪在Web2.0、社交网络、微博等同样多样时互联网产品的勃兴,基于Web环境之互联网采用越来越普遍,Web攻击的招数为更为多样,Web安全史上之一个最主要里程碑是大体1999年发现的SQL注入攻击,之后的XSS,CSRF等攻击手段进一步强大,Web攻击的笔触也于服务端转向了客户端,转向了浏览器和用户。

每当平安世界,一般用帽子的颜色来比喻黑客的轻与恶,白帽子是据那些工作于倒黑客领域的技艺专家,这个部落是”善”的的代表;而黑帽子则是依赖那些运用黑客技术造成损坏还谋取私利造成违法之群体,他们是”恶”的象征。

“白帽子”和”黑帽子”是少数只全对立的部落。对于黑帽子而言,他们若找到网的一个切入点就可直达入侵破坏的目的,而白帽子必须用好系统所有或让突破的地方都设防,以保证系统的安康运转。

立看起好像是免公道的,但是安全世界里之规则就是是这么,可能我们的网站1000处在还布防的怪好,考虑的怪完善,但是要发生一个地方疏忽了,攻击者就会见动这点开展突破,让咱们另外的1000处于大力白费。

sql注入主要是凭借经在get、post请求参数中组织sql语句,以改程序运行时所行的sql语句,从而实现获取、修改信息还是是删除数据的目的,sql被注入的原委根本是代码编写的起题目(有漏洞),只要平时小心在编写和sql相关的代码时养成好的惯,对可能为注入的sql语句加以防范,那么在大部分气象下是好预防sql注入的。下面看下怎样不好的编码习惯易逗select语句被注入,并分析下防范措施。

普遍攻击方式

普普通通,在Web安全世界,常见的攻击方式大概发生以下几种植:
1、SQL注入攻击
2、跨站脚论攻击 – XSS
3、跨站伪造请求攻击 – CSRF
4、文件上传漏洞攻击
5、分布式拒绝服务攻击 – DDOS

说个写外话,本来就首文章一开始的标题叫做
「Web安全之常表现攻击方法和防范」,我原先想将地方的就5种艺术还满形容以一如既往篇稿子里,可是刚写了第一单SQL注入攻击的时光,就意识文章篇幅就不缺乏了,又格外麻烦再进行大的简洁,所以干脆将Web安全分成一个密密麻麻,分多首文章来显现于大家,下面你看来的就是是第一首「Web安全之SQL注入攻击的技艺和防范」。

在意:这里没有完全的php代码,可以大概假设一个情景:用户可经类似下面的url地址http://localhost/user.php?username=yang或http://localhost/user.php?uid=yang,通过get方法来请求数据库中的信息,数据库中有user、article表。

SQL注入常见攻击技巧

SQL注入攻击是Web安全史上的一个第一里程碑,它由1999年篇赖跻身人们的视线,至今已闹十几年之史了,虽然我们今天既来矣好圆满的戒备对策,但是她的威力依然拒绝轻视,SQL注入攻击至今仍是Web安全领域被之一个最主要组成部分。

因PHP+MySQL为例,让咱们为一个Web网站中最中心的用户系统来开实例演示,看看SQL注入究竟是怎么发的。

1、创建一个誉为也demo的数据库:
<pre>
CREATE DATABASE demo DEFAULT CHARACTER SET utf8 COLLATE
utf8_general_ci;
</pre>

2、创建一个名为也user的数据表,并插入1条演示数据:
<pre>
CREATE TABLE demo.user (
uid INT( 11 ) NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT
‘用户uid’,
username VARCHAR( 20 ) NOT NULL COMMENT ‘用户名’,
password VARCHAR( 32 ) NOT NULL COMMENT ‘用户密码’
) ENGINE = INNODB;
INSERT INTO demo.user (uid, username, password) VALUES (‘1’,
‘plhwin’, MD5(‘123456’));
</pre>

1,sql语句被之更迭变量不加引号
看下立刻长长的告句子 $sql = “select
uid, username from user where uid = $uid “; 
轮换变量不加引号,如果用户输入这样的$uid:$uid = ‘1 and 1=2 union select
* from article where aid = 1’;

实例一

透过传播username参数,在页面打印出这个会员的详细信息,编写
userinfo.php 程序代码:

<pre>
<?php
header(‘Content-type:text/html; charset=UTF-8’);
$username = isset($_GET[‘username’]) ? $_GET[‘username’] : ”;
$userinfo = array();
if($username){
//使用mysqli驱动连接demo数据库
$mysqli = new mysqli(“localhost”, “root”, “root”, ‘demo’);
$sql = “SELECT uid,username FROM user WHERE username='{$username}'”;
//mysqli multi_query 支持实施多长MySQL语句
$query = $mysqli->multi_query($sql);
if($query){
do {
$result = $mysqli->store_result();
while($row = $result->fetch_assoc()){
$userinfo[] = $row;
}
if(!$mysqli->more_results()){
break;
}
} while ($mysqli->next_result());
}
}
echo ‘<pre>’,print_r($userinfo, 1),'</pre>’;
</pre>

上面这个顺序一旦兑现之职能是基于浏览器传入的用户称参数,在页面及打印出之用户的详细信息,程序写的这么复杂是因自身利用了mysqli的让,以便能够下及
multi_query
方法来支持而实施多漫漫SQL语句,这样能够重复好的印证SQL注入攻击的危害性。

假若我们得经 http://localhost/test/userinfo.php?username=plhwin
这个URL来做客到具体有会员的详情,正常情况下,如果浏览器里传开的username是法定的,那么SQL语句会执行:

<pre>
SELECT uid,username FROM user WHERE username=’plhwin’
</pre>

但是,如果用户在浏览器里将传播的username参数变为
plhwin';SHOW TABLES-- hack,也即是当URL变为
http://localhost/test/userinfo.php?username=plhwin';SHOW TABLES-- hack
的当儿,此时我们先后实际施行之SQL语句变成了:

<pre>
SELECT uid,username FROM user WHERE username=’plhwin’;SHOW TABLES–
hack’
</pre>

瞩目:在MySQL中,最后连的星星个减号表示忽略这个SQL减号后面的语,我本机的MySQL版本号为5.6.12,目前几有SQL注入实例都是直接利用简单个减号结尾,但是事实上测试,这个版本号的MySQL要求简单只减号后面总得使起空格才能够正常注入,而浏览器是碰头自行删除掉URL尾部空格的,所以我们的流会于个别只减号后面统一上加任意一个字符或单词,本篇文章的SQL注入实例统一为
-- hack 结尾。

通过地方的SQL注入后,原本想使尽查询会员详情的SQL语句,此时尚格外执行了
SHOW TABLES;
语词,这明明不是开发者的原意,此时可以在浏览器里看到页面的出口:

<pre>
Array
(
[0] => Array
(
[uid] => 1
[username] => plhwin
)

[1] => Array
    (
        [Tables_in_demo] => user
    )

)
</pre>

而会清楚的看看,除了会员的信,数据库表的名user否于打印在了页面上,如果滋事的黑客此时将参数换成
plhwin';DROP TABLE user-- hack,那将产生灾难性的沉痛结果,当你当浏览器被推行
http://localhost/test/userinfo.php?username=plhwin';DROP TABLE user-- hack
这个URL后,你见面发觉全 user 数据表都消失不见了。

经过上面的事例,大家就认及SQL注入攻击的危害性,但是还是会有人心里存疑问,MySQL默认驱动的mysql_query艺术现在早已不支持多修语句以执行了,大部分开发者怎么可能像上面的演示程序那样以辛苦又非安全。

是的,在PHP程序中,MySQL是勿同意在一个mysql_query饱受使用分号执行多SQL语句之,这使广大开发者都认为MySQL本身就无同意多告知句执行了,但实际MySQL早以4.1本子就允许多告句子执行,通过PHP的源代码,我们发现其实只有是PHP语言自身限制了这种用法,具体情况大家好望就首文章「PHP+MySQL多报句执行」。

那么可以组织出这样的sql

实例二

假定系统非允而推行多长条SQL语句,那么SQL注入攻击是无是就是不再这样可怕吗?答案是否认的,我们仍以点的user数据表,用Web网站中常用的会员登录体系来开另外一个面貌实例,编写程序login.php,代码如下:

<?php
if($_POST){
$link = mysql_connect(“localhost”, “root”, “root”);
mysql_select_db(‘demo’, $link);
$username = empty($_POST[‘username’]) ? ” :
$_POST[‘username’];
$password = empty($_POST[‘password’]) ? ” :
$_POST[‘password’];
$md5password = md5($password);
$sql = “SELECT uid,username FROM user WHERE username='{$username}’ AND
password='{$md5password}'”;
$query = mysql_query($sql, $link);
$userinfo = mysql_fetch_array($query, MYSQL_ASSOC);
if(!empty($userinfo)){
//登录成功,打印出会员信息
echo ‘<pre>’,print_r($userinfo, 1),'</pre>’;
} else {
echo “用户称无存在或者密码错误!”;
}
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset=”utf-8″>
<title>Web登录系统SQL注入实例</title>
</head>
<body>
<form name=”LOGIN_FORM” method=”post” action=””>
签到帐号: <input type=”text” name=”username” value=”” size=30
/><br /><br />
签到密码: <input type=”text” name=”password” value=”” size=30
/><br /><br />
<input type=”submit” value=”登录” />
</form>
</body>
</html>

这儿若输入是的用户名 plhwin 和密码 123456,执行的SQL语句为:

<pre>
SELECT uid,username FROM user WHERE username=’plhwin’ AND
password=’e10adc3949ba59abbe56e057f20f883e’
</pre>

方语句没有任何问题,可以看看页面打印出了登录成功后底会员信息,但如发生捣蛋鬼输入的用户称也
plhwin' AND 1=1-- hack,密码任意输入,比如aaaaaa,那么拼接之后的SQL查询语句就改为了如下内容:
<pre>
SELECT uid,username FROM user WHERE username=’plhwin’ AND 1=1– hack’
AND password=’0b4e7a0e5fe84ad35fb5f95b9ceeac79′
</pre>

实施方的SQL语句,因为1=1是恒久成立的标准化,这代表黑客只待掌握别人的会员名,无需了解密码就会如愿登录到网。

select uid, username from user where uid = 1 and 1=2 union select * from article where aid = 1

争规定SQL注入漏洞

由此以上的实例,我们照样还会来问号:黑客并不知道我们程序代码的逻辑与SQL语句之写法,他是怎么样规定一个网站是否是SQL注入漏洞也?一般说来有以下2种途径:

得视结合union,就得针对其他表中的多寡进行询问。

1、错误提示

假如目标Web网站开启了左显示,攻击者就足以经过反复调整发送的参数、查看页面打印的错误信息,推测出Web网站使用的数据库与出语言等根本消息。

为此,sql语句被之变量应该要抬高引号 $sql =
“select uid, username from user where uid =
‘$uid'”; 
然就算被sql注入,被组织之sql语句也无非见面变成这样:

2、盲注

惟有运维人员大意,否则大部分的Web运营网站应当还关闭了错提示信息,此时攻击者一般会利用盲注的技巧来开展反复的品判断。
仍然因点的数额表user为条例,我们前面的查看会员详情页面的url地址为userinfo.php?username=plhwin,此时黑客分别拜访userinfo.php?username=plhwin' AND 1=1-- hackuserinfo.php?username=plhwin' AND 1=2-- hack,如果前者访问能够返正常的信息一旦后人不克,就基本好看清是网站是SQL注入漏洞,因为后者的1=2是表达式永远不起,所以就算username传入了不易的参数为束手无策通过,由这可以想见是页面是SQL注入漏洞,并且可以透过username参数进行注入。

select uid, username from user where uid = '1 and 1=2 union select * from article where aid = 1';

哪守护SQL注入

对服务器配置范围的严防,应该保证生产环境的Webserver是关错误信息的,比如PHP在养环境的布文件php.ini中之display_errors应该安装为Off,这样就是关了不当提示,下面我们还多的于编码的角度来看看如何预防SQL注入。

地方用少单实例分析了SQL注入攻击的技巧,可以看看,但凡来SQL注入漏洞的主次,都是盖程序要接受来自客户端用户输入的变量或URL传递的参数,并且这个变量或参数是构成SQL语句之同一局部,对于用户输入的内容或传递的参数,我们当要随时保持警惕,这是安世界里之「外部数据不可相信」的规范,纵观Web安全领域的各种攻击方式,大多数都是盖开发者违反了这个规则要导致的,所以自然会体悟的,就是从变量的检测、过滤、验证下手,确保变量是开发者所预期的。

这么构造出底uid就不得不是sql语句被询问参数的价值,也即起未顶注入作用了。

1、检查变量数据类型和格式

假若您的SQL语句是近似where id={$id}这种样式,数据库里所有的id都是数字,那么即使该当SQL被实施前,检查确保变量id是int类型;如果是受邮箱,那就相应检查并严厉保证变量一定是邮箱的格式,其他的类型比如日期、时间等呢是一个道理。总结起来:要是发出固定格式的变量,在SQL语句执行前,应该严格以固定格式去检查,确保变量是咱们预料的格式,这样好非常程度及足避SQL注入攻击。

仍,我们前接受username参数例子中,我们的产品设计应该是以用户注册之同样发端,就发生一个用户名的平整,比如5-20个字符,只能由大小写字母、数字以及一些安全的符号组成,不包含特殊字符。此时我们相应来一个check_username的函数来拓展统一之检查。不过,仍然发生很多例外情况并无克应用至及时同样准则,比如文章披露网,评论系统等必须使允许用户提交任意字符串的情景,这便待以了滤等任何方案了。

2,未对用户之输入进行过滤与转义

2、过滤特殊符号

对此无法确定固定格式的变量,一定要是开展特殊符号过滤或转义处理。以PHP为例,通常是行使addslashes函数,它会在指定的预约义字符前补加反斜杠转义,这些预定义的字符是:单引号 (') 双引号 (") 反斜杠 (\) NULL

来看2条SQL语句:
<pre>
$uid = isset($_GET[‘uid’]) ? $_GET[‘uid’] : 0;
$uid = addslashes(uid);
$sql = “SELECT uid,username FROM user WHERE uid='{$uid}'”;
</pre>
以及
<pre>
$uid = isset($_GET[‘uid’]) ? $_GET[‘uid’] : 0;
$uid = addslashes(uid);
$sql = “SELECT uid,username FROM user WHERE uid={$uid}”;
</pre>

地方两单查询语句都通过了php的addslashes函数过滤转义,但以安全性上也大不相同,在MySQL中,对于int类型字段的规则查询,上面只告知句的查询功能完全一致,由于第一句子SQL的变量被单引号包含起来,SQL注入的时段,黑客面临的基本点问题是必须要先关前面的单引号,这样才会要后面的言辞作为SQL执行,并且还要注释掉原SQL语句被之后的单引号,这样才堪成功注入,由于代码里采取了addslashes函数,黑客的攻击会无从下手,但次句没有用引号包含变量,那黑客也并非考虑去关、注释,所以就相同利用addslashes转义,也还是在SQL攻击漏洞。

对于PHP程序+MySQL构架的次第,在动态的SQL语句被,使用单引号把变量包含起来相当addslashes函数是应本着SQL注入攻击的有效性手段,但迅即做的还不够,像面的2条SQL语句,根据「检查数据类型」的格,uid都应经过intval函数格式为int型,这样不但能够立竿见影避免第二长告句子之SQL注入漏洞,还会令程序看起重自然,尤其是以NoSQL(如MongoDB)中,变量类型一定要是和字段类型相匹配才可以。

自打者可以视,第二单SQL语句是发漏洞的,不过出于用了addslashes函数,你晤面发现黑客的抨击语句也设有未可知采取特殊符号的规格限制,类似where username='plhwin'诸如此类的抨击语句是可望而不可及执行的,但是黑客可以将字符串转为16进制编码数据或行使char函数进行转发,同样会上平等的目的,如果对当下有些情节感兴趣,可以点击这里翻。而且由于SQL保留重要字,如「HAVING」、「ORDER
BY」的存在,即使是因黑白名单之过滤方法还会生出或多还是遗失问题,那么是否还有另外措施来防御SQL注入呢?

(1)过滤,对数码进行过滤,将那个易为自己得之格式,或者判断数格式是否合法。判断数格式是否合法这个要依照好定义的规则来进展,比如email地址格式、用户称长度以及组成、密码长度以及组成等,这里先不讨论数量格式合法性的问题。下面先简单看下格式转换问题:

3、绑定变量,使用预编译语句

MySQL的mysqli使提供了预编译语句之支撑,不同的程序语言,都分别发生采取预编译语句之措施,我们这边仍因PHP为条例,编写userinfo2.php代码:

<pre>
<?php
header(‘Content-type:text/html; charset=UTF-8’);
$username = isset($_GET[‘username’]) ? $_GET[‘username’] : ”;
$userinfo = array();
if($username){
//使用mysqli驱动连接demo数据库
$mysqli = new mysqli(“localhost”, “root”, “root”, ‘demo’);
//使用问号替代变量位置
$sql = “SELECT uid,username FROM user WHERE username=?”;
$stmt = $mysqli->prepare($sql);
//绑定变量
$stmt->bind_param(“s”, $username);
$stmt->execute();
$stmt->bind_result($uid, $username);
while ($stmt->fetch()) {
$row = array();
$row[‘uid’] = $uid;
$row[‘username’] = $username;
$userinfo[] = $row;
}
}
echo ‘<pre>’,print_r($userinfo, 1),'</pre>’;
</pre>

自打上面的代码可以看来,我们先后里连不曾动addslashes函数,但是浏览器里运行
http://localhost/test/userinfo2.php?username=plhwin' AND 1=1-- hack里得不交其它结果,说明SQL漏洞以这次里连无有。

实际上,绑定变量使用预编译语句是严防SQL注入的特级艺术,使用预编译的SQL语句语义不会见来变动,在SQL语句被,变量用问号?表示,黑客就是本事再不行,也束手无策更改SQL语句的结构,像上面例子中,username变量传递的plhwin' AND 1=1-- hack参数,也不过会当作username字符串来诠释查询,从根本上杜绝了SQL注入攻击的发生。

于以id查找的sql,因为id一般也整数,所以可以预先以用户输入的数据类型转换为int,这样就用户尝试构造$uid为:

数据库信息加密安全

深信不疑大家还还针对性2011年爆出的CSDN拖库事件记忆犹新,这桩工作导致CSDN处在风口浪尖被大家痛骂的缘由即在于他们还公开存储用户的密码,这引发了科技界对用户信息安全更是密码安全之确定性关注,我们于防止SQL注入的发生的还要,也该未雨绸缪,说不定下一个让拖库的即是你,谁知道啊。

以Web开发被,传统的加解密大致可分为三栽:

1、对如加密:即加密方和解密方都采用相同之加密算法和密钥,这种方案的密钥的保留好主要,因为算法是当面的,而密钥是保密的,一旦密匙泄露,黑客还是可以轻易解密。常见的对称加密算法来:AESDES等。

2、非对如加密:即利用不同之密钥来展开加解密,密钥被分成公钥和私钥,用私钥加密的多寡要以公钥来解密,同样用公钥加密的数量必须用相应之私钥来解密,常见的不对如加密算法有:RSA等。

3、不可逆加密:利用哈希算法使数码加密之后无法解密回原数据,这样的哈希算法常用之产生:md5SHA-1等。

当我们地方登录体系的演示代码中,$md5password = md5($password);起当下句代码可以看到运了md5的不可逆加密算法来存储密码,这为是基本上年来业界常用之密码加密算法,但是及时仍然不安全。为什么也?

立是盖md5加密有一个表征:同样的字符串经过md5哈希计算后转的加密字符串也是相同的,由于业界采用这种加密的道长期,黑客们为准备了友好强大的md5彩虹表来接向匹配加密前的字符串,这种用于逆向反推MD5加密的彩虹表在互联网及随处可见,在Google里使用md5 解密作为重点词搜索,一下就能找到md5于线破解网站,把咱插入用户数据时的MD5加以密字符串e10adc3949ba59abbe56e057f20f883e填入进,瞬间就算会获得加密前的密码:123456。当然为并无是各国一个且能学有所成,但可以得的凡,这个彩虹表会越来越健全。

从而,我们出迫切的需使重复好之方式对密码数据进行不可逆加密,通常的做法是吧每个用户确定不同之密码加盐(salt)后,再混合用户之忠实密码进行md5加密,如以下代码:

<pre>
//用户注册下装的password
$password = $_POST[‘password’];
//md5加密,传统做法直接将加密后底字符串存入数据库,但随即不够,我们后续改善
$passwordmd5 = md5($password);
//为用户生成不同之密码盐,算法可以因自己事情的待而不同
$salt = substr(uniqid(rand()), -6);
//新的加密字符串包含了密码盐
$passwordmd5 = md5($passwordmd5.$salt);
</pre>

 $uid = (int)’1 and 1=2
union select * from article where aid = 1′ ,

小结

1、不要任意敞开生产条件中Webserver的谬误显示。
2、永远不要相信来用户端的变量输入,有固定格式的变量一定要严格检查对应的格式,没有固定格式的变量需要对引号等特殊字符进行必要的过滤转义。
3、使用预编译绑定变量的SQL语句。
4、做好数据库帐号权限管理。
5、严格加密处理用户之机密信息。

它为会见被转移为数字,这当得水平上会避免被注入。

(2)对于按如username字符串类型查找的sql,面临的机要注入风险是经过在参数中长单引号、sql注释符、sql语句结束符等符号来组织sql,所以要注意将这些字符进行转义即可,也便是针对性用户输入的多少开展转义,这里涉及到零星独函数:addslashes()和
addcslashes()。addslashes()可以对单引号’、双引号”、反斜线\及NUL(NULL字符)进行转义。addcslashes()可以于定义需要转义的字符,下面来拘禁下使用addcslashes()对用户之输入进行转义。

遵循下面就漫漫sql语句:

$sql = "select uid, username from user where username = '{$username}' ";

当匪进行转义的早晚,用户可组织$username如下: yang’;SHOW TABLES– inject 
末构造出如下的sql:

select uid, username from user where username = 'yang';SHOW TABLES-- inject';

今昔我们因而addcslashes()函数对$username进行转义,

$username = isset($_GET['username']) ? addcslashes($_GET['username'], "'\"%_\\;-") : '';

顾点的语句会对下面的字符进行转义 ,可以因实际需要转义相应的字符。

' 单引号
" 双引号
% 百分号
_ 下划线
\ 反斜线
; 分号
- 小破折号

这会儿要用户构造的 yang’;SHOW TABLES– inject 就会化为这个法: yang\’\;SHOW TABLES\-\-
inject ,构造的sql会化这样:

select uid, username from user where username = 'yang\'\;SHOW TABLES\-\- inject';

可以算得惨不忍睹了,sql注入也即失效了。

3,小结

点只是简单的辨析了爱给sql注入的少个坏的编程习惯与呼应的预防,其实sql注入的不二法门、方法还有很多,所谓魔高一尺、道高一丈,需要上的地方还有为数不少。

 参考:

php程序设计

Web安全的SQL注入攻击技巧及预防

admin

网站地图xml地图