概述
1.理解文件上传的概念
2.了解文件上传攻击的方式
3.掌握防范攻击的方法
预备知识
有时候需要让来访者能够上传文件,例如在邮件服务中上传附件,在博客中上传图片,或是提供PHP+MySQL网页空间来让来访者上传文件。
在PHP中,文件的交换与表单数据传递的方式不同,在<form>标签中必须指定enctype属性值是multipart/form-data:
<form action="upload.php" method="post" enctype="multipart/form-data">
当同时传递文件与表单数据时,HTTP请求会有特殊的格式。因此在<form>标签中指定enctype属性值是multipart/form-data时,才能让文件正确上传。
设置上传文件的类型,需要设置type属性值为file的input标签:
<input type="file" name="file1" />
一个简单形式的文件上传表单:( 详细程序代码看 :
<meta Contenr-type="test/html" charset="utf-8" />
<form action="ex9-1-upload.php" method="post" enctype="multipart/from-data" target="form-target" onsubmit="startUpload();">
上传: <input type="file" name="file1" />
<input type="file" name="MAX_FILE_SIZE" value="1000000" />
<input type="submit" name="submit" value="上传文件" />
</form>
<input type="file" />类型用来指定上传文件的路径。
MAX_FILE_SIZE隐藏类型用来设置能够允许上传的最大文件大小是40106字节。
<input type="submit" />类型用来激活一个上传文件的操作。
点击“演示一”
点击“演示2”文件是一个一般形式的文件上传表单,如图:
上传文件的大小
在PHP的配置文件php.ini中,上传文件的大小默认值是2MB。也可以编辑这个数值,来修改允许上传的文件大小。
打开“C:xamppphpphp.ini"文件找到“upload_max_filesize”字段的位置,如图:
修改可以上传文件的大小
上传文件的大小默认值是128MB,可以更改这个数值来修改可以上传文件的大小,更改后保存php.ini文件,并且重新启动Apache服务器使修改的数据生效。
另外一种设置上传文件大小的方式,是在表单内加入一个隐藏按钮:
<input type="hidden" name="MAX_FILE_SIZE" value="2M" />
隐藏按钮的名称必须是“MAX_FILE_SIZE”,而且必须放在所有上传文件类型的前面。
“MAX_FILE_SIZE”隐藏按钮的value属性值,就是允许上传文件的最大大小。注意浏览器不一定会按照“MAX_FILE_SIZE”隐藏按钮的设置值,使用php.ini文件来设置是最保险的方式。
$FILES数组变量
PHP使用变量$_FILES来上传文件,$_FILES是一个数组。如果上传test.txt文件,那么使用: print_r($_FIIES); 来显示$_FILES数组的内容,将会得到:
$_FILES
Array
(
[file] => Array
(
[name] => test.txt
[type] => text/plam
[tmp_name] => C:WINDOWSTEMPphp5D.tmp
[error] => 0
[size] => 1662
)
)
● ['name']:这是在客户端的原始上传文件的名称,不包含路径。
● ['type']:上传文件的MIME类型。
● ['tmp_name']:服务器端用来保存上传文件的临时文件路径。
● ['error']:上传文件时的错误信息。
● ['size']:上传文件的大小,单位是字节。
其中,name与type是由来访者提供,tmp name、error与size则是由PHP系统提供。
如果“上传文件”按钮的name属性值是file:
<iput type="file" name="file" />
那么使用$_FILES['file']['name']来取得客户端的上传文件名称,不包含路径。使用$_FILES['file'][’tmp_name']来取得服务器端用来保存上传文件的临时文件路径。
存放上传文件的文件夹
PHP不会直接将上传文件放在网站的根目录中,而是保存为一个临时文件,这个临时文件的名称就是$_FILES ['file']['tmp_name']的值。用户必须将这个临时文件复制到存放的网站文件夹中。
$_FILES['file']['tmp_name']的临时文件名称是由PHP设置的,与上传文件的原始名称不一样。用户必须使用$_FILES['file']['name']来取得上传文件的原始名称。
存放上传文件的文件夹路径是由php.ini文件的upload_tmp_dir来设置的。
上传文件时的错误信息
$_FILES['file']['error']变量用来保存上传文件时的错误信息,它的数值如表10-1所示。
文件上传攻击
黑客能发动的文件上传攻击包括以下几个方面。
(1)黑客将可执行的PHP文件上传到网站的公共文件夹内,然后执行这个PHP文件来进行攻击。
(2)如果黑客了解您的网站的文件结构,他就可以上传与您的网站文件有相同名称的文件来覆盖您网站内的原有文件。
(3)黑客可以连续不断地上传文件,使您的Web应用程序没有更多的资源处理其他来访者的请求,由此来瘫痪您的网站,发动阻断服务攻击。
(4)上传的文件会保存到一个临时的文件夹,默认值的位置是系统的文件夹。
如果黑客有权限存取这个文件夹,就可以在文件上传期间在PHP还没有移动到目的文件夹之前读取上传的文件数据。
上传可执行文件
如果网站提供来访者上传图片的功能,那么必须小心来访者上传的实际上可能并不是图片,而是可以执行的PHP程序。如果存放图片的是一个公开的文件夹,黑客就可以远程执行上传的PHP文件来进行攻击。
上传的文件名称是在表单内指定,然后经由浏览器传递给服务器的。详细代码:
<meta Contenr-type="test/html" charset="utf-8" />
<form action="ex9-5.php" method="post" enctype="multipart/from-data" target="form-target" onsubmit="startUpload();">
上传: <input type="file" name="file1" />
<input type="hidden" name="MAX_FILE_SIZE" value="1000000" />
<input type="submit" name="submit" value="上传文件" />
</form>
假设现在我们打开“演示2”,单击浏览按钮,然后上传:
C:xampphtdocsexample_codesourcecode10ex10-3-attack.php文件
attack.php文件
然后点击上传,此时你将会看到ex9-3-attack.php文件上传成功:
这时我们就可以在远程执行下列HTTP请求,点击“攻击2”
ex10-3-attack.php文件只是显示一行文字:
Hello! 我是黑客
如果ex9-3-attack.php文件中的代码具有删除目录/文件或其他攻击性的程序代码,那么就会对网站造成极大的伤害。
现在来看打开ex10-4-attack.php文件的例子:详细代码
<meta Contenr-type="test/html" charset="utf-8" />
<form action="ex9-6.php" method="post" enctype="multipart/from-data" target="form-target" onsubmit="startUpload();">
上传: <input type="file" name="file1" />
<input type="hidden" name="MAX_FILE_SIZE" value="1000000" />
<input type="submit" name="submit" value="上传文件" />
</form>
点击“攻击3”
这会显示网站的C:/xampp/htdocs/example_code/source/code10/image文件夹的信息。
覆盖原有文件
如果黑客了解网站的目录结构,他就可以上传与网站文件有相同名称的文件。黑客可以藉此来覆盖网站内的原有文件,可以是系统文件、PHP文件,或是Web应用程序所使用的文件。
瘫痪网站
黑客可以连续不断地上传文件,或上传极大的文件,使Web应用程序无暇处理其他来访者的请求,借此来瘫痪网站,发动阻断服务( Denial of Service)攻击。
存取上传的文件数据
上传的文件会保存到一个临时的文件夹,默认值的位置是系统文件夹,在Windows上就是C:WINDOWSTEMP。
这个上传文件的临时文件夹通常是所有来访者都可以读取的。在文件土传期间,在PHP还没有将上传的文件移动到目的文件夹之前,任何来访者都可能存取上传的文件数据。 ‘
防范的方法
在防范文件上传攻击时,可以使用下列方法。
(1)如果您的Web应用程序不需要上传文件的功能就将它关掉。
(2)限制能够上传的文件大小。
(3)检查是否真的是上传的文件。
(4)更改保存上传临时文件目录的路径。
(5)读取上传文件的绝对路径与文件名称。
(6)隐藏文件的路径。
关掉上传文件的功能
如果Web应用程序不需要上传文件的功能,则可以直接将上传文件的功能关闭来避免不必要的麻烦。
打开“C:xamppphpphp.ini”文件,找到file_uploads的位置,将file_uploads设置成Off。
关闭文件上传的功能
限制允许上传的文件大小
如果黑客采取连续不断地上传文件,或是上传极大的文件,来使您的Web应用程序没有更多资源来处理其他来访者的请求,黑客就可以借此来瘫痪您的网站。
PHP的限制机制可以让您限制允许上传文件体积的最大值,来避免来访者上传太大的文件。
单独POST请求的最大值,可以使用php.ini文件的upload_max_size来设置。
打开“C:xamppphpphp.ini”文件,找到upload_max_size的位置,将upload_max_size设置成您想要的值,如图。
限制单独POST请求的最大值
upload_max_size的默认值是8M,表示整个POST请求的最大值是8MB。注意,upload_max_size的数值并不是单一上传文件的最大值,而是整个POST请求的最大值。
整个POST请求包括上传的文件、表头、其他表单类型。如果上传的文件有10个,那么这10个上传文件的大小总和不能够超过8MB。
上传文件的最大值可以用php.ini文件中的upload_max_filesize来设置。
upload_max_filesize的默认值是2M,表示所有上传文件的最大值是2MB。注意,upload_max_filesize的数值并不是单一上传文件的最大值,而是所有上传文件的最大值。
upload_max_filesize的设置值会比post_max_size的设置值小,这是因为post_max_size还包含了表头及其他的表单类型。
更改post_max_size与upload_max_filesize的设置值,来符合网站的需求。因为黑客可以上传极大的图片或文件来占用服务器的处理时间。如果服务器只处理这些上传的图片或文件,就无法提供服务给其他的来访者。
将post_max_size与upload_max_filesize的设置值设置得小些,具体的值就要视网站的需求而定。
检查是否真的是上传的文件
黑客会在上传的类型中输入类似:
../../etc/password
的路径字符串,来显示网站内其他文件夹的文件,尤其是存放账号与密码的文件。
PHP提供两个函数is_uploaded_file和move_uploaded_file,来检查是否是真正的上传文件。
(1)如果要检查$_FILES变量中tmp_name所表示的是否是一个上传的文件,可以使用is_uploaded_file函数。
is_uploaded_file函数的用法如下:
bool is_uploaded_file ( string filename )
filename是上传文件的路径
如果filename是使用HTTP的POST方法来上传的,那么is_uploaded_file函数会返回TRUE,请参考ex10-5.php文件。
源代码:C:xamppphpphp.ini
(2)如果要将上传的文件移动到某个文件夹,可以使用move_uploaded_file函数。move_uploaded_file函数的用法如下:
bool move_uploaded_file ( string filename, string destination )
● filename是上传文件的路径。
● destination是要移动的目的路径。
如果filename是使用HTTP的POST方法来上传的,那么move_uploaded_file函数会返回TRUE。如果filename不是上传的文件,或是无法移动到目的路径,那么move_uploaded_file函数会返回FALSE。
请参考ex10-6.php文件。
源码详细请看:C:/xampp/htdocs/example_code/source/code10/ex9-6.php
<?php
header("Content-Type: text/html; charset=UTF-8");
sleep(2);
$fileTypes=array('jpg','png','gif','bmp'.'php','txt','html','asp','htm','doc','docx','xml','pdf','ini','exe','dll','chm');
$result = null;
$uploadDir = 'c:/xampp/htdocs/example_code/source/code10/image/';
$maxSize = 1 * pow(2,20);
if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['submit'])) {
$myfile = $_FILES['filel'];
$myfileType = substr($mfile['name'],strrpos($myfile['name'],".") + 1);
if ($myfile['size'] > $maxSize) {
$result = 1;
} else if (!in_array($myfileType, $fileType)) {
$result = 2;
} else if (is_uploaded_file($myfile['tmp_name'])) {
$toFile = $uploadDir . '/' . $myfile['tmp_name'];
if (@move_uploaded_file($myfile['tmp_name'], $toFile)) {
$result = 0;
echo "上传成功!";
echo "是上传的文件,而是移动到目的路径"。$new_filename;
} else {
echo "上传错误" ;
}
}
?>
<?php
header("Content-type: text/html; charset=UTF-8");
$old_filename=$_FILES["filel"]["tmp_name"];
$new_filename="c:xampp/htdocs/example_code/source/code10/image/";
if (move_uploaded_file($old_filename, $new_filename))
{
echo $old_filename ."是上传的文件,而且移动到目的路径"。$new_filename;
}
?>
(3)另外还可以使用filesize函数,来检查上传文件的大小是否正确。
源码详细请看:C:/xampp/htdocs/example_code/source/code10/ex9-5.php
<?php
header("Content-Type: text/html; charset=UTF-8");
sleep(2);
$fileTypes=array('jpg','png','gif','bmp'.'php','txt','html','asp','htm','doc','docx','xml','pdf','ini','exe','dll','chm');
$result = null;
$uploadDir = 'c:/xampp/htdocs/example_code/source/code10/image/';
$maxSize = 1 * pow(2,20);
if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['submit'])) {
$myfile = $_FILES["filel"]["tmp_name"];
if (is_uploaded_file($filename))
{
echo "$filename是上传的文件";
}
$myfile = $_FILES['filel'];
$myfileType = substr($mfile['name'],strrpos($myfile['name'],".") + 1);
if ($myfile['size'] > $maxSize) {
$result = 1;
} else if (!in_array($myfileType, $fileType)) {
$result = 2;
} else if (is_uploaded_file($myfile['tmp_name'])) {
$toFile = $uploadDir . '/' . $myfile['name'];
if (@move_uploaded_file($myfile['tmp_name'], $toFile)) {
$result = 0;
echo "上传成功!";
} else {
echo "上传错误" ;
}
} else {
$result = 1;
}
}
?>
(4)如果上传的是图片文件,您可以使用getimagesize函数来检查上传图片的大小。getimagesize函数的用法如下:
array getimagesize ( string filename [,array &imageinfo])
filename是上传图片文件的路径
getimagesize函数会返回一个数组,包含以下5个元素。
● 图片的高度。
● 图片的宽度。
● 图片的类型。
● height="yyy" width="xxx"的字符串。
● 图片的MIME类型。
更改临时文件夹的路径
上传的文件会保存到一个临时的文件夹,在Windows上,PHP默认值的位置是在C:xampptmp。
这个临时文件夹通常是所有的来访者都可以读取的,因此建立一个只有网站管理员可以存取的文件夹来存放上传的临时文件,对于维护上传文件的安全会有很大的帮助。
PHP的上传文件的临时文件夹是在php.ini文件中的upload_tmp_ dir设置的。
打开“C:xamppphpphp.ini”文件,找到upload_tmp_dir的位置。将upload_tmp_dir设置成您要的路径,例如:
upload_tmp_dir = C:my_upload_dirtemp
如图所示:
另外还可以使用chown函数来指定文件的所有者。chown函数的用法如下:
bool chown ( string filename, mixed user )
● filename是上传文件的路径。
● user是文件的所有者,可以是名称或数字。
读取上传文件的绝对路径与文件名称
如果上传文件的路径中包含有“./”或“../”等可疑的路径字符,有可能就是黑客在使用目录切换攻击。黑客的目的是为了获取目录中的重要文件,例如包含账号与密码的文件。
您可以使用realpath和basename两个函数来确保上传文件的路径中不会出现“./”或“../”等可疑的路径字符。
浏览器提供的上传文件的路径,应该使用realpath函数返回规范化的绝对路径名,以及使用basename函数来返回不包含路径的文件名称。
(1) realpath函数用来展开文件路径中的“"./"”、“"../"”及“"/"”等字符,然后返回绝对的路径名称。realpath函数的用法如下:
string realpath( string path )
path是浏览器提供的上传文件的路径。
下列范例:
<?php
chdir ('/var/www/');
echo realpath('./../../etc/passwd');
?>
会得到:
/etc/passwd
(2) basename函数用来返回不包含路径的文件名称,用法如下:
string basename ( string path [, string suffi_x] )
● path是浏览器提供的上传文件的路径。
● suffix用来指定扩展名。
单击“防护4”你将会看到值为index
隐藏文件的路径
上传的文件不要保存在公开的文件夹内,以避免被黑客直接读取。另外将文件的路径隐藏起来,或是将文件名称改成没有扩展名的随机文件名,都可以增加上传文件的安全性。
最后
以上就是顺心薯片为你收集整理的文件上传攻击的全部内容,希望文章能够帮你解决文件上传攻击所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复