zoukankan      html  css  js  c++  java
  • PHP+MYSQL网站SQL Injection攻防

    程序员们写代码的时候讲究TDD(测试驱动开发):在实现一个功能前,会先写一个测试用例,然后再编写代码使之运行通过。其实当黑客SQL Injection时,同样是一个TDD的过程:他们会先尝试着让程序报错,然后一点一点的修正参数内容,当程序再次运行成功之时,注入也就随之成功了。

    进攻:

    假设你的程序里有类似下面内容的脚本:

    $sql = "SELECT id, title, content FROM articles WHERE id = {$_GET[''id'']}";

    正常访问时其URL如下:

    /articles.php?id=123

    当黑客想判断是否存在SQL Injection漏洞时,最常用的方式就是在整形ID后面加个单引号:

    /articles.php?id=123''

    由于我们没有过滤$_GET[''id'']参数,所以必然会报错,可能会是类似下面的信息:

    supplied argument is not a valid MySQL result resource in ...

    这些信息就足以说明脚本存在漏洞了,我们可以再耍点手段:

    /articles.php?id=0 union select 1,2,3

    之所以select 1,2,3是因为union要求两边的字段数一致,前面是id,title,content三个字段,后面1,2,3也是三个,所以不会报语法错误,还有设置id=0是一条不存在的记录,那么查询的结果就是1,2,3,反映到网页上,原本显示id的地方会显示1,显示title的地方会显示2,显示content的地方会显示3。

    至于如何继续利用,还要看magic_quotes_gpc的设置:

    当magic_quotes_gpc为off时

    /articles.php?id=0 union select 1,2,load_file(''/etc/passwd'')

    如此一来,/etc/passwd文件的内容就会显示在原本显示content的地方。

    当magic_quotes_gpc为on时

    此时如果直接使用load_file(''/etc/passwd'')就无效了,因为单引号被转义了,但是还有办法:

    /articles.php?id=0 union select 1,2,load_file(char(47,101,116,99,47,112,97,115,115,119,100))

    其中的数字就是/etc/passwd字符串的ASCII:字符串每个字符循环输出ord(...)

    除此以为,还可以使用字符串的十六进制:字符串每个字符循环输出dechex(ord(...))

    /articles.php?id=0 union select 1,2,load_file(0x2f6574632f706173737764)

    这里仅仅说了数字型参数的几种攻击手段,属于冰山一角,字符串型参数等攻击手段看后面的文档链接。

    防守:

    网络上有一些类似SQL Injection Firewall的软件可供使用,比如说GreenSQL,如果网站已经开始遭受SQL Injection攻击,那么使用这样的快捷工具往往会救你一命,不过这样的软件在架构上属于一个Proxy的角色,多半会影响网站并发性能,所以在选择与否这个问题上最好视客观条件来慎重决定。很多时候专业的软件并不是必须的,还有很多轻量级解决方案,下面演示一下如何使用awk来检测可能的漏洞。

    创建detect_sql_injection.awk脚本,内容如下(如果要拷贝一下内容的话记得不要包括行号):

    01 #!/bin/gawk -f
    02
    03 /$_(GET|POST|COOKIE|REQUEST)s*[/ {
    04     IGNORECASE = 1
    05     if (match($0, /$.*(sql|query)/)) {
    06         IGNORECASE = 0
    07         output()
    08         next
    09     }
    10 }
    11
    12 function output()
    13 {
    14     $1 = $1
    15     print "CRUD: " $0 " FILE: " FILENAME " LINE: " FNR " "
    16 }

    此脚本可匹配出类似如下的问题代码,想要扩展匹配模式也容易,只要照猫画虎写if match语句即可。

    1:$sql = "SELECT * FROM users WHERE username = ''{$_POST[''username'']}''";
    2:$res = mysql_query("SELECT * FROM users WHERE username = ''{$_POST[''username'']}''");

    使用前别忘了先chmod +x detect_sql_injection.awk,有两种调用方法:

    1:./detect_sql_injection.awk /path/to/php/script/file
    2:find /path/to/php/script/directory -name "*.php" | xargs ./detect_sql_injection.awk

    会把有问题的代码信息显示出来,样子如下:

    CRUD: $sql = "SELECT * FROM users WHERE username = ''{$_POST[''username'']}''";
    FILE: /path/to/file.php
    LINE: 123

    现实环境中有很多应用这个脚本的方法,比如说通过CRON定期扫描程序源文件,或者在SVN提交时通过钩子方法自动匹配。

    使用专业工具也好,检测脚本亦罢,都是被动的防守,问题的根本始终取决于在程序员头脑里是否有必要的安全意识,下面是一些必须要牢记的准则:

    1:数字型参数使用类似intval,floatval这样的方法强制过滤。
    2:字符串型参数使用类似mysql_real_escape_string这样的方法强制过滤,而不是简单的addslashes。
    3:最好抛弃mysql_query这样的拼接SQL查询方式,尽可能使用PDO的prepare绑定方式。
    4:使用rewrite技术隐藏真实脚本及参数的信息,通过rewrite正则也能过滤可疑的参数。
    5:关闭错误提示,不给攻击者提供敏感信息:display_errors=off。
    6:以日志的方式记录错误信息:log_errors=on和error_log=filename,定期排查,Web日志最好也查。
    7:不要用具有FILE权限的账号(比如root)连接MySQL,这样就屏蔽了load_file等危险函数。
    8:......

    网站安全其实并不复杂,总结出来就是一句话:过滤输入,转义输出。其中,我们上面一直讨论的SQL Injection问题就属于过滤输入问题,至于转义输出问题,其代表是Cross-site scripting,但它不属于本文的范畴,就不多说了。

    文档:

    addslashes() Versus mysql_real_escape_string()
    SQL Injection with MySQL
    Advanced SQL Injection with MySQL
    MySQL注入中导出字段内容的研究——通过注入导出WebShell

    转载自:http://www.aspnetjia.com

  • 相关阅读:
    Kubernetes实战:高可用集群的搭建和部署
    华为云MVP程云:知识化转型,最终要赋能一线
    支持60+数据传输链路,华为云DRS链路商用大盘点
    关于单元测试的那些事儿,Mockito 都能帮你解决
    深入原生冰山安全体系,详解华为云安全服务如何构筑全栈安全
    云小课|ModelArts Pro 视觉套件:零代码构建视觉AI应用
    FLINK重点原理与机制:内存(1)task之间的数据传输
    FLINK重点原理与机制:内存(2)网络流控及反压机制剖析(一)
    FLINK重点原理与机制:状态(3)两阶段提交
    FLINK重点原理与机制:状态(2)Flink的检查点算法CHECKPOINT
  • 原文地址:https://www.cnblogs.com/aspnetjia/p/5318380.html
Copyright © 2011-2022 走看看