为了防止安全漏洞,文件上传功能应该满足以下要求:
1.限制文件上传的大小
2.只允许满足业务需要的相关文件类型,限制上传任意可能被Web服务器解析的文件(如exe、bat、css、js、htm、html、aspx、jsp、asp、php等)
3.通过检查文件头信息(如JPEG文件头信息十六进制为FFD8FF),后端验证上传文件必须为允许的文件类型
4.上传文件以二进制形式下载,且不能在服务器端运行,防止木马文件直接执行
5.禁止授予上传文件存储目录的可执行权限。
详细说明
原生js判断文件类型和大小
1.限制文件上传的大小
限制文件大小的原因是防止有人通过上传非常大的文件,防止拒绝服务(DDos)攻击
2.限制文件传输的格式
通过限制文件上传类型,避免他人上传可执行的文件,脚本或其他具有潜在威胁的文件。
<input type="file" onchange="fileChange(this)">
<script type="text/javascript">
var fileChange = function(target){
let file = target.files[0];
//文件限制5M
let validSize = 5*1024*1024;
let validType = 'png';
if(!fileSizeValid(file.size,validSize)){
alert('文件大小超出限制')
return false
}
if(!fileTypeValid(file.name,validType)){
alert('文件格式不正确')
return false
}
//继续执行文件上传操作....
}
/**
* 检查文件上传大小
* @param {number} fileSize 用户选择文件的大小
* @param {number} validSize 限制大小
* @returns {boolean}
*/
var fileSizeValid = function(fileSize,validSize){
if(fileSize>validSize){
return false
}
return true
}
/**
* 检查文件类型
* @param {string} fileName 用户选择文件名称 xxx.html
* @param {string} validType 限制格式 png/xlsx/...
* @returns {boolean}
*/
var fileTypeValid = function(fileName,validType){
let dotPosition = fileName.lastIndexOf(".");
if(dotPosition===-1){
return false
}
let type = fileName.substring(dotPosition+1).toLowerCase();
if(type!==validType){
return false
}
return true
}
</script>
3.后端校验文件头信息
通过修改文件后缀名的方式,前端的校验可以被绕过。如将test.php重命名为test.png,实际上并不是图片文件,更可靠的方式是后端校验文件的头部信息。文件头部信息链接:
4.上传文件以二进制形式下载,且不能在服务器端运行,防止木马文件直接执行
若文件作为数据存储在数据库或者统一文件服务器,不能直接执行的,这条应该可以忽略。对于存储在自身服务器文件夹下的应用,有可能黑客通过上传可解析的文件破解服务器。示例:
这里做了一个实验,若通过文件上传功能上传名为test.aspx文件:
文件内容如下:
<%@ Page Language="Jscript"%> <%eval(Request.Item["value"])%>
访问文件时,在url里给value赋值,通过eval函数将直接执行value的参数内的代码。
黑客利用这个原理,通过木马软件(此处使用了《菜刀》)可以直接看到本机下的所有文件文件夹。
一方面需要限制jsp,aspx,php等格式的文件上传,一方面可以通过以二进制形式下载,且不能在服务器端运行,防止攻击者调用自己上传的文件,防止木马文件直接执行。
5.禁止授予上传文件存储目录的可执行权限。
可以通过设置专门的文件上传文件夹,并设置此文件夹的执行权限,来防止木马脚本的执行。