php上传图片 解码,PHP编码安全之六: 文件上传安全

本文探讨了PHP文件上传漏洞的危害,展示了如何通过检查文件类型和扩展名来防止恶意文件上传。文中提出,仅凭MIME类型或扩展名检查并不充分,建议采用白名单机制、使用随机文件名及限制上传目录权限等综合措施确保文件上传的安全性。
摘要由CSDN通过智能技术生成

本文内容参考自《PHP安全之道》。

文件上传漏洞的危害

在PHP项目中, 提供上传功能并在服务器端未对上传的文件格式进行合理的校验是存在巨大风险的。如果恶意攻击者利用上传漏洞上传一些 webshell,则可能完全控制整个网站程序, 执行系统命令(如删除系统文件), 获取数据库连接字符串进行数据库操作等危险操作。

文件上传漏洞

以下是一个不安全的文件上传后端代码 (upload.php):

$upload_dir = 'uploads/';

$upload_file = $upload_dir . basename($_FILES['file']['name']);

if(move_upload_file($_FILES['file']['tmp_name'], $upload_file)){

echo '文件上传成功!';

}else{

echo '错误: 文件上传失败!';

}

前端html:

请选择文件:

这是一个简单的文件上传模块. 其中由用户上传文件, 如果上传成功, 则保存文件的路径为: http://服务器路径/uploads/文件名称。

如果攻击者上传一个如下内容的hacker.php脚本文件到服务器:

system($_GET['shell']);

则攻击者就可以通过该文件进行url请求 http://服务器路径/uploads.php?hacker.php?shell=ls%20-al, 从而可以执行任何shell命令.

检查文件类型防止上传漏洞

上面的演示代码很简单, 没有做任何的上传限制。 如果要限制,通常的做法是限制文件上传类型(MIME)

if($_FILES['file']['tye'] != 'images/gif'){

die('请上传正确的文件类型!');

}

$upload_dir = 'uploads/';

$upload_file = $upload_dir . basename($_FILES['file']['name']);

if(move_upload_file($_FILES['file']['tmp_name'], $upload_file)){

echo '文件上传成功!';

}else{

echo '错误: 文件上传失败!';

}

如果攻击者试图上传 shell.php, 会被系统拒绝. 这里简单的通过文件类型检测阻止了非法文件上传。

但是只是简单的进行文件类型MIME检查也是不够的, 攻击者通过修改POST数据包中的Content-type: text/plain 为 Content-type: image/gif 即可骗过系统。

检查文件扩展名称防止上传漏洞

除了检测MIME类型,常用的方法是基于黑白名单验证所传文件的扩展名称是否符合要求。

以下代码通过黑名单方式对文件类型进行限制:

$ext_black_list = ['.php', '.phtml', '.php3', '.php4'];//黑名单

$upload_dir = 'uploads/';

$file_name = $_FILES['file']['name'];

$upload_file = $upload_dir . basename($file_name);

$ext = substr($file_name, -4);//扩展名

if(in_array($ext, $ext_black_list)){

die('请选择正确的文件类型');

}

if(move_uploaded_file($_FILES['file']['tmp_name'], $upload_file)){

echo '文件上传成功!';

}else{

echo '错误: 文件上传失败!';

}

以下代码通过白名单方式对文件类型进行限制:

$ext_white_list = ['.jpg', '.gif', '.png'];//白名单

$upload_dir = 'uploads/';

$file_name = $_FILES['file']['name'];

$upload_file = $upload_dir . basename($file_name);

$ext = substr($file_name, -4);//扩展名

if(!in_array($ext, $ext_white_list)){

die('请选择正确的文件类型');

}

if(move_uploaded_file($_FILES['file']['tmp_name'], $upload_file)){

echo '文件上传成功!';

}else{

echo '错误: 文件上传失败!';

}

从黑名单和白名单两种不同的验证方法来看,白名单方式要比黑名单更安全, 但是采取白名单还是不够的。

Apache存在一个扩展名解析漏洞(apahce2.4下仍然存在): 如果一个文件有多个扩展名时, 如果最后的扩展名未定义, 就会解析前一个扩展名, 比如 hacker.php.2018 会解析成.php扩展名, 从而该文件被当做脚本执行。如果使用黑名单机制, 很明显无法防御此种攻击,但是白名单机制就可以。

文件上传漏洞的综合防护

我们不能期望只通过一种安全手段就能阻止非法文件上传, 应该同时综合运用文件类型检测、后缀名检测、黑白名单机制、使用随机文件名、上传文件目录禁止执行权限等多种方法同时进行。

/**

* 生成随机字符串

* @param int $len

* @return string

*/

function getRandomString(int $len){

$chars = array_merge(range('a', 'z'), range('A', 'Z'), range(0, 9));

$char_len = count($chars) - 1;

shuffle($chars); //将数组打乱

$rt = '';

for($i=0; $i < $len; $i++){

$rt .= $chars[mt_rand(0, $char_len)];

}

return $rt;

}

$ext_white_list = ['.jpg', '.gif', '.png'];//后缀名白名单

$file_name = $_FILES['file']['name']; //原文件名

$ext = substr($file_name, -4);//扩展名

if(!in_array($ext, $ext_white_list)){

die('请选择正确的文件类型');

}

$mime_white_list = ['image/gif', 'image/png', 'image/jpeg']; //MIME白名单

if(!in_array($_FILES['file']['type'], $mime_white_list)){

die('请选择正确的文件类型');

}

$upload_dir = '/tmp/uploads/';//将上传的文件放到项目目录之外

$upload_file = $upload_dir . getRandomString(20). $ext; // 使用随机文件名

if(move_uploaded_file($_FILES['file']['tmp_name'], $upload_file)){

echo '文件上传成功!';

}else{

echo '错误: 文件上传失败!';

}

除了在代码中阻止上传漏洞外, 还需要在项目部署时对上传目录进行安全设置: 禁止文件的执行权限, 把该目录的所有文件当做静态资源处理。

当用户上传文件到服务器时保存时, 一定要使用随机文件名进行存储, 并保证所存储的扩展名合法。保证文件名的唯一性,也保证了存储的安全性,可以防止上传文件非法扩展的解析。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值