Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
T
topology
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
姜立玮
topology
Commits
6bb166b8
提交
6bb166b8
authored
11月 17, 2020
作者:
RuoYi
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
阻止任意文件下载漏洞
上级
823e9566
变更
3
隐藏空白字符变更
内嵌
并排
正在显示
3 个修改的文件
包含
136 行增加
和
19 行删除
+136
-19
CommonController.java
...ava/com/ruoyi/web/controller/common/CommonController.java
+26
-17
FileTypeUtils.java
.../main/java/com/ruoyi/common/utils/file/FileTypeUtils.java
+47
-0
FileUtils.java
.../src/main/java/com/ruoyi/common/utils/file/FileUtils.java
+63
-2
没有找到文件。
ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java
浏览文件 @
6bb166b8
...
@@ -5,6 +5,7 @@ import javax.servlet.http.HttpServletResponse;
...
@@ -5,6 +5,7 @@ import javax.servlet.http.HttpServletResponse;
import
org.slf4j.Logger
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.http.MediaType
;
import
org.springframework.web.bind.annotation.GetMapping
;
import
org.springframework.web.bind.annotation.GetMapping
;
import
org.springframework.web.bind.annotation.PostMapping
;
import
org.springframework.web.bind.annotation.PostMapping
;
import
org.springframework.web.bind.annotation.RestController
;
import
org.springframework.web.bind.annotation.RestController
;
...
@@ -41,17 +42,15 @@ public class CommonController
...
@@ -41,17 +42,15 @@ public class CommonController
{
{
try
try
{
{
if
(!
FileUtils
.
isValidFilename
(
fileName
))
if
(!
FileUtils
.
checkAllowDownload
(
fileName
))
{
{
throw
new
Exception
(
StringUtils
.
format
(
"文件名称({})非法,不允许下载。 "
,
fileName
));
throw
new
Exception
(
StringUtils
.
format
(
"文件名称({})非法,不允许下载。 "
,
fileName
));
}
}
String
realFileName
=
System
.
currentTimeMillis
()
+
fileName
.
substring
(
fileName
.
indexOf
(
"_"
)
+
1
);
String
realFileName
=
System
.
currentTimeMillis
()
+
fileName
.
substring
(
fileName
.
indexOf
(
"_"
)
+
1
);
String
filePath
=
RuoYiConfig
.
getDownloadPath
()
+
fileName
;
String
filePath
=
RuoYiConfig
.
getDownloadPath
()
+
fileName
;
response
.
setCharacterEncoding
(
"utf-8"
);
response
.
setContentType
(
MediaType
.
APPLICATION_OCTET_STREAM_VALUE
);
response
.
setContentType
(
"multipart/form-data"
);
FileUtils
.
setAttachmentResponseHeader
(
response
,
realFileName
);
response
.
setHeader
(
"Content-Disposition"
,
"attachment;fileName="
+
FileUtils
.
setFileDownloadHeader
(
request
,
realFileName
));
FileUtils
.
writeBytes
(
filePath
,
response
.
getOutputStream
());
FileUtils
.
writeBytes
(
filePath
,
response
.
getOutputStream
());
if
(
delete
)
if
(
delete
)
{
{
...
@@ -92,18 +91,28 @@ public class CommonController
...
@@ -92,18 +91,28 @@ public class CommonController
* 本地资源通用下载
* 本地资源通用下载
*/
*/
@GetMapping
(
"/common/download/resource"
)
@GetMapping
(
"/common/download/resource"
)
public
void
resourceDownload
(
String
name
,
HttpServletRequest
request
,
HttpServletResponse
response
)
throws
Exception
public
void
resourceDownload
(
String
resource
,
HttpServletRequest
request
,
HttpServletResponse
response
)
throws
Exception
{
{
// 本地资源路径
try
String
localPath
=
RuoYiConfig
.
getProfile
();
{
// 数据库资源地址
if
(!
FileUtils
.
checkAllowDownload
(
resource
))
String
downloadPath
=
localPath
+
StringUtils
.
substringAfter
(
name
,
Constants
.
RESOURCE_PREFIX
);
{
// 下载名称
throw
new
Exception
(
StringUtils
.
format
(
"资源文件({})非法,不允许下载。 "
,
resource
));
String
downloadName
=
StringUtils
.
substringAfterLast
(
downloadPath
,
"/"
);
}
response
.
setCharacterEncoding
(
"utf-8"
);
// 本地资源路径
response
.
setContentType
(
"multipart/form-data"
);
String
localPath
=
RuoYiConfig
.
getProfile
();
response
.
setHeader
(
"Content-Disposition"
,
// 数据库资源地址
"attachment;fileName="
+
FileUtils
.
setFileDownloadHeader
(
request
,
downloadName
));
String
downloadPath
=
localPath
+
StringUtils
.
substringAfter
(
resource
,
Constants
.
RESOURCE_PREFIX
);
FileUtils
.
writeBytes
(
downloadPath
,
response
.
getOutputStream
());
// 下载名称
String
downloadName
=
StringUtils
.
substringAfterLast
(
downloadPath
,
"/"
);
response
.
setContentType
(
MediaType
.
APPLICATION_OCTET_STREAM_VALUE
);
FileUtils
.
setAttachmentResponseHeader
(
response
,
downloadName
);
FileUtils
.
writeBytes
(
downloadPath
,
response
.
getOutputStream
());
}
catch
(
Exception
e
)
{
log
.
error
(
"下载文件失败"
,
e
);
}
}
}
}
}
ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileTypeUtils.java
0 → 100644
浏览文件 @
6bb166b8
package
com
.
ruoyi
.
common
.
utils
.
file
;
import
java.io.File
;
import
org.apache.commons.lang3.StringUtils
;
/**
* 文件类型工具类
*
* @author ruoyi
*/
public
class
FileTypeUtils
{
/**
* 获取文件类型
* <p>
* 例如: ruoyi.txt, 返回: txt
*
* @param file 文件名
* @return 后缀(不含".")
*/
public
static
String
getFileType
(
File
file
)
{
if
(
null
==
file
)
{
return
StringUtils
.
EMPTY
;
}
return
getFileType
(
file
.
getName
());
}
/**
* 获取文件类型
* <p>
* 例如: ruoyi.txt, 返回: txt
*
* @param fileName 文件名
* @return 后缀(不含".")
*/
public
static
String
getFileType
(
String
fileName
)
{
int
separatorIndex
=
fileName
.
lastIndexOf
(
"."
);
if
(
separatorIndex
<
0
)
{
return
""
;
}
return
fileName
.
substring
(
separatorIndex
+
1
).
toLowerCase
();
}
}
\ No newline at end of file
ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java
浏览文件 @
6bb166b8
...
@@ -7,7 +7,11 @@ import java.io.IOException;
...
@@ -7,7 +7,11 @@ import java.io.IOException;
import
java.io.OutputStream
;
import
java.io.OutputStream
;
import
java.io.UnsupportedEncodingException
;
import
java.io.UnsupportedEncodingException
;
import
java.net.URLEncoder
;
import
java.net.URLEncoder
;
import
java.nio.charset.StandardCharsets
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
org.apache.commons.lang3.ArrayUtils
;
import
com.ruoyi.common.utils.StringUtils
;
/**
/**
* 文件处理工具类
* 文件处理工具类
...
@@ -104,6 +108,30 @@ public class FileUtils extends org.apache.commons.io.FileUtils
...
@@ -104,6 +108,30 @@ public class FileUtils extends org.apache.commons.io.FileUtils
return
filename
.
matches
(
FILENAME_PATTERN
);
return
filename
.
matches
(
FILENAME_PATTERN
);
}
}
/**
* 检查文件是否可下载
*
* @param resource 需要下载的文件
* @return true 正常 false 非法
*/
public
static
boolean
checkAllowDownload
(
String
resource
)
{
// 禁止目录上跳级别
if
(
StringUtils
.
contains
(
resource
,
".."
))
{
return
false
;
}
// 检查允许下载的文件规则
if
(
ArrayUtils
.
contains
(
MimeTypeUtils
.
DEFAULT_ALLOWED_EXTENSION
,
FileTypeUtils
.
getFileType
(
resource
)))
{
return
true
;
}
// 不在允许下载的文件规则
return
false
;
}
/**
/**
* 下载文件名重新编码
* 下载文件名重新编码
*
*
...
@@ -111,8 +139,7 @@ public class FileUtils extends org.apache.commons.io.FileUtils
...
@@ -111,8 +139,7 @@ public class FileUtils extends org.apache.commons.io.FileUtils
* @param fileName 文件名
* @param fileName 文件名
* @return 编码后的文件名
* @return 编码后的文件名
*/
*/
public
static
String
setFileDownloadHeader
(
HttpServletRequest
request
,
String
fileName
)
public
static
String
setFileDownloadHeader
(
HttpServletRequest
request
,
String
fileName
)
throws
UnsupportedEncodingException
throws
UnsupportedEncodingException
{
{
final
String
agent
=
request
.
getHeader
(
"USER-AGENT"
);
final
String
agent
=
request
.
getHeader
(
"USER-AGENT"
);
String
filename
=
fileName
;
String
filename
=
fileName
;
...
@@ -139,4 +166,38 @@ public class FileUtils extends org.apache.commons.io.FileUtils
...
@@ -139,4 +166,38 @@ public class FileUtils extends org.apache.commons.io.FileUtils
}
}
return
filename
;
return
filename
;
}
}
/**
* 下载文件名重新编码
*
* @param response 响应对象
* @param realFileName 真实文件名
* @return
*/
public
static
void
setAttachmentResponseHeader
(
HttpServletResponse
response
,
String
realFileName
)
throws
UnsupportedEncodingException
{
String
percentEncodedFileName
=
percentEncode
(
realFileName
);
StringBuilder
contentDispositionValue
=
new
StringBuilder
();
contentDispositionValue
.
append
(
"attachment; filename="
)
.
append
(
percentEncodedFileName
)
.
append
(
";"
)
.
append
(
"filename*="
)
.
append
(
"utf-8''"
)
.
append
(
percentEncodedFileName
);
response
.
setHeader
(
"Content-disposition"
,
contentDispositionValue
.
toString
());
}
/**
* 百分号编码工具方法
*
* @param s 需要百分号编码的字符串
* @return 百分号编码后的字符串
*/
public
static
String
percentEncode
(
String
s
)
throws
UnsupportedEncodingException
{
String
encode
=
URLEncoder
.
encode
(
s
,
StandardCharsets
.
UTF_8
.
toString
());
return
encode
.
replaceAll
(
"\\+"
,
"%20"
);
}
}
}
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论