(一)临时文件简介
临时文件,顾名思义是临时的文件,文件的生命周期短。
然而,很多应用的运行都离不开临时文件,临时文件在我们电脑上无处不在,通常有以下几种形式的临时文件:

文件或图形编辑程序,所生成的中间文件
数据库查询时,生成的临时缓存文件,提供之前的结果数据而,以减少再次访问数据库的代价;通常用于远程数据库或远程xml的服务
文件被上传后在服务端的临时储存,其文件名为php的全局变量$_FILES['userfile']['tmp_name']的值
在http请求中,用于存放session的临时文件,这些文件名通常就是sessionid(如 sess_7483ae44d51fe21353afb671d13f7199)
在不同应用或相同应用传递数据,而对方要求基于文件的输入,此时用临时文件存放数据
(二)临时文件的安全特征
临时文件的最大特征就是它的非持久性,除此之外,从安全性的角度,可以从以下几个方面关注临时文件的其它特点或风险:
1)位置
临时文件通常被创建并存放在默认的路径,在一个典型的Linux系统中,至少有两个目录或分区保持着临时文件。其中之一是/tmp目录,再者是/var/tmp。在更新的Linux内核的系统中,还可能有/dev/shm,它是用tmpfs文件系统装载的。有时临时文件,也可能放在用户home目录下的隐藏子目录中。使用默认临时文件目录的好处在于,系统进程可以方便查找和读写。
然而,默认临时文件的存放目录可能成为损害系统安全的僵尸和rootkit的温床。这是因为在多数情况下,任何人(或任何进程)都可以向这些目录写入东西,有不安全的许可问题。比如我们都知道sticky bit,该位可以理解为防删除位。如果希望用户能够添加文件但同时不能删除文件, 则可以对文件使用sticky bit位。设置该位后,就算用户对目录具有写权限,也不能删除该文件。多数Linux发行版本在临时目录上设置sticky位,这意味着用户A不能清除属于用户B的一个文件,反之亦然。但是,根据文件自身的许可,用户A有可能查看并修改那个文件的内容。
2)持久
前面提到临时文件是非持久的,在程序结束时,会被删除,但有的时候临时文件也会被迫持久保存了,没有被删除,如:

应用程序在关闭前崩溃了,还没有机会删除临时文件
应用程序还跑着,但操作系统崩溃了
文件复制过程中由于空间问题而复制失败,导致中间文件没有删除
操作系统进程通常会定期清空的默认临时文件目录,但可能因为某些原因,而删除失败
写得不好的应用程序,可能忽略或者忘记了删除临时文件
3)风险
无用的临时文件像幽灵一样存在你的服务器上,一方面占用硬盘,另一方面,可以被其它人非法使用,存着如下一些风险:
3.1)可见
众所周知,将私有数据公开很有风险。一旦用户通过某些手段(如shell或者ftp)窃取了你的临时文件,就可以获取到用户或企业的私有数据,从而对你造成影响。
例如:临时文件2011_Confidential_Sales_Strategies.tmp,可能暴露你们公司2011年的商业策略,这对你的竞争对手来说,将很有用处;而对于session劫持者来说,存放用户session信息的临时文件sess_95971078f4822605e7a18c612054f658非常关键。
除此之后,还有别的情况临时文件可能会被偷窥,如:一个拼写检查的服务,返回结果的url是:http://bad.example.com/spellcheck.php?tmp_file=spellcheck46 ,攻击者分析你的url参数后使用http://bad.example.com/spellcheck.php?tmp_file=spellcheck45 就可以访问到前一个用户的验证结果了。
3.2)执行
通常临时文件是不可执行,但如果攻击者上传了一个php脚本到你的临时目录,而且通过某种方式执行了它,那可能造成悲剧了。如下:
<?php exec(‘rm /*.*’); ?>
3.3)劫持
攻击者可能为了自己的目的,而劫持你的临时文件。他可能替换你的临时文件,也可能在你的临时文件后面追加一些信息。
劫持临时文件的目的包括:

让你的应用程序处理他的数据,而不是你自己的数据
暴露隐私数据,比如系统的密码文件,或者其它php安全模式不能正常读的文件
删除数据,阻碍请求的正常进行
创建并输出虚假的数据,破坏请求的结果
通过提供虚假的数据,对使用数据进行下一步处理的应用程序造成破坏
将你的输出重定向到其它地方,可以方便攻击者访问或者覆盖系统文件
劫持通常与竞争条件相关。当两个不同的进程操作同一个文件的时候,就可能产生竞争条件。例如,一个读进程和一个写进程同时操作一段数据,当写进程只完成了一部分的时候,读进程已经完成,这样读的到内容一部分是新的,一部分是旧的,也就是我们常说的读脏数据。
临时文件的劫持,在一定程度上会造成竞争条件,除非劫持者准确的把握时间和位置,否则就会造成此类安全问题。
(三)预防临时文件的恶用
前面我们介绍了临时文件的概念,以及临时文件被恶用可能带来的危害,这个部分主要介绍一些策略来预防临时文件被恶意利用,以及减少其带来的危害。
1)调整存放位置
防止临时文件被恶意利用的最重要,也是最简单的一步就是让你的临时文件目录以及名字不容易被猜到。任何对临时文件的恶意利用,攻击者都必须知道临时文件的名字和路径,因此你应该尽可能的让他难以猜到你的临时文件名字及路径。
建议你在临时文件目录的选择时,还是将你的临时文件放在默认的目录下吧,这样系统进程可以方便找到以及读写。而把精力花费放在为文件名想个合适的难猜的名字。
php的tempnam()函数,可以创建一个临时文件,并且其自动生成的文件名不会与当前目录下的其它文件名冲突,此函数创建的文件默认权限是600,即rw——-。
例如
$filename = tempnam( ‘..’, ‘myTempfile’);
运行后可能生成一个名为myTempfile1af的文件,当第二次运行的时候就生成了名为myTempfile1b0的文件名。
也许一些编程实践指南会建议你在使用tempnam()生成文件的时候,用一些有意义的前缀来命名,这样能通过文件名看出文件中包含的数据或者需要此数据的应用,但从安全性的角度来看最好不要这样,这样等于为攻击者指明了方向。
这里介绍一种方法,即能有一定意义的前缀同时也让攻击者不那么好猜,如下:
<?php
// define the parts of the filename
define (‘TMP_DIR’,'/tmp/’);
$prefix = ‘skiResort’;
// construct the filename
$tempFilename = uniqid( $prefix, TRUE );
// create the file
touch( $tempFilename );
// restrict permissions
chmod ( $tempFilename, 0600 );
// now work with the file
// … assuming data in $value
file_put_contents( $tempFilename, $value );
// …
// when done with temporary file, delete it
unlink ( $tempFilename );
?>
这个脚本通过uniqid()函数,生成的文件名格式为:/tmp/skiResort392942668f9b396c08.03510070,并通过chmod将文件的权限设置为600。
如果你需要与其它应用共享信息,比如用户密码或运行时生成的随机token,这里你可能需要对文件名加密,只有知道这个密钥的应用程序才能读取或修改文件内容。
如下是一个简单的生成加密文件名文件的示例:
<?php
$pathPrefix = ‘/tmp/skiResort’;
// for demonstration, construct a secret here
$secret = ‘Today is ‘ . date( “l, d F.” );
$randomPart = sha1( $secret );
$tempFilename = $pathPrefix . $randomPart;
touch( $tempFilename );
chmod ( $tempFilename, 0600 );
// now work with the file
// … assuming data in $value
file_put_contents( $tempFilename, $value );
// …
// when done with temporary file, delete it
unlink ( $tempFilename );
?>
2)约束访问权限
为了降低临时文件被执行或劫持的可能性,需要设置临时文件和临时文件目录的访问权限。通常情况下,将临时文件的权限设置为rw——-,临时文件目录的权限设置为rwx——。
此外,也可以通过设置apache的配置文件来限制访问(只有你将临时文件放在www目录下的时候),如下:
<Directory /var/www/myapp/tmp>
<FilesMatch “\.ph(p(3|4)?|tml)$”>
order deny,allow
deny from all
</FilesMatch>
</Directory>
3)只写已知文件
既然你是临时文件的创建者和作者,那你应该随时知道哪些文件存在,文件里有哪些内容。前面提到的方法,只是让临时文件劫持更困难,但不能完全杜绝劫持者替换文件或者在文件后面追加一些内容的可能,所以在你创建或写文件时,需要仔细检查文件内容是否满足要求。

当你使用w+的方式,创建了一个文件,在你开始写之前,这个文件应该为空,如下
<?php
if ( filesize( $tempFilename ) === 0 ) {
// write to the file
} else {
exit ( “$tempFilename is not empty.\nStart over again.”);
}
?>
如果文件不为空,可能你创建的有问题,也有可能劫持者在你创建与写文件的这个时间段 内作了手脚。

还有可能,你第一次成功写入了临时文件,但在你后面的写的过程中,劫持者对这个临时文件进行了一些操作,这种情况可以通过检验码的方式来检查,如下:
<?php
// write something to the file; then hash it
$hashnow = sha1_file( $tempFilename );
$_SESSION['hashnow'] = $hashnow;
// later, get ready to write again
$hashnow = sha1_file( $tempFilename );
if ( $hashnow === $_SESSION['hashnow'] ) {
// write to the file again
// get and save a new hash
$hashnow = sha1_file( $tempFilename );
$_SESSION['hashnow'] = $hashnow;
} else {
exit ( “Temporary file contains unexpected contents.\nStart over again.”);
}
?>
4)只读已知文件
与只写已知文件类似,在读文件前需要检查检验码是否一致,防止临时文件被篡改。除此之外,如果你使用了openssl,可以在写文件的时候,将合法证书放在文件的末尾,这样的读的时候可以先检查文件末尾是否存在合法的证书;如果你没有使用openssl,也可以写入一段特定的算法生成的token,原理类似。
5)检查上传的文件
判断文件是否是通过 HTTP POST 上传的
bool is_uploaded_file ( string $filename )
如果 filename 所给出的文件是通过 HTTP POST 上传的则返回 TRUE。这可以用来确保恶意的用户无法欺骗脚本去访问本不能访问的文件,例如 /etc/passwd。 如果上传的文件有可能会造成对用户或本系统的其他用户显示其内容的话,这种检查显得格外重要。
为了能使 is_uploaded_file() 函数正常工作,必须指定类似$_FILES['userfile']['tmp_name'] 的变量,而不是从客户端上传的文件名 $_FILES['userfile']['name']。需要注意的是is_uploaded_file返回false,不一定是上传文件被劫持了,也有可能是文件太大或者上传部分等,这些可以通过$_FILES['userfile']['error']查看。
参考文献:
《Apress pro.php security 2th》
http://cn.php.net/is_uploaded_file
http://server.chinabyte.com/46/11089046.shtml

本文来自 http://blog.webshuo.com/2011/04/11/php%E5%AE%89%E5%85%A8%E4%B9%8B%E4%B8%B4%E6%97%B6%E6%96%87%E4%BB%B6%E7%9A%84%E5%AE%89%E5%85%A8/

PHP安全之临时文件的安全的更多相关文章

  1. IE8,IE10下载的临时文件到哪里去了???

    操作攻略: 打开IE浏览器=>工具=>Internet选项=>常规选项卡中,找到"浏览历史记录"=>设置,然后就可看到"当前位置"所列出 ...

  2. SQLite剖析之临时文件、内存数据库

    一.7种临时文件    SQLite中,一个数据库由单个磁盘文件构成,简化了SQLite的使用,因为移动或备份数据库只要拷贝单个文件即可.这也使得SQLite适合用作应用程序文件格式.但是,当在单个文 ...

  3. Apache Spark技术实战之8:Standalone部署模式下的临时文件清理

    未经本人同意严禁转载,徽沪一郎. 概要 在Standalone部署模式下,Spark运行过程中会创建哪些临时性目录及文件,这些临时目录和文件又是在什么时候被清理,本文将就这些问题做深入细致的解答. 从 ...

  4. windows API 创建临时文件

    创建完临时文件后,即可用C\C++标准函数写入.读取,也可以用API.MFC方法来操作. TCHAR szPathName[MAX_PATH]; TCHAR szFileName[MAX_PATH]; ...

  5. mkstemp生成临时文件

    使用该函数可以指定目录生成临时文件,函数原型为 int mkstemp(char *template); 应用举例 int main(int argc, char *argv[]) { /* char ...

  6. VMWare虚拟机 使用vmtools拷贝文件 临时文件问题

    Win7下, 临时文件会存放在路径C:\Users\admin\AppData\Local\Temp\vmware-admin\VMwareDnD,如果不及时删除,C盘就会越来越大直至放满.

  7. [python] 创建临时文件-tempfile模块

    This module generates temporary files and directories. It works on all supported platforms.In versio ...

  8. 如何清理WindowsXp的临时文件

    软件限制策略中的 "路径规则" 不允许的, 是指在 这个路径中的程序都 不准运行! 这就限制了 : 通常电脑中病毒, 都是通过上网感染病毒的 -> 病毒/恶意软件通过 &qu ...

  9. 临时文件相关的v$tempfile v$sort_usage与V$tempseg_usage

    SQL> select username,user,segtype,segfile#,segblk#,extents,segrfno# from v$sort_usage; SEGFILE#代表 ...

  10. AutoIT删除Internet临时文件

    搜集了几个超赞的方法: 1.删除临时文件 Temporary Internet Files:RunDll32.exe InetCpl.cpl,ClearMyTracksByProcess 8 2. 删 ...

随机推荐

  1. hdu3191+hdu1688(求最短路和次短路条数,模板)

    hdu3191题意:求出次短路的长度和条数 #include<iostream> #include<cstdio> #include<cstring> #inclu ...

  2. C#学习笔记(17)——C#中接口的作用

    说明(2017-7-17 23:50:48): 原文: 接口的作用 接口的作用(C#)(另一篇) C#接口是一个让很多初学C#者容易迷糊的东西,用起来好像很简单,定义接口,里面包含方法,但没有方法具体 ...

  3. WPF中的数据驱动

    在WPF出现之前,Win Form,ASP.NET等技术均采用“事件驱动”理念,这种由“事件-订阅-事件处理器”关系交织在一起构成的程序,景观可以使用MVC.MVP等设计模式,但一不小心就会使界面逻辑 ...

  4. Spring Bean装配学习

    解释:所谓装配就是把一个类需要的组件给它设置进去,英文就是wire,wiring:注解Autowire也叫自动装配. 目前Spring提供了三种配置方案: 在XML中进行显式的配置 在Java中进行显 ...

  5. Android 一条竖线或横线、画边框

    Android 一条竖线或横线.画边框 博客分类: android androidshape  1.画线 [img] http://pic002.cnblogs.com/images/2010/122 ...

  6. go包管理之glide

    go语言的包是没有中央库来统一管理的,通过使用go get命令从远程代码库(github.com,goolge code 等)拉取,直接跳过中央版本库的约束,让代码的拉取直接基于源代码版本控制库,开发 ...

  7. 在Linux下用make指令编译进度条程序。

    首先建立一个新的文件,touch progress_bar.c 运行该vim progress_bar.c命令.写进度条的程序. 写进一个进度条程序: #include<stdio.h> ...

  8. Redis管道传输

    Redis是一个TCP服务器,并支持请求/响应协议.redis的一个请求完成需要下面的步骤: 客户端发送一个查询到服务器,并从套接字中读取,通常在封闭的方式,对服务器的响应. 服务器处理命令并将响应返 ...

  9. 再谈git的http服务-权限控制gitweb版(未成功)

    截至目前,对gitweb的掌握还没达到最终目标,仅仅实现了通过浏览器来浏览项目,通过git命令仍然未能clone项目.但仍然要记录下来,主要是因为打算暂时放弃这条路,而所收获的一些经验还是要记录下来. ...

  10. 使用JAAS登录kerberos服务器

    java代码: package com.snsprj.jaas0822; import javax.security.auth.*; import javax.security.auth.callba ...