ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

SQL 注入如何进行攻击与如何防护!!!

SQL 注入如何进行攻击与如何防护!!! Web安全简史在Web1.0时代人们更多是关注服务器端动态脚本语言的安全问题比如将一个可执行脚本俗称Webshell通过脚本语言的漏洞上传到服务器上从而获得服务器权限。在Web发展初期随着动态脚本语言的发展和普及以及早期工程师对安全问题认知不足导致很多”安全血案”的发生至今仍然遗留下许多历史问题比如PHP语言至今仍然无法从语言本身杜绝「文件包含漏洞」参见这里只能依靠工程师良好的代码规范和安全意识。伴随着Web2.0、社交网络、微博等一系列新型互联网产品的兴起基于Web环境的互联网应用越来越广泛Web攻击的手段也越来越多样Web安全史上的一个重要里程碑是大约1999年发现的SQL注入攻击之后的XSSCSRF等攻击手段愈发强大Web攻击的思路也从服务端转向了客户端转向了浏览器和用户。在安全领域一般用帽子的颜色来比喻黑客的善与恶白帽子是指那些工作在反黑客领域的技术专家这个群体是”善”的的象征而黑帽子则是指那些利用黑客技术造成破坏甚至谋取私利造成犯罪的群体他们是”恶”的代表。“白帽子”和”黑帽子”是两个完全对立的群体。对于黑帽子而言他们只要找到系统的一个切入点就可以达到入侵破坏的目的而白帽子必须将自己系统所有可能被突破的地方都设防以保证系统的安全运行。这看起来好像是不公平的但是安全世界里的规则就是这样可能我们的网站1000处都布防的很好考虑的很周到但是只要有一个地方疏忽了攻击者就会利用这个点进行突破让我们另外的1000处努力白费。常见攻击方式一般说来在Web安全领域常见的攻击方式大概有以下几种1、SQL注入攻击2、跨站脚本攻击 - XSS3、跨站伪造请求攻击 - CSRF4、文件上传漏洞攻击5、分布式拒绝服务攻击 - DDOS限于篇幅本篇只讨论SQL注入攻击的技巧与防范。SQL注入常见攻击技巧SQL注入攻击是Web安全史上的一个重要里程碑它从1999年首次进入人们的视线至今已经有十几年的历史了虽然我们现在已经有了很全面的防范对策但是它的威力仍然不容小觑SQL注入攻击至今仍然是Web安全领域中的一个重要组成部分。以PHPMySQL为例让我们以一个Web网站中最基本的用户系统来做实例演示看看SQL注入究竟是怎么发生的。1、创建一个名为demo的数据库CREATEDATABASEdemoDEFAULTCHARACTERSETutf8COLLATEutf8_general_ci;2、创建一个名为user的数据表并插入1条演示数据CREATETABLEdemo.user(uidINT(11)NOTNULLAUTO_INCREMENTPRIMARYKEYCOMMENT用户uid,usernameVARCHAR(20)NOTNULLCOMMENT用户名,passwordVARCHAR(32)NOTNULLCOMMENT用户密码)ENGINEINNODB;INSERTINTOdemo.user(uid,username,password)VALUES(1,plhwin,MD5(123456));实例一通过传入username参数在页面打印出这个会员的详细信息编写 userinfo.php 程序代码?phpheader(Content-type:text/html; charsetUTF-8);$usernameisset($_GET[username])?$_GET[username]:;$userinfoarray();if($username){ //使用mysqli驱动连接demo数据库 $mysqlinewmysqli(localhost,root,root,demo); $sqlSELECT 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()); }}echopre,print_r($userinfo,1),/pre;上面这个程序要实现的功能是根据浏览器传入的用户名参数在页面上打印出这个用户的详细信息程序写的这么复杂是因为我采用了mysqli的驱动以便能使用到 multi_query 方法来支持同时执行多条SQL语句这样能更好的说明SQL注入攻击的危害性。假设我们可以通过 http://localhost/test/userinfo.php?usernameplhwin 这个URL来访问到具体某个会员的详情正常情况下如果浏览器里传入的username是合法的那么SQL语句会执行SELECT uid,username FROM user WHERE usernameplhwin但是如果用户在浏览器里把传入的username参数变为 plhwin’;SHOW TABLES-- hack也就是当URL变为 http://localhost/test/userinfo.php?usernameplhwin’;SHOW TABLES-- hack 的时候此时我们程序实际执行的SQL语句变成了SELECTuid,usernameFROMuserWHEREusernameplhwin;SHOWTABLES-- hack注意在MySQL中最后连续的两个减号表示忽略此SQL减号后面的语句我本机的MySQL版本号为5.6.12目前几乎所有SQL注入实例都是直接采用两个减号结尾但是实际测试这个版本号的MySQL要求两个减号后面必须要有空格才能正常注入而浏览器是会自动删除掉URL尾部空格的所以我们的注入会在两个减号后面统一添加任意一个字符或单词本篇文章的SQL注入实例统一以 – hack 结尾。经过上面的SQL注入后原本想要执行查询会员详情的SQL语句此时还额外执行了 SHOW TABLES; 语句这显然不是开发者的本意此时可以在浏览器里看到页面的输出Array([0]Array([uid]1[username]plhwin)[1]Array([Tables_in_demo]user))你能清晰的看到除了会员的信息数据库表的名字user也被打印在了页面上如果作恶的黑客此时将参数换成 plhwin’;DROP TABLE user-- hack那将产生灾难性的严重结果当你在浏览器中执行 http://localhost/test/userinfo.php?usernameplhwin’;DROP TABLE user-- hack 这个URL后你会发现整个 user 数据表都消失不见了。通过上面的例子大家已经认识到SQL注入攻击的危害性但是仍然会有人心存疑问MySQL默认驱动的mysql_query方法现在已经不支持多条语句同时执行了大部分开发者怎么可能像上面的演示程序那样又麻烦又不安全。是的在PHP程序中MySQL是不允许在一个mysql_query中使用分号执行多SQL语句的这使得很多开发者都认为MySQL本身就不允许多语句执行了但实际上MySQL早在4.1版本就允许多语句执行通过PHP的源代码我们发现其实只是PHP语言自身限制了这种用法具体情况大家可以看看这篇文章「PHPMySQL多语句执行」。实例二如果系统不允许同时执行多条SQL语句那么SQL注入攻击是不是就不再这么可怕呢答案是否定的我们仍然以上面的user数据表用Web网站中常用的会员登录系统来做另外一个场景实例编写程序login.php代码如下?phpif($_POST){ $linkmysql_connect(localhost,root,root); mysql_select_db(demo,$link); $usernameempty($_POST[username])?:$_POST[username]; $passwordempty($_POST[password])?:$_POST[password]; $md5passwordmd5($password); $sqlSELECT uid,username FROM user WHERE username{$username} AND password{$md5password}; $querymysql_query($sql,$link); $userinfomysql_fetch_array($query,MYSQL_ASSOC); if(!empty($userinfo)){ //登录成功打印出会员信息 echopre,print_r($userinfo,1),/pre; }else{ echo用户名不存在或密码错误; }}? !DOCTYPE html html head meta charsetutf-8 titleWeb登录系统SQL注入实例/title /head body form nameLOGIN_FORM methodpost action 登录帐号: input typetext nameusername value size30 /br /br / 登录密码: input typetext namepassword value size30 /br /br / input typesubmit value登录 / /form /body /html此时如果输入正确的用户名 plhwin 和密码 123456执行的SQL语句为SELECT uid,username FROM user WHERE usernameplhwin AND passworde10adc3949ba59abbe56e057f20f883e上面语句没有任何问题可以看到页面打印出了登录成功后的会员信息但如果有捣蛋鬼输入的用户名为 plhwin’ AND 11-- hack密码随意输入比如 aaaaaa那么拼接之后的SQL查询语句就变成了如下内容SELECT uid,username FROM user WHERE usernameplhwin AND 11-- hack AND password0b4e7a0e5fe84ad35fb5f95b9ceeac79执行上面的SQL语句因为 11 是永远成立的条件这意味着黑客只需要知道别人的会员名无需知道密码就能顺利登录到系统。如何确定SQL注入漏洞通过以上的实例我们仍然还会有疑问黑客并不知道我们程序代码的逻辑和SQL语句的写法他是如何确定一个网站是否存在SQL注入漏洞呢一般说来有以下2种途径1、错误提示如果目标Web网站开启了错误显示攻击者就可以通过反复调整发送的参数、查看页面打印的错误信息推测出Web网站使用的数据库和开发语言等重要信息。2、盲注除非运维人员疏忽否则大部分的Web运营网站应该都关闭了错误提示信息此时攻击者一般会采用盲注的技巧来进行反复的尝试判断。 仍然以上面的数据表user为例我们之前的查看会员详情页面的url地址为 userinfo.php?usernameplhwin此时黑客分别访问 userinfo.php?usernameplhwin’ AND 11-- hack 和 userinfo.php?usernameplhwin’ AND 12-- hack如果前者访问能返回正常的信息而后者不能就基本可以判断此网站存在SQL注入漏洞因为后者的 12 这个表达式永远不成立所以即使username传入了正确的参数也无法通过由此可以推断这个页面存在SQL注入漏洞并且可以通过username参数进行注入。如何防御SQL注入对于服务器配置层面的防范应该保证生产环境的Webserver是关闭错误信息的比如PHP在生产环境的配置文件php.ini中的display_errors应该设置为Off这样就关闭了错误提示下面我们更多的从编码的角度来看看如何防范SQL注入。上面用两个实例分析了SQL注入攻击的技巧可以看到但凡有SQL注入漏洞的程序都是因为程序要接受来自客户端用户输入的变量或URL传递的参数并且这个变量或参数是组成SQL语句的一部分对于用户输入的内容或传递的参数我们应该要时刻保持警惕这是安全领域里的「外部数据不可信任」的原则纵观Web安全领域的各种攻击方式大多数都是因为开发者违反了这个原则而导致的所以自然能想到的就是从变量的检测、过滤、验证下手确保变量是开发者所预想的。1、检查变量数据类型和格式如果你的SQL语句是类似where id{$id}这种形式数据库里所有的id都是数字那么就应该在SQL被执行前检查确保变量id是int类型如果是接受邮箱那就应该检查并严格确保变量一定是邮箱的格式其他的类型比如日期、时间等也是一个道理。总结起来只要是有固定格式的变量在SQL语句执行前应该严格按照固定格式去检查确保变量是我们预想的格式这样很大程度上可以避免SQL注入攻击。比如我们前面接受username参数例子中我们的产品设计应该是在用户注册的一开始就有一个用户名的规则比如5-20个字符只能由大小写字母、数字以及一些安全的符号组成不包含特殊字符。此时我们应该有一个check_username的函数来进行统一的检查。不过仍然有很多例外情况并不能应用到这一准则比如文章发布系统评论系统等必须要允许用户提交任意字符串的场景这就需要采用过滤等其他方案了。2、过滤特殊符号对于无法确定固定格式的变量一定要进行特殊符号过滤或转义处理。以PHP为例通常是采用addslashes函数它会在指定的预定义字符前添加反斜杠转义这些预定义的字符是单引号 () 双引号 () 反斜杠 (\) NULL。来看2条SQL语句$uidisset($_GET[uid])?$_GET[uid]:0;$uidaddslashes(uid);$sqlSELECT uid,username FROM user WHERE uid{$uid};以及$uidisset($_GET[uid])?$_GET[uid]:0;$uidaddslashes(uid);$sqlSELECT uid,username FROM user WHERE uid{$uid};上面两个查询语句都经过了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 usernameplhwin’这样的攻击语句是没法执行的但是黑客可以将字符串转为16进制编码数据或使用char函数进行转化同样能达到相同的目的如果对这部分内容感兴趣可以点击这里查看。而且由于SQL保留关键字如「HAVING」、「ORDER BY」的存在即使是基于黑白名单的过滤方法仍然会有或多或少问题那么是否还有其他方法来防御SQL注入呢3、绑定变量使用预编译语句MySQL的mysqli驱动提供了预编译语句的支持不同的程序语言都分别有使用预编译语句的方法我们这里仍然以PHP为例编写userinfo2.php代码?phpheader(Content-type:text/html; charsetUTF-8);$usernameisset($_GET[username])?$_GET[username]:;$userinfoarray();if($username){ //使用mysqli驱动连接demo数据库 $mysqlinewmysqli(localhost,root,root,demo); //使用问号替代变量位置 $sqlSELECT 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()){ $rowarray(); $row[uid]$uid; $row[username]$username; $userinfo[]$row; }}echopre,print_r($userinfo,1),/pre;从上面的代码可以看到我们程序里并没有使用addslashes函数但是浏览器里运行 http://localhost/test/userinfo2.php?usernameplhwin’ AND 11-- hack 里得不到任何结果说明SQL漏洞在这个程序里并不存在。实际上绑定变量使用预编译语句是预防SQL注入的最佳方式使用预编译的SQL语句语义不会发生改变在SQL语句中变量用问号?表示黑客即使本事再大也无法改变SQL语句的结构像上面例子中username变量传递的 plhwin’ AND 11-- hack 参数也只会当作username字符串来解释查询从根本上杜绝了SQL注入攻击的发生。数据库信息加密安全相信大家都还对2011年爆出的CSDN拖库事件记忆犹新这件事情导致CSDN处在风口浪尖被大家痛骂的原因就在于他们竟然明文存储用户的密码这引发了科技界对用户信息安全尤其是密码安全的强烈关注我们在防范SQL注入的发生的同时也应该未雨绸缪说不定下一个被拖库的就是你谁知道呢。在Web开发中传统的加解密大致可以分为三种:1、对称加密即加密方和解密方都使用相同的加密算法和密钥这种方案的密钥的保存非常关键因为算法是公开的而密钥是保密的一旦密匙泄露黑客仍然可以轻易解密。常见的对称加密算法有AES、DES等。2、非对称加密即使用不同的密钥来进行加解密密钥被分为公钥和私钥用私钥加密的数据必须使用公钥来解密同样用公钥加密的数据必须用对应的私钥来解密常见的非对称加密算法有RSA等。3、不可逆加密利用哈希算法使数据加密之后无法解密回原数据这样的哈希算法常用的有md5、SHA-1等。在我们上面登录系统的示例代码中m d 5 p a s s w o r d m d 5 ( md5password md5(md5passwordmd5(password); 从这句代码可以看到采用了md5的不可逆加密算法来存储密码这也是多年来业界常用的密码加密算法但是这仍然不安全。为什么呢这是因为md5加密有一个特点同样的字符串经过md5哈希计算之后生成的加密字符串也是相同的由于业界采用这种加密的方式由来已久黑客们也准备了自己强大的md5彩虹表来逆向匹配加密前的字符串这种用于逆向反推MD5加密的彩虹表在互联网上随处可见在Google里使用md5 解密作为关键词搜索一下就能找到md5在线破解网站把我们插入用户数据时候的MD5加密字符串e10adc3949ba59abbe56e057f20f883e填入进去瞬间就能得到加密前的密码123456。当然也并不是每一个都能成功但可以肯定的是这个彩虹表会越来越完善。所以我们有迫切的需求采用更好的方法对密码数据进行不可逆加密通常的做法是为每个用户确定不同的密码加盐salt后再混合用户的真实密码进行md5加密如以下代码?php//用户注册时候设置的password $password$_POST[password];//md5加密传统做法直接将加密后的字符串存入数据库但这不够我们继续改良 $passwordmd5md5($password);//为用户生成不同的密码盐算法可以根据自己业务的需要而不同 $saltsubstr(uniqid(rand()),-6);//新的加密字符串包含了密码盐 $passwordmd5md5($passwordmd5.$salt);小结1、不要随意开启生产环境中Webserver的错误显示。2、永远不要信任来自用户端的变量输入有固定格式的变量一定要严格检查对应的格式没有固定格式的变量需要对引号等特殊字符进行必要的过滤转义。3、使用预编译绑定变量的SQL语句。4、做好数据库帐号权限管理。5、严格加密处理用户的机密信息。以上就是今天的分享觉得有帮助记得点赞收藏以上所说到的漏洞扫描工具都整理成压缩包了朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】同时还为准备学习网络安全黑客或者正在学习整理了一套360独家内部资料包含以下内容如有需要也可文末获取①网络安全学习路线②20份渗透测试电子书③安全攻防357页笔记④50份安全攻防面试指南⑤安全红队渗透工具包⑥网络安全必备书籍⑦100个漏洞实战案例⑧安全大厂内部视频资源⑨历年CTF夺旗赛题解析一、网络安全黑客学习路线网络安全黑客学习路线形成网络安全领域所有的知识点汇总它的用处就在于你可以按照上面的知识点去找对应的学习资源保证自己学得较为全面。二、网络安全教程视频我们在看视频学习的时候不能光动眼动脑不动手比较科学的学习方法是在理解之后运用它们这时候练手项目就很适合了。三、网络安全CTF实战案例光学理论是没用的要学会跟着一起敲要动手实操才能将自己的所学运用到实际当中去这里带来的是CTFSRC资料HW资料毕竟实战是检验真理的唯一标准嘛~四、网络安全面试题最后我们所有的作为都是为就业服务的所以关键的临门一脚就是咱们的面试题内容所以面试题板块是咱们不可或缺的部分这里我给大家准备的就是我在面试期间准备的资料。网安其实不难难的是坚持和相信自己我的经验是既然已经选定网安你就要相信它相信它能成为你日后进阶的高效渠道这样自己才会更有信念去学习才能在碰到困难的时候坚持下去。机会属于有准备的人这是一个实力的时代。人和人之间的差距不在于智商而在于如何利用业余时间只要你想学习什么时候开始都不晚不要担心这担心那你只需努力剩下的交给时间这份完整版的网络安全学习资料已经上传CSDN朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】
返回列表