Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
S
sts网站
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
liyang
sts网站
Commits
6bb166b8
Commit
6bb166b8
authored
Nov 17, 2020
by
RuoYi
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
阻止任意文件下载漏洞
parent
823e9566
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
136 additions
and
19 deletions
+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
No files found.
ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java
View file @
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
{
if
(!
FileUtils
.
checkAllowDownload
(
resource
))
{
throw
new
Exception
(
StringUtils
.
format
(
"资源文件({})非法,不允许下载。 "
,
resource
));
}
// 本地资源路径
// 本地资源路径
String
localPath
=
RuoYiConfig
.
getProfile
();
String
localPath
=
RuoYiConfig
.
getProfile
();
// 数据库资源地址
// 数据库资源地址
String
downloadPath
=
localPath
+
StringUtils
.
substringAfter
(
nam
e
,
Constants
.
RESOURCE_PREFIX
);
String
downloadPath
=
localPath
+
StringUtils
.
substringAfter
(
resourc
e
,
Constants
.
RESOURCE_PREFIX
);
// 下载名称
// 下载名称
String
downloadName
=
StringUtils
.
substringAfterLast
(
downloadPath
,
"/"
);
String
downloadName
=
StringUtils
.
substringAfterLast
(
downloadPath
,
"/"
);
response
.
setCharacterEncoding
(
"utf-8"
);
response
.
setContentType
(
MediaType
.
APPLICATION_OCTET_STREAM_VALUE
);
response
.
setContentType
(
"multipart/form-data"
);
FileUtils
.
setAttachmentResponseHeader
(
response
,
downloadName
);
response
.
setHeader
(
"Content-Disposition"
,
"attachment;fileName="
+
FileUtils
.
setFileDownloadHeader
(
request
,
downloadName
));
FileUtils
.
writeBytes
(
downloadPath
,
response
.
getOutputStream
());
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
View file @
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
View file @
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"
);
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment