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']; //上傳文件出現的錯誤號,為一個整數
\)_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">
// 實例化 UEditor
var ue = UE.getEditor('editor');
</script>
</body>
</html>
運行效果:
進行文件上傳的測試
可以看到第三方組件過濾了簡單的惡意文件
總結
到此文件上傳漏洞的大致原理和簡單利用就結束了,自己開發的代碼漏洞出在自己開發的部分,而如果引用第三方組件,那么漏洞點在第三方組件。至于過濾、繞過這些都是后面的事情
總結
以上是生活随笔為你收集整理的php开发之文件上传的实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 3.1 IDA Pro编写IDC脚本入门
- 下一篇: 闲来无聊,花了1小时我去爬了掘金相亲角热