网络安全基础之php开发文件上传的实现

前言

php是网络安全学习里必不可少的一环,简单理解php的开发环节能更好的帮助我们去学习php以及其他语言的web漏洞原理

正文

在正常的开发中,文件的功能是必不可少,比如我们在论坛的头像想更改时就涉及到文件的上传等等文件功能。但也会出现漏洞,或者一些bug。这部分是php开发部分的文件上传、删除部分,为啥不写完?感觉有点多。

文件上传代码

在开发中,对于这种功能型的代码一般有两种办法来开发。一种比较复杂,另外一种比较简单。

自己写代码

这种办法是比较复杂、比较费时费力的。甚至在某些情况下是单纯的吃力不讨好。比如你花几个星期开发一个文本编辑器,最后开发出的文本编辑器性能还不怎么样,但是开源社区或者其他地方有符合你最终需求的文本编辑器代码,性能还优秀,这种情况下就真的吃力不讨好了。

PS:在开发时一点要做好技术选型这些,尽量避免重复造轮子
创建一个file_upload.php文件来实现一个简单文件上传功能,先编写一个html页面来方便查看结果,在file_index.php中写入下面的html代码

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Head</title><link rel="stylesheet" href="index.css">
</head>
<body>
<div class="header"><a href="index.html" class="logo"><h1>wushiyiwuzhong</h1></a><nav class="navbar"><ul><li><a href="#">文件功能导航</a></li><li><a href="#">文件上传</a></li><li><a href="#">文件下载</a></li><li><a href="#">文件删除</a></li><li><a href="#">文件读取</a></li><li><a href="#">文件写入</a></li></ul></nav>
</div>
<div class="content"></div>
</body>
</html>

页面展示效果如下:
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

接下来我们开始实现简单的文件上传功能,在file_upload.php中编写代码,同样,我们先设计前端代码

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Head</title><link rel="stylesheet" href="index.css">
</head>
<body>
<div class="header"><a href="index.html" class="logo"><h1>wushiyiwuzhong</h1></a><nav class="navbar"><ul><li><a href="file_index.php">文件功能导航</a></li><li><a href="file_upload.php">文件上传</a></li><li><a href="#">文件下载</a></li><li><a href="#">文件删除</a></li><li><a href="#">文件读取</a></li><li><a href="#">文件写入</a></li></ul></nav>
</div>
<div class="content">
<h1>文件上传 功能页面</h1>
<!--  编写form表单上传文件  --><form action="" method="post"><!-- action留空,由当前页面处理  --><input type="file" name="file"><!--  文件上传框  --><input type="submit" name="上传"><!--  提交按钮 --></form>
</div>
</body>
</html>

页面效果如下:

开始php后端部分的编写,现在前端这些代码只负责让用户上传文件,并不负责验证这个是不是病毒等等有害文件、能不能上传、上传后放在那里。像后面这些功能都是有后端决定的。

前置知识

在PHP中,文件上传功能的实现步骤:
(1)在网页中上传表单,单击“上传”按钮后,选择的文件数据将发送到服务器。
(2)用$_FILES获取上传文件有关的各种信息。
(3)用文件上传处理函数对上传文件进行后续处理。

说明:
(1)如果表单中有文件上传域,则定义表单时必须设置enctype=“multipart/form-data”,且必须为POST方式发送。
(2)限制文件大小可在表单中添加一个隐藏域,该隐藏域必须放在文件上传域之前,否则会设置失效。

若文件上传域的name属性值为upfile,则可以使用$_FILES[‘upfile’]访问文件的有关信息。
相关信息:
$_FILES[‘upfile’][‘name’]; //客户端上传文件的原名称,不包含路径
$_FILES[‘upfile’][‘type’]; //上传文件的MIME类型
$_FILES[‘upfile’][‘tmp_name’]; //已上传文件在服务器端保存的临时文件名,包含路径
$_FILES[‘upfile’][‘error’]; //上传文件出现的错误号,为一个整数
F I L E S [ ′ u p f i l e ′ ] [ ′ s i z e ′ ] ; / / 已上传文件的大小,单位为字节说明:若同时上传多个文件,则上传域的 n a m e 属性值应为 u p f i l e [ ] , 此时 _FILES['upfile']['size']; //已上传文件的大小,单位为字节 说明:若同时上传多个文件,则上传域的name属性值应为upfile[],此时 FILES[upfile][size];//已上传文件的大小,单位为字节说明:若同时上传多个文件,则上传域的name属性值应为upfile[],此时_FILES变成三维数组,保存第一个文件名的数组元素是$_FILES[‘upfile’][‘name’][0]。

保存上传文件到指定目录
move_uploaded_file(文件原来的路径和文件名,文件的目的路径和文件名);
功能说明:
(1)将上传的文件移动到网站指定目录内,并为它重命名。
(2)检查并确保由第一个参数指定的文件是合法的上传文件(即通过HTTP POST上传机制所上传),这对于网站安全是至关重要的。

下面是具体的代码

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Head</title><link rel="stylesheet" href="index.css">
</head>
<body>
<div class="header"><a href="index.html" class="logo"><h1>wushiyiwuzhong</h1></a><nav class="navbar"><ul><li><a href="#">文件功能导航</a></li><li><a href="#">文件上传</a></li><li><a href="#">文件下载</a></li><li><a href="#">文件删除</a></li><li><a href="#">文件读取</a></li><li><a href="#">文件写入</a></li></ul></nav>
</div>
<div class="content">
<h1>文件上传 功能页面</h1>
<!--  编写form表单上传文件  --><form action="" method="post" enctype="multipart/form-data"><!--enctype进行编码传输--><input type="file" name="file"><!--name参数--><input type="submit" name="submit" value="提交"></form>
</div>
</body>
</html><?php//获取上传文件名
@$file_name=$_FILES['file']['name'];
//获取上传文件类型
@$file_type=$_FILES['file']['type'];
//获取上传文件大小
@$file_size=$_FILES['file']['size'];
//获取上传文件临时文件名
@$file_tmpname=$_FILES['file']['tmp_name'];
//获取上传文件是否错误
@$file_error=$_FILES['file']['error'];echo $file_name."<hr>";
echo $file_type."<hr>";
echo $file_size."<hr>";
echo $file_tmpname."<hr>";
echo $file_error."<hr>";

运行查看效果,如果代码正确的话上传一个文件会打印这个被上传的文件的相关信息

我这里上传一张图片做为测试

点击提交上传之后会打印这种图片相关信息

保存用户上传的文件

现在我们实现当用户上传文件后,比如用户上传了自己的头像后我们的服务器要保存用户的数据。这里我们设置当用户上传文件后将文件保存在当前目录下的upload目录里

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Head</title><link rel="stylesheet" href="index.css">
</head>
<body>
<div class="header"><a href="index.html" class="logo"><h1>wushiyiwuzhong</h1></a><nav class="navbar"><ul><li><a href="file_index.php">文件功能导航</a></li><li><a href="file_upload.php">文件上传</a></li><li><a href="#">文件下载</a></li><li><a href="#">文件删除</a></li><li><a href="#">文件读取</a></li><li><a href="#">文件写入</a></li></ul></nav>
</div>
<div class="content">
<h1>文件上传 功能页面</h1>
<!--  编写form表单上传文件  --><form action="upload.php" method="post" enctype="multipart/form-data"><input type="file" name="file"><!-- name是什么,那么后端接受的参数就是什么--><input type="submit" name="submit" value="提交"></form>
</div>
</body>
</html><?php
// 检查是否有文件被上传
if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_FILES['file'])) {// 指定存放上传文件的目录$uploadDirectory = "upload/";// 获取文件相关信息$fileName = $_FILES['file']['name']; // 文件原名$fileTmpName = $_FILES['file']['tmp_name']; // 文件临时存放的位置$fileError = $_FILES['file']['error']; // 错误码$fileSize = $_FILES['file']['size']; // 文件大小// 检查目录是否存在if (!file_exists($uploadDirectory)) {// 如果不存在则创建目录mkdir($uploadDirectory, 0755, true);}// 检查文件上传过程中是否出错if ($fileError === 0) {// 检查文件是否已经存在if (!file_exists($uploadDirectory . $fileName)) {// 尝试移动文件到指定目录if (move_uploaded_file($fileTmpName, $uploadDirectory . $fileName)) {echo "文件上传成功!";} else {echo "文件上传失败,请检查目录权限。";}} else {echo "文件已存在于目标目录中。";}} else {// 错误处理echo "上传过程中出错,错误码:" . $fileError;}
} else {echo "请通过有效表单提交文件。";
}

代码运行效果如下:

上传文件进行测试,看是不是保存在upload目录下


打开文件夹,确认是不是真的成功了

到这里成功实现了文件上传功能

PS:此时我们就完成了简单的文件上传功能的实现,但是现在的代码是没有任何过滤的,攻击者可以通过上传木马、webshell等等恶意文件来控制我们的服务器。

情景假设:

我是一名黑客,我在目标网站找到了上传漏洞。我现在先上传一个php的webshell到网站上去


现在我们使用蚁剑去连,连接编码为base64,密码为123

PS:当时写代码的时候忘记写回显了。。。。。。不过实战中还是有很多方法可以知道上传路径的

通过第三方组件进行文件上传

在实际的开发中我们可能会节省重复造轮子的时间而去使用其他第三方开发的第三方组件来快速实现我们需要的功能。下面的就是一个第三方组件的例子
(演示使用的第三方组件下载地址)[https://github.com/fex-team/ueditor/releases/tag/v1.4.3.3]

下载后解压到对应的网站目录
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
然后在代码里引入该第三方组件,在html代码里直接加入

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>第三方组件的文件上传</title><link rel="stylesheet" href="index.css"><!-- 集成 UEditor 的 CSS 文件 --><link href="ueditor/themes/default/css/ueditor.min.css" type="text/css" rel="stylesheet"><!-- UEditor 配置文件 --><script type="text/javascript" charset="utf-8" src="ueditor/ueditor.config.js"></script><!-- UEditor 编辑器源码文件 --><script type="text/javascript" charset="utf-8" src="ueditor/ueditor.all.min.js"></script>
</head>
<body>
<a href="index.html" class="logo"><h1>wushiyiwuzhong</h1>
</a>
<nav class="navbar"><ul><li><a href="file_index.php">文件功能导航</a></li><li><a href="file_upload.php">文件上传</a></li><li><a href="#">文件下载</a></li><li><a href="#">文件删除</a></li><li><a href="#">文件读取</a></li><li><a href="#">文件写入</a></li></ul>
</nav>
</div>
<div class="content"><h1>文件上传 功能页面</h1><!-- 编写form表单上传文件 --><form action="upload.php" method="post" enctype="multipart/form-data"><!-- 初始化 UEditor 编辑器的容器 --><script id="editor" name="editor" type="text/plain" style="width:1024px;height:500px;"></script><input type="file" name="file"><!-- 文件上传的input --><input type="submit" name="submit" value="提交"></form>
</div>
<script type="text/javascript">// 实例化 UEditorvar ue = UE.getEditor('editor');
</script>
</body>
</html>

运行效果:

进行文件上传的测试


可以看到第三方组件过滤了简单的恶意文件

总结

到此文件上传漏洞的大致原理和简单利用就结束了,自己开发的代码漏洞出在自己开发的部分,而如果引用第三方组件,那么漏洞点在第三方组件。至于过滤、绕过这些都是后面的事情

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/188459.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端通过导入editor.md库实现markdown功能

小王学习录 今日摘录前言jquery下载editor下载editor和jquery的导入初始化editor总结 今日摘录 满招损&#xff0c;谦受益 前言 要想通过editor.md实现markdown的功能&#xff0c;需要经过如下四步&#xff1a; 下载editor.md到本地将本地editor导入到前端代码中编写少量代…

No source control providers registered

使用vscode时碰到这个问题 git扩展没启动

LeetCode(3)删除有序数组中的重复项【数组/字符串】【简单】

目录 1.题目2.答案3.提交结果截图 链接&#xff1a; 26. 删除有序数组中的重复项 1.题目 给你一个 非严格递增排列 的数组 nums &#xff0c;请你** 原地** 删除重复出现的元素&#xff0c;使每个元素 只出现一次 &#xff0c;返回删除后数组的新长度。元素的 相对顺序 应该保…

推荐这款机器学习的特征筛选神器!

大家好&#xff0c;特征选择是机器学习建模流程中最重要的步骤之一&#xff0c;特征选择的好坏直接决定着模型效果的上限&#xff0c;好的特征组合甚至比模型算法更重要。除了模型效果外&#xff0c;特征选择还有以下几点好处&#xff1a; 提高模型性能并降低复杂性&#xff08…

华为ensp:交换机接口划分vlan

现在要把 e0/0/1 接口放入vlan1 e0/0/2 接口放入vlan2 e0/0/3 接口放入vlan3 默认所有接口都在vlan1所以 e0/0/0 接口不用动 1.创建vlan 进入系统视图模式 直接输入 vlan 编号 即可创建对应vlan vlan 编号 vlan 2 创建vlan2 vlan 3 创建vlan3 2.将接口进入vlan…

Spring Boot自动配置原理、实战、手撕自动装配源码

Spring Boot自动配置原理 相比较于传统的 Spring 应用&#xff0c;搭建一个 SpringBoot 应用&#xff0c;我们只需要引入一个注解 SpringBootApplication&#xff0c;就可以成功运行。 前面四个不用说&#xff0c;是定义一个注解所必须的&#xff0c;关键就在于后面三个注解&a…

Flink SQL自定义表值函数(Table Function)

使用场景&#xff1a; 表值函数即 UDTF&#xff0c;⽤于进⼀条数据&#xff0c;出多条数据的场景。 开发流程&#xff1a; 实现 org.apache.flink.table.functions.TableFunction 接⼝实现⼀个或者多个⾃定义的 eval 函数&#xff0c;名称必须叫做 eval&#xff0c;eval ⽅法…

OpenCV-Python小应用(九):通过灰度直方图检测图像异常点

OpenCV-Python小应用&#xff08;九&#xff09;&#xff1a;通过灰度直方图检测图像异常点 前言前提条件相关介绍实验环境通过灰度直方图检测图像异常点代码实现输出结果 参考 前言 由于本人水平有限&#xff0c;难免出现错漏&#xff0c;敬请批评改正。更多精彩内容&#xff…

centos7安装linux版本的mysql

1.下载linux版本的mysql 进入mysql官网&#xff0c;点击社区版本下载&#xff1a; https://dev.mysql.com/downloads/mysql/ 选择版本&#xff0c;可以跟着我下面这个图进行选择&#xff0c;选择红帽版本的既可&#xff0c;都是linux版本的。 2.上传解压linux版本的mysql安装包…

linux安装nodejs

写在前面 因为工作需要&#xff0c;需要使用到nodejs&#xff0c;所以这里简单记录下学习过程。 1&#xff1a;安装 wget https://nodejs.org/dist/v14.17.4/node-v14.17.4-linux-x64.tar.xz tar xf node-v14.17.4-linux-x64.tar.xz mkdir /usr/local/lib/node // 这一步骤根…

力扣138:随机链表的复制

力扣138&#xff1a;随机链表的复制 题目描述&#xff1a; 给你一个长度为 n 的链表&#xff0c;每个节点包含一个额外增加的随机指针 random &#xff0c;该指针可以指向链表中的任何节点或空节点。 构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成&#xff…

【从0到1设计一个网关】上岸大厂的秘诀之一

文章目录 前言【从0到1设计一个网关】什么是网关&#xff1f;以及为什么需要自研网关&#xff1f;【从0到1设计一个网关】自研网关的设计要点以及架构设计【从0到1设计一个网关】自研网关的架构搭建【从0到1设计一个网关】网络通信框架Netty的设计【从0到1设计一个网关】整合Na…

智能指针,c++11,单例,类型转换

c11 unique_ptr 防拷贝 shared_ptr / weak_ptr: 引用计数,支持拷贝 面试 手写shared_ptr 各种ptr的特性对比, 不会问定制删除器和weak_ptr,但是问shared_ptr时,可以往这边延展. 单例 保证一写数据在一个进程中,只有一份,并且方便访问修改. 饿汉模式 在main函数之前就创…

竞赛 车道线检测(自动驾驶 机器视觉)

0 前言 无人驾驶技术是机器学习为主的一门前沿领域&#xff0c;在无人驾驶领域中机器学习的各种算法随处可见&#xff0c;今天学长给大家介绍无人驾驶技术中的车道线检测。 1 车道线检测 在无人驾驶领域每一个任务都是相当复杂&#xff0c;看上去无从下手。那么面对这样极其…

win10网络和Internet设置

win10网络设置 win10进入网络设置的常用入口有两个 第一个入口 桌面右下角右键网络图标&#xff0c;然后打开“网络和Internt设置” 第二个入口 桌面的“我的网络”快捷方式&#xff0c;或者我的电脑进去后&#xff0c;左侧栏找到“网络” 右键“属性” 可以看到&#xff0c;…

图论10-哈密尔顿回路和哈密尔顿路径+状态压缩+记忆化搜索

文章目录 1 哈密尔顿回路2 哈密尔顿回路算法实现2.1 常规回溯算法2.2 引入变量记录剩余未访问的节点数量 3 哈密尔顿路径问题4 状态压缩4.1 查看第i位是否为14.2 设置第i位是为1或者04.3 小结4.4 状态压缩在哈密尔顿问题中的应用 5 记忆化搜索5.1 记忆化搜索与递推区别5.2 记忆…

基于单片机的空调智能控制器的设计

**单片机设计介绍&#xff0c;基于单片机的空调智能控制器的设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机的空调智能控制器需要具备输入输出端口、定时器、计数器等模块&#xff0c;以便对空调进行精确控制。下…

补坑:Java的字符串String类(3):再谈String

不太熟悉字符串的可以看看这两篇文章 补坑&#xff1a;Java的字符串String类&#xff08;1&#xff09;-CSDN博客 补坑&#xff1a;Java的字符串String类&#xff08;2&#xff09;&#xff1a;一些OJ题目-CSDN博客 字符串创建对象 public static void main(String[] args) …

ES6学习

let和const命名 let基本用法-块级作用域 在es6中可以使用let声明变量&#xff0c;用法类似于var ⚠️ let声明的变量&#xff0c;只在let命令所在的代码块内有效 {let a 10;var b 20; } console.log(a); //a is not defined console.log(b); //20不存在变量提升 var命令…

【11】使用透视投影建立一个3D空间的测试

核心操作&#xff1a; 1.proj view model 这三个矩阵 glm::mat4 mvp m_Proj * m_View * model; m_Shader->Bind(); m_Shader->SetUniformMat4f("u_MVP", mvp);着色器里面就&#xff1a; proj:投影矩阵&#xff0c;可以选择正交投影&#xff0c;或者透视投影…