Day24 -php开发day03 --文件上传模块(上传、显示)+ 三种方法验证上传类型(黑白名单、MIME)【上篇】

发布于:2025-05-01 ⋅ 阅读:(24) ⋅ 点赞:(0)

功能实现:文件后台管理模块的上传、显示功能

=========================  文件上传   ====================================

一、文件上传

1、前端页面

让gpt去给我们生成即可,可以直接复用现成的

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>文件上传页面</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            background-color: #f2f2f2;
            padding: 20px;
        }
        h1 {
            text-align: center;
            margin-top: 50px;
        }
        form {
            background-color: #fff;
            border-radius: 10px;
            padding: 20px;
            margin-top: 30px;
            max-width: 600px;
            margin: 0 auto;
        }
        input[type="file"] {
            margin-top: 20px;
            margin-bottom: 20px;
        }
        button {
            background-color: #4CAF50;
            color: #fff;
            padding: 10px 20px;
            border: none;
            border-radius: 5px;
            cursor: pointer;
        }
        button:hover {
            background-color: #3e8e41;
        }
    </style>
</head>
<body>
<h1>文件上传</h1>
<form action="upload.php" method="POST" enctype="multipart/form-data">
    <label for="file">选择文件:</label>
    <br>
    <input type="file" id="file" name="f">
    <br>
    <button type="submit">上传文件</button>
</form>
</body>
</html>
        
2、文件上传后端部分
1)先利用全局变量file去提取接收到的文件的各类信息
<?php

// 从前端表单提取出来的信息,利用全局变量进行提出
$name=$_FILES['f']['name'];
$type=$_FILES['f']['type'];
$size=$_FILES['f']['size'];
$tmp_name=$_FILES['f']['tmp_name'];
$error=$_FILES['f']['error'];

2)进行文件上传到服务器的逻辑实现

利用的是move_uploaded_file(),上传到服务器上,我这里是本地开发,所以说本机模拟的是服务器,给的路径是在项目demo1下的upload文件夹

打印一下信息对照是否上传文件是对应的。

<?php

// 从前端表单提取出来的信息,利用全局变量进行提出
$name=$_FILES['f']['name'];
$type=$_FILES['f']['type'];
$size=$_FILES['f']['size'];
$tmp_name=$_FILES['f']['tmp_name'];
$error=$_FILES['f']['error'];

# 测试是否正确提取图片信息
echo $name."<br>";
echo $type."<br>";
echo $size."<br>";
echo $error."<br>";

# 测试文件是否成功上传到服务器的指定文件夹内   注意:需要提前创建好文件夹;
if(move_uploaded_file($tmp_name,'upload/'.$name)){ // 按照我的本地环境,我的服务器地址就是我的php项目地址
    echo "文件已成功上传";                            // 所以我需要在/demo1下面创建一个文件夹 /demo1/upload
}

?>


但是这样非常不安全,因为用户可以上传任意的文件类型,所以我们需要加入筛选逻辑(黑白名单)

3、三种文件上传类型验证机制
1)**黑名单**逻辑实现

如果不对上传的文件类型进行限制,那么可能会有木马文件被上传,攻击者可以进入服务器后门。

逻辑:将禁止的后缀类型写入数组,然后我分割服务器接收到的文件名,只取后缀名,用一个变量去接收他,再将其与数组中的黑名单后缀进行比较,如果在黑名单内,则提示禁止上传。

$black_ext=array('php','asp','jsp','aspx');
//xxx.jpg xxx.png
$fenge = explode('.',$name);
$exts = end($fenge);
if(in_array($exts,$black_ext)){
    echo '非法后缀文件'.$exts;
}else{
    move_uploaded_file($tmp_name,'upload/'.$name);
    echo '<script>alert("上传成功")</script>';
}

测试一下,成功拦截黑名单内的后缀文件上传到服务器。

但是随之而来的是,文件类型太多种了,而且同种文件类型有不同的名字例如html2、html4等等。所以更加安全的是写一个白名单,我们允许哪些类型的通过,不符合条件的一律拒之门外。

2)**白名单**逻辑实现 

先进行文件名的切割,给一个新变量去接收,然后拿新变量去我们的白名单数组进行对比,若在允许后缀内,则进行上传服务器的操作;如果不在范围内,则提示非法,不做上传的操作

$allow_ext=array('png','jpg','gif','jpeg');
// xxx.jpg xxx.png
$fenge = explode('.',$name);
$exts = end($fenge);
if(in_array($exts,$allow_ext)) {  //第一个参数是要进行判断的变量;第二个参数是判断的依据
    move_uploaded_file($tmp_name, 'uoload/' . $name);
    echo '<script>alert("上传成功!")</script>';
}else{
    echo '非法后缀文件';
}

测试:提交一个exe文件

3)**MIME文件类型**逻辑实现

MIME 类型 | 菜鸟教程

mime在哪里作用?

我们就给一个mime类型:image/gifimage/pngimage/jpeg 这三种吧

注意我们这里的逻辑是提取上传文件的文件类型,那么可以通过全局变量file去抓取type。

$allow_ext=array('image/png','image/gif','image/jpeg');
// 前面有利用全局变量file去提取文件类型
if(in_array($type,$allow_ext)) {  //第一个参数是要进行判断的变量;第二个参数是判断的依据
    move_uploaded_file($tmp_name, 'upload/' . $name);
    echo '<script>alert("上传成功!")</script>';
}else{
    echo '非法后缀文件.'.$type; //给一个上传的文件类型
}

 

=========================      文件显示     ====================================

 

二、文件显示

1、逻辑实现

00x1、先给一个初始目录进行访问   ----利用get方法去提取url里的,没有就当前目录

00x2、给这个目录一个操作许可    -----  opendir( )实现

00x3、打开这个目录            ----opendir( )实现

00x4、区分文件夹和文件     ---- is_dir()实现

               --- 若为文件,则打印文件:文件名

               --- 若为文件名,则利用超链接进行路径拼接跳转(将path=此文件夹路径拼接到原url中,实现对文件夹下级路径的访问)

2、代码实现
<?php

// 如果初始url没有path参数,则路径取当前文件夹下
$dir =$_GET['path'] ?? './';

# 1.实现打开指定目录,并显示其文件/文件夹名   ---利用readdir()函数
function show_file($dir){
    $d = opendir($dir);   // 相当于给d一个可以对目录操作的许可
    while(($file = readdir($d)) !== false){   //file变量接收的是目录(有d操作许可,且是dir指向的路径目录);
        echo $file."<br>";                  // 同时注意逻辑运算符的优先级,!==要大于= 所以要加括号给$fil
        # 2.继续进行文件夹和文件的判断  ---利用is_dir()函数
        if(is_dir($file)){
            # 3.实现点击文件夹继续进入目录的效果
    // 原理:利用超链接在url后面增加$file接收到的文件夹,从而实现了url/path=$file的效果,从而可以查看$file接收到的文件夹下面的文件/子目录
            echo "文件夹:"."<a href='?path=$file'>$file</a><br>"; 
        }else{
            echo "文件:" . $file . "<br>";
        }
    }
}

show_file($dir);

 测试

一一对应   成功!

3、payload方向(文件包含)

涉及到文件包含漏洞,与php.ini中的一个参数有关 【open_basedir】

注意:搞清楚是小皮内置的php.ini 还是自己配置的php环境的ini文件

我这里是关闭,不生效,那么看一下效果

给path参数里面写我任意一个文件夹都可以被访问到。

如果我进行了设置,给他限制在我demo1的上层目录xiaodikaifa中

刷新一下,看效果

总结:如果是没有对php.ini做目录限制的话,就可以利用遍历文件路径,进行被攻击者/服务器文件的泄露。


网站公告

今日签到

点亮在社区的每一天
去签到