读《PHP安全之道》提纲挈领笔记03

5 篇文章 0 订阅

在这里插入图片描述

四、PHP项目中常见漏洞与防护

1、SQL注入漏洞

(1)SQL注入

在处理程序时,未对用户可控参数进行严格校验,如利用字符串拼接的方式构造SQL语句在数据库中执行,很容易埋下安全隐患。
SQL注入可以造成数据库信息泄露。
通过操作数据库对特定网页进行篡改,修改数据库一些字段值,嵌入恶意链接,进行挂马攻击,传播恶意软件。
服务器还容易被远程控制,修改操作系统以及破坏磁盘,使系统瘫痪。
SQL注入攻击方式:①报错注入②普通注入③隐式类型注入④盲注⑤宽字节注入⑥二次解码注入

(2)报错注入
test.php?name=zhangsan'errr
select * from test where name ='zhangsan'errr'

恶意攻击者使用特殊的方式使数据发生错误并产生报错信息,从而获得数据库和系统信息,方便攻击者进行下一步攻击。
要对传入参数进行严格处理。
数据库报错,攻击者可以通过这种方式来获取MySQL的各类信息。防止报错信息被攻击者直接看到,需设置display_errors=Off

(3)普通注入
test.php?name=zhangsan'or'a'='a //组合成万能查询语句
select * from test where name ='zhangsan'or'a'='a'

后面随意拼接,可能会导致数据库数据泄漏和数据删除,如果没有对数据进行备份,将对系统造成的伤害是毁灭性的。

(4) 隐式类型注入
select * from test where where email=0;

把查询语句误写,如果SQL语句中的字段类型和对应表中的字段数据类型不一致,MySQL查询优化器会将数据的类型进行隐式转换。其中 email 是 varchar 类型。
下表是MySQL类型转换规则:
在这里插入图片描述

(5)盲注

盲注容易被忽略。
攻击者可以利用延时等技术实现发现和利用注入漏洞。

select * from test where if((MID(version(),1,1)) LIKE 5,sleep(5),1) limit 0,1;

利用 BENCHMARK()函数进行延时注入。
(IF (MID(version(),1,1) like 5,BENCHMARK(100000,SHA1('true')),false))
该请求会使MySQL的查询睡眠5秒,攻击者可以通过添加判断条件到SQL语句中。如果睡眠5秒,那么说明MySQL版本是5。

(6)宽字节注入

使用addslashes()函数可以使“’”变成“’”。输入 “%81’”

id=%81%27

数据库和程序编码都是GBK编码的需要注意。当输入的第一个字符的ASCII码大于128时。GBK是多字节编码,PHP认为两个字节代表一个汉字,所以输入%81和后面的反斜杠%5c变成一个汉字“乘”,造成反斜杠消失。

(7)二次解码注入

防止SQL注入,通常采用转义特殊字符。如单引号(’)、双引号(")转义成’"。有一个误区就是通过配置PHP的GPC开关进行自动转义。

?name=name%2527

当PHP自动URL解码,变成name%27,然后代码里再使用urldecode()rawurldecode()函数进行解码时,%27就变成单引号。URL最终变成name=name’ 引发SQL注入。

2、SQL注入漏洞防护

SQL注入是最危险的漏洞之一,也是最好防护的漏洞之一。合理利用MySQL提供的预编译进行sql注入防护,在PHP中使用PHP数据对象或MySQL扩展连接数据库,并对SQL语句进行预编译处理。
如果在项目中无法使用预编译来防止SQL注入,可以采用传统方式来验证用户输入是否合法,严格控制输入参数的数据类型,过滤非法字符。

(1)MySQL预编译处理

MySQL预编译处理分为编译、执行、释放。语编译遵循指令和数据分离原则。
编译。
通过PREPARE stmt_name FROM preparable_stm 来编译一条SQL语句。

>  PREPARE test  FROM 'insert into test select ?,?,?,? ';

通过 EXECUTE stmt_name [USING @var_name,[,@var_name]…]的语法来执行预编译语句。

>set @name='zhangsan',@email='test@qq.com',@password='123456789',@status=1;
>execute test using @name,@email,@password,@ststus;

MySQL的预编译语句作用域是会话级,但可以通过max_prepared_stmt_count 变量来控制全局最大存储的预编译语句。

> set @@global.max_prepared_stmt_count=1;

当预编译条数达到阈值时,则报错。
如果要释放一条预编译的语句,则可以使用 {deallocate | drop} prepare stmt_name 的语法进行操作。

> deallocate prepare test;

同一个处理操作,SQL语句只编译一次。

(2)PHP使用MySQL的预编译处理

SQL使用预编译处理:增强系统安全性;提高系统的执行效率。
PHP 可以通过PDO 模块进行SQL预编译处理。
可参照手册学习:https://www.php.net/manual/zh/book.pdo.php
其中,在默认的情况下,PDO没有让MySQL数据库执行真正的预处理语句。应禁止PDO模拟预处理语句。
添加 ATTR_EMULATE_PREPARES (false)ATTR_ERRMODE ( ERRMODE_EXCEPTION) 属性 。

    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);    
    $pdo->setAttribute( PDO::ATTR_EMULATE_PREPARES, false ); 

客户端执行SQL 只需传参数,预编译处理分离了参数与SQL语句。

(3)校验和过滤

如果无法使用MySQL预编译处理,防止前面几种注入方式,需要对输入的数据进行有效的检验和过滤。
以下是常用的检验变量函数:

在这里插入图片描述在这里插入图片描述

除了函数,也可以使用正则处理。
过滤方式需要结合业务,使用不当可能会对现有业务造成影响。

(4)宽字节注入防护

在SQL查询前,使用 intval 对变量进行强制转换。
可以使用 mysql_real_escape_string (php5.5起已废弃,php7开始移除)进行防御,在使用前需要 mysql_set_charset指定字符集才能生效。
还可以将 character_set_client 设置成 binary,设置成二进制格式就不存在宽字节或多字节问题。

(5) 禁用魔术引号
关闭魔术引号并不能有效解决SQL注入,但可以提高性能。

magic_quotes_gpc=Off;//关闭魔术引号

3、XML注入漏洞防护

XML解析依赖于libxml库,默认支持并开启外部实体的引用。XML漏洞被使用可读取服务器任意文件、执行代码、发起DDos攻击。
(1)对用户的输入过滤 如 <、>、’、"、&等。
(2)XML解析方法有 DOMDocumentSimpleXML、XMLReader。在PHP解析XML文件之前使用libxml_disable_entity_loader(true)来禁止加载外部实体。使用 libxml_use_internal_errors()禁止报错。

4、邮件安全

(1)邮件注入

注意%0A。SMTP区分消息头部和消息主题是依据%0A%0A双换行符决定的,消息头里的属性是以%0A区分的,因此用户如果自行将%0A%0A或%0A写入到变量,会直接控制消息体控制被发送对象以及内容。
接收用户的请求后要进行严格的过滤,防止用户恶意注入。

(2)防止邮件注入

使用filter_var()函数。
(PHP 5 >= 5.2.0, PHP 7)

filter_var — 使用特定的过滤器过滤一个变量。

邮箱过滤使用:

var_dump(filter_var('bob@example.com', FILTER_VALIDATE_EMAIL));
//其中,FILTER_SANITIZE_EMAIL   Remove all characters except letters, digits and !#$%&'*+-=?^_`{|}~@.[].

对用户自定义的内容过滤。

5、PHP组件漏洞防护

PHP文件(框架,模块)总是以全部权限运行,如果使用了一个带有漏洞的组件,这种攻击可能对数据和服务器造成损失。防止此类漏洞,一定要时刻关注该软件的更新,使用最新的组件。

(1)RSS安全漏洞

聚合内容(really simple syndication,RSS)是在线共享内容的一中简易方式。
如果RSS是不受信任的信息来源,很可能被注入script或者html标签。这些恶意标签很可能攻击浏览器。
在转发前,必须使用可靠的过滤表进行过滤,或者它们必须过滤特定的字符集。
受攻击应用:
① 本地RSS阅读器。 如foxmal
②web RSS 阅读器。如 Google reader

(2) PHPMailer漏洞

在 5.2.18以前存在一个漏洞,攻击者利用该漏洞可在web服务器中执行任意远程代码。
在5.2.21及以前存在任意文件读取漏洞。

(3)OpenSSL漏洞

OpenSSL是一个安全套接字层密码库,包括主要的密码算法、常用的密钥和证书封装管理功能及SSL协议。
①OpenSSL 1.0.1n 、 1.0.1o、 1.0.2b、 1.0.2c版本,crypto/x509/x509_vfy.c内的函数X509_verify_cert,在替换证书链过程识别中没有正确处理X.509 Base Constraints CA 值,存在安全漏洞。利用此漏洞发布无效证书。
②Heartbleed漏洞。由于未在 memcpy() 调用客户端输入内容作为长度参数之前正确进行边界检查,攻击者可追踪OpenSSL64k缓存。

(4)SSL v2.0协议漏洞

SSL v2.0主要存在以下问题。
①同一加密密钥用于消息身份验证和加密。
②弱消息认证代码结构和只支持不安全的MD5散列函数。
③ SSL 握手过程没有采取任何防护,这意味着非常容易遭遇中间人攻击。
④使用TCP连接关闭,以指示数据的末尾(没有明确的会话关闭通知)。这意味着截断攻击是可能的:攻击者只需伪造一个TCP FIN,使得接收方无法识别数据结束消息的合法性。
⑤仅能提供单一服务和绑定一个固定域名,这与Web服务器中的虚拟主机标准功能有冲突,这意味着许多网站无法使用SSL。

6、文件包含安全

通过PHP函数引用文件。

(1)文件包含漏洞

按文件包含形式分:简单文件包含漏洞、受限制的文件包含漏洞、Zip文件包含漏洞、远程文件包含漏洞等。

对客户端输入参数进行检验和过滤,限制文件类型。

(2)避免文件包含漏洞

include()include_once()require()requre_once()spl_autoload()

带 once 的函数 PHP会检查该文件是否已经被包含过,如果是则不会再次包含。
require在出错时产生E_COMPILE_ERROR级别的错误。换句话说,就是require将导致脚本中止,而include只产生警告 (E_WARNING),脚本会继续运行。

spl_autoload — __autoload()函数的默认实现,如果不使用任何参数调用 

spl_autoload_register() 函数,则以后在进行 __autoload() 调用时会自动使用此函数。

在使用上述函数时要注意以下问题。
①保证接收的用户参数不可构造成文件路径。
②禁用远程访问,修改PHP配置。
③指定默认文件名称和路径,不允许用户自行传递文件名称。
④使用basename进行过滤。

7、系统命令注入

攻击者提交恶意的shell命令,通过PHP函数执行。

(1)易发生命令注入的函数

exec()system()passthru()popen()shell_exec()pcntl_exec()等。

(2)防御命令注入

①尽量避免使用此类函数,避免从用户端接收执行命令。
②如果必须使用,执行命令的参数应禁止外部获取,防止用户伪造。
③php.ini 设置 safe_mode=On。使用 disable_functions禁用这些函数

 disable_functions= exec,system,passthru,popen,shell_exec,pcntl_exec

④使用自定义函数或函数库来代替外部命令函数
⑤结合使用escapeshellarg()escapeshellcmd()函数来处理命令参数。
escapeshellarg()函数会将任何引起参数或命令结束的字符转义,单引号“’”替换成“’”,双引号“"”替换成“"”,分号“;”替换成“;”
⑥使用safe_mode_exec_dir指定可执行文件的路径。
safe_mode_exec_dir指定可执行文件的路径,可以把会使用的命令提前放入此路径内。



END

如有问题请在下方留言。

或关注我的公众号“孙三苗”,输入“联系方式”。获得进一步帮助。

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值