Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
D
dataease
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
zhu
dataease
Commits
5e34d52d
提交
5e34d52d
authored
8月 04, 2021
作者:
fit2cloud-chenyw
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
fix: sql注入和xss攻击
上级
9579d08b
隐藏空白字符变更
内嵌
并排
正在显示
4 个修改的文件
包含
493 行增加
和
0 行删除
+493
-0
SqlFilter.java
...d/src/main/java/io/dataease/commons/filter/SqlFilter.java
+78
-0
ThreadLocalContextHolder.java
.../io/dataease/commons/holder/ThreadLocalContextHolder.java
+24
-0
XssAndSqlHttpServletRequestWrapper.java
...e/commons/wrapper/XssAndSqlHttpServletRequestWrapper.java
+370
-0
FilterConfig.java
backend/src/main/java/io/dataease/config/FilterConfig.java
+21
-0
没有找到文件。
backend/src/main/java/io/dataease/commons/filter/SqlFilter.java
0 → 100644
浏览文件 @
5e34d52d
package
io
.
dataease
.
commons
.
filter
;
import
io.dataease.commons.holder.ThreadLocalContextHolder
;
import
io.dataease.commons.wrapper.XssAndSqlHttpServletRequestWrapper
;
import
org.apache.commons.lang3.StringUtils
;
import
javax.servlet.*
;
import
javax.servlet.http.HttpServletRequest
;
import
java.io.*
;
public
class
SqlFilter
implements
Filter
{
@Override
public
void
destroy
()
{
// TODO Auto-generated method stub
}
@Override
public
void
doFilter
(
ServletRequest
request
,
ServletResponse
response
,
FilterChain
chain
)
throws
IOException
,
ServletException
{
String
method
=
"GET"
;
String
param
=
""
;
XssAndSqlHttpServletRequestWrapper
xssRequest
=
null
;
if
(
request
instanceof
HttpServletRequest
)
{
method
=
((
HttpServletRequest
)
request
).
getMethod
();
xssRequest
=
new
XssAndSqlHttpServletRequestWrapper
((
HttpServletRequest
)
request
);
}
if
(
"POST"
.
equalsIgnoreCase
(
method
))
{
param
=
this
.
getBodyString
(
xssRequest
.
getReader
());
if
(
StringUtils
.
isNotBlank
(
param
)){
if
(
xssRequest
.
checkXSSAndSql
(
param
)){
response
.
setCharacterEncoding
(
"UTF-8"
);
response
.
setContentType
(
"application/json;charset=UTF-8"
);
PrintWriter
out
=
response
.
getWriter
();
String
msg
=
ThreadLocalContextHolder
.
getData
().
toString
();
out
.
write
(
msg
);
return
;
}
}
}
if
(
xssRequest
.
checkParameter
())
{
response
.
setCharacterEncoding
(
"UTF-8"
);
response
.
setContentType
(
"application/json;charset=UTF-8"
);
PrintWriter
out
=
response
.
getWriter
();
String
msg
=
ThreadLocalContextHolder
.
getData
().
toString
();
out
.
write
(
msg
);
return
;
}
chain
.
doFilter
(
xssRequest
,
response
);
}
@Override
public
void
init
(
FilterConfig
filterConfig
)
throws
ServletException
{
}
// 获取request请求body中参数
public
static
String
getBodyString
(
BufferedReader
br
)
{
String
inputLine
;
String
str
=
""
;
try
{
while
((
inputLine
=
br
.
readLine
())
!=
null
)
{
str
+=
inputLine
;
}
br
.
close
();
}
catch
(
IOException
e
)
{
System
.
out
.
println
(
"IOException: "
+
e
);
}
return
str
;
}
}
backend/src/main/java/io/dataease/commons/holder/ThreadLocalContextHolder.java
0 → 100644
浏览文件 @
5e34d52d
package
io
.
dataease
.
commons
.
holder
;
public
class
ThreadLocalContextHolder
{
private
static
ThreadLocal
<
Object
>
sceneThreadLocal
=
new
ThreadLocal
<>();
public
static
Object
getData
()
{
return
sceneThreadLocal
.
get
();
}
public
static
void
setData
(
Object
data
)
{
if
(
ThreadLocalContextHolder
.
sceneThreadLocal
==
null
)
{
ThreadLocalContextHolder
.
sceneThreadLocal
=
new
ThreadLocal
<>();
}
ThreadLocalContextHolder
.
sceneThreadLocal
.
set
(
data
);
}
public
static
void
clearScene
()
{
setData
(
null
);
}
}
backend/src/main/java/io/dataease/commons/wrapper/XssAndSqlHttpServletRequestWrapper.java
0 → 100644
浏览文件 @
5e34d52d
package
io
.
dataease
.
commons
.
wrapper
;
import
java.io.BufferedReader
;
import
java.io.ByteArrayInputStream
;
import
java.io.IOException
;
import
java.io.InputStreamReader
;
import
java.util.Enumeration
;
import
java.util.HashMap
;
import
java.util.Map
;
import
java.util.Set
;
import
java.util.Vector
;
import
java.util.regex.Matcher
;
import
java.util.regex.Pattern
;
import
javax.servlet.ReadListener
;
import
javax.servlet.ServletInputStream
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletRequestWrapper
;
import
io.dataease.commons.holder.ThreadLocalContextHolder
;
import
org.springframework.util.StreamUtils
;
public
class
XssAndSqlHttpServletRequestWrapper
extends
HttpServletRequestWrapper
{
HttpServletRequest
orgRequest
=
null
;
private
Map
<
String
,
String
[]>
parameterMap
;
private
final
byte
[]
body
;
//用于保存读取body中数据
public
XssAndSqlHttpServletRequestWrapper
(
HttpServletRequest
request
)
throws
IOException
{
super
(
request
);
orgRequest
=
request
;
parameterMap
=
request
.
getParameterMap
();
body
=
StreamUtils
.
copyToByteArray
(
request
.
getInputStream
());
}
// 重写几个HttpServletRequestWrapper中的方法
/**
* 获取所有参数名
*
* @return 返回所有参数名
*/
@Override
public
Enumeration
<
String
>
getParameterNames
()
{
Vector
<
String
>
vector
=
new
Vector
<
String
>(
parameterMap
.
keySet
());
return
vector
.
elements
();
}
/**
* 覆盖getParameter方法,将参数名和参数值都做xss & sql过滤。<br/>
* 如果需要获得原始的值,则通过super.getParameterValues(name)来获取<br/>
* getParameterNames,getParameterValues和getParameterMap也可能需要覆盖
*/
@Override
public
String
getParameter
(
String
name
)
{
String
[]
results
=
parameterMap
.
get
(
name
);
if
(
results
==
null
||
results
.
length
<=
0
)
return
null
;
else
{
String
value
=
results
[
0
];
if
(
value
!=
null
)
{
value
=
xssEncode
(
value
);
}
return
value
;
}
}
/**
* 获取指定参数名的所有值的数组,如:checkbox的所有数据 接收数组变量 ,如checkobx类型
*/
@Override
public
String
[]
getParameterValues
(
String
name
)
{
String
[]
results
=
parameterMap
.
get
(
name
);
if
(
results
==
null
||
results
.
length
<=
0
)
return
null
;
else
{
int
length
=
results
.
length
;
for
(
int
i
=
0
;
i
<
length
;
i
++)
{
results
[
i
]
=
xssEncode
(
results
[
i
]);
}
return
results
;
}
}
/**
* 覆盖getHeader方法,将参数名和参数值都做xss & sql过滤。<br/>
* 如果需要获得原始的值,则通过super.getHeaders(name)来获取<br/>
* getHeaderNames 也可能需要覆盖
*/
@Override
public
String
getHeader
(
String
name
)
{
String
value
=
super
.
getHeader
(
xssEncode
(
name
));
if
(
value
!=
null
)
{
value
=
xssEncode
(
value
);
}
return
value
;
}
/**
* 将容易引起xss & sql漏洞的半角字符直接替换成全角字符
*
* @param s
* @return
*/
private
static
String
xssEncode
(
String
s
)
{
if
(
s
==
null
||
s
.
isEmpty
())
{
return
s
;
}
else
{
s
=
stripXSSAndSql
(
s
);
}
StringBuilder
sb
=
new
StringBuilder
(
s
.
length
()
+
16
);
for
(
int
i
=
0
;
i
<
s
.
length
();
i
++)
{
char
c
=
s
.
charAt
(
i
);
switch
(
c
)
{
case
'>'
:
sb
.
append
(
">"
);
// 转义大于号
break
;
case
'<'
:
sb
.
append
(
"<"
);
// 转义小于号
break
;
// case '\'':
// sb.append("'");// 转义单引号
// break;
// case '\"':
// sb.append(""");// 转义双引号
// break;
case
'&'
:
sb
.
append
(
"&"
);
// 转义&
break
;
case
'#'
:
sb
.
append
(
"#"
);
// 转义#
break
;
default
:
sb
.
append
(
c
);
break
;
}
}
return
sb
.
toString
();
}
/**
* 获取最原始的request
*
* @return
*/
public
HttpServletRequest
getOrgRequest
()
{
return
orgRequest
;
}
/**
* 获取最原始的request的静态方法
*
* @return
*/
public
static
HttpServletRequest
getOrgRequest
(
HttpServletRequest
req
)
{
if
(
req
instanceof
XssAndSqlHttpServletRequestWrapper
)
{
return
((
XssAndSqlHttpServletRequestWrapper
)
req
).
getOrgRequest
();
}
return
req
;
}
/**
*
* 防止xss跨脚本攻击(替换,根据实际情况调整)
*/
public
static
String
stripXSSAndSql
(
String
value
)
{
if
(
value
!=
null
)
{
// NOTE: It's highly recommended to use the ESAPI library and
// uncomment the following line to
// avoid encoded attacks.
// value = ESAPI.encoder().canonicalize(value);
// Avoid null characters
/** value = value.replaceAll("", ""); ***/
// Avoid anything between script tags
Pattern
scriptPattern
=
Pattern
.
compile
(
"<[\r\n| | ]*script[\r\n| | ]*>(.*?)</[\r\n| | ]*script[\r\n| | ]*>"
,
Pattern
.
CASE_INSENSITIVE
);
value
=
scriptPattern
.
matcher
(
value
).
replaceAll
(
""
);
// Avoid anything in a
// src="http://www.yihaomen.com/article/java/..." type of
// e-xpression
scriptPattern
=
Pattern
.
compile
(
"src[\r\n| | ]*=[\r\n| | ]*[\\\"|\\\'](.*?)[\\\"|\\\']"
,
Pattern
.
CASE_INSENSITIVE
|
Pattern
.
MULTILINE
|
Pattern
.
DOTALL
);
value
=
scriptPattern
.
matcher
(
value
).
replaceAll
(
""
);
// Remove any lonesome </script> tag
scriptPattern
=
Pattern
.
compile
(
"</[\r\n| | ]*script[\r\n| | ]*>"
,
Pattern
.
CASE_INSENSITIVE
);
value
=
scriptPattern
.
matcher
(
value
).
replaceAll
(
""
);
// Remove any lonesome <script ...> tag
scriptPattern
=
Pattern
.
compile
(
"<[\r\n| | ]*script(.*?)>"
,
Pattern
.
CASE_INSENSITIVE
|
Pattern
.
MULTILINE
|
Pattern
.
DOTALL
);
value
=
scriptPattern
.
matcher
(
value
).
replaceAll
(
""
);
// Avoid eval(...) expressions
scriptPattern
=
Pattern
.
compile
(
"eval\\((.*?)\\)"
,
Pattern
.
CASE_INSENSITIVE
|
Pattern
.
MULTILINE
|
Pattern
.
DOTALL
);
value
=
scriptPattern
.
matcher
(
value
).
replaceAll
(
""
);
// Avoid e-xpression(...) expressions
scriptPattern
=
Pattern
.
compile
(
"e-xpression\\((.*?)\\)"
,
Pattern
.
CASE_INSENSITIVE
|
Pattern
.
MULTILINE
|
Pattern
.
DOTALL
);
value
=
scriptPattern
.
matcher
(
value
).
replaceAll
(
""
);
// Avoid javascript:... expressions
scriptPattern
=
Pattern
.
compile
(
"javascript[\r\n| | ]*:[\r\n| | ]*"
,
Pattern
.
CASE_INSENSITIVE
);
value
=
scriptPattern
.
matcher
(
value
).
replaceAll
(
""
);
// Avoid vbscript:... expressions
scriptPattern
=
Pattern
.
compile
(
"vbscript[\r\n| | ]*:[\r\n| | ]*"
,
Pattern
.
CASE_INSENSITIVE
);
value
=
scriptPattern
.
matcher
(
value
).
replaceAll
(
""
);
// Avoid onload= expressions
scriptPattern
=
Pattern
.
compile
(
"onload(.*?)="
,
Pattern
.
CASE_INSENSITIVE
|
Pattern
.
MULTILINE
|
Pattern
.
DOTALL
);
value
=
scriptPattern
.
matcher
(
value
).
replaceAll
(
""
);
}
return
value
;
}
public
static
boolean
checkSqlInjection
(
Object
obj
){
Pattern
pattern
=
Pattern
.
compile
(
"(.*\\=.*\\-\\-.*)|(.*(\\+|\\-).*)|(.*\\w+(%|\\$|#|&)\\w+.*)|(.*\\|\\|.*)|(.*\\s+(and|or)\\s+.*)"
+
"|(.*\\b(select|update|union|and|or|delete|insert|trancate|char|into|substr|ascii|declare|exec|count|master|into|drop|execute)\\b.*)"
);
Matcher
matcher
=
pattern
.
matcher
(
obj
.
toString
().
toLowerCase
());
return
matcher
.
find
();
}
public
static
boolean
checkXSSAndSql
(
String
value
)
{
boolean
flag
=
false
;
if
(
value
!=
null
)
{
boolean
b
=
checkSqlInjection
(
value
);
if
(
b
)
{
ThreadLocalContextHolder
.
setData
(
"包含SQL注入的参数,请检查参数!"
);
return
true
;
}
// NOTE: It's highly recommended to use the ESAPI library and
// uncomment the following line to
// avoid encoded attacks.
// value = ESAPI.encoder().canonicalize(value);
// Avoid null characters
/** value = value.replaceAll("", ""); ***/
// Avoid anything between script tags
Pattern
scriptPattern
=
Pattern
.
compile
(
"<[\r\n| | ]*script[\r\n| | ]*>(.*?)</[\r\n| | ]*script[\r\n| | ]*>"
,
Pattern
.
CASE_INSENSITIVE
);
flag
=
scriptPattern
.
matcher
(
value
).
find
();
if
(
flag
)
{
// threadLocal.set("包含XSS攻击脚本,请检查参数!");
return
flag
;
}
// Avoid anything in a
// src="http://www.yihaomen.com/article/java/..." type of
// e-xpression
scriptPattern
=
Pattern
.
compile
(
"src[\r\n| | ]*=[\r\n| | ]*[\\\"|\\\'](.*?)[\\\"|\\\']"
,
Pattern
.
CASE_INSENSITIVE
|
Pattern
.
MULTILINE
|
Pattern
.
DOTALL
);
flag
=
scriptPattern
.
matcher
(
value
).
find
();
if
(
flag
)
{
ThreadLocalContextHolder
.
setData
(
"包含XSS攻击脚本,请检查参数!"
);
return
flag
;
}
// Remove any lonesome </script> tag
scriptPattern
=
Pattern
.
compile
(
"</[\r\n| | ]*script[\r\n| | ]*>"
,
Pattern
.
CASE_INSENSITIVE
);
flag
=
scriptPattern
.
matcher
(
value
).
find
();
if
(
flag
)
{
ThreadLocalContextHolder
.
setData
(
"包含XSS攻击脚本,请检查参数!"
);
return
flag
;
}
// Remove any lonesome <script ...> tag
scriptPattern
=
Pattern
.
compile
(
"<[\r\n| | ]*script(.*?)>"
,
Pattern
.
CASE_INSENSITIVE
|
Pattern
.
MULTILINE
|
Pattern
.
DOTALL
);
flag
=
scriptPattern
.
matcher
(
value
).
find
();
if
(
flag
)
{
ThreadLocalContextHolder
.
setData
(
"包含XSS攻击脚本,请检查参数!"
);
return
flag
;
}
// Avoid eval(...) expressions
scriptPattern
=
Pattern
.
compile
(
"eval\\((.*?)\\)"
,
Pattern
.
CASE_INSENSITIVE
|
Pattern
.
MULTILINE
|
Pattern
.
DOTALL
);
flag
=
scriptPattern
.
matcher
(
value
).
find
();
if
(
flag
)
{
ThreadLocalContextHolder
.
setData
(
"包含XSS攻击脚本,请检查参数!"
);
return
flag
;
}
// Avoid e-xpression(...) expressions
scriptPattern
=
Pattern
.
compile
(
"e-xpression\\((.*?)\\)"
,
Pattern
.
CASE_INSENSITIVE
|
Pattern
.
MULTILINE
|
Pattern
.
DOTALL
);
flag
=
scriptPattern
.
matcher
(
value
).
find
();
if
(
flag
)
{
ThreadLocalContextHolder
.
setData
(
"包含XSS攻击脚本,请检查参数!"
);
return
flag
;
}
// Avoid javascript:... expressions
scriptPattern
=
Pattern
.
compile
(
"javascript[\r\n| | ]*:[\r\n| | ]*"
,
Pattern
.
CASE_INSENSITIVE
);
flag
=
scriptPattern
.
matcher
(
value
).
find
();
if
(
flag
)
{
ThreadLocalContextHolder
.
setData
(
"包含XSS攻击脚本,请检查参数!"
);
return
flag
;
}
// Avoid vbscript:... expressions
scriptPattern
=
Pattern
.
compile
(
"vbscript[\r\n| | ]*:[\r\n| | ]*"
,
Pattern
.
CASE_INSENSITIVE
);
flag
=
scriptPattern
.
matcher
(
value
).
find
();
if
(
flag
)
{
ThreadLocalContextHolder
.
setData
(
"包含XSS攻击脚本,请检查参数!"
);
return
flag
;
}
// Avoid onload= expressions
scriptPattern
=
Pattern
.
compile
(
"onload(.*?)="
,
Pattern
.
CASE_INSENSITIVE
|
Pattern
.
MULTILINE
|
Pattern
.
DOTALL
);
flag
=
scriptPattern
.
matcher
(
value
).
find
();
if
(
flag
)
{
ThreadLocalContextHolder
.
setData
(
"包含XSS攻击脚本,请检查参数!"
);
return
flag
;
}
}
return
flag
;
}
public
final
boolean
checkParameter
()
{
Map
<
String
,
String
[]>
submitParams
=
new
HashMap
(
parameterMap
);
Set
<
String
>
submitNames
=
submitParams
.
keySet
();
for
(
String
submitName
:
submitNames
)
{
Object
submitValues
=
submitParams
.
get
(
submitName
);
if
((
submitValues
instanceof
String
))
{
if
(
checkXSSAndSql
((
String
)
submitValues
))
{
return
true
;
}
}
else
if
((
submitValues
instanceof
String
[]))
{
for
(
String
submitValue
:
(
String
[])
submitValues
){
if
(
checkXSSAndSql
(
submitValue
))
{
return
true
;
}
}
}
}
return
false
;
}
@Override
public
BufferedReader
getReader
()
throws
IOException
{
return
new
BufferedReader
(
new
InputStreamReader
(
getInputStream
()));
}
@Override
public
ServletInputStream
getInputStream
()
throws
IOException
{
final
ByteArrayInputStream
bais
=
new
ByteArrayInputStream
(
body
);
return
new
ServletInputStream
()
{
@Override
public
int
read
()
throws
IOException
{
return
bais
.
read
();
}
@Override
public
boolean
isFinished
()
{
// TODO Auto-generated method stub
return
false
;
}
@Override
public
boolean
isReady
()
{
// TODO Auto-generated method stub
return
false
;
}
@Override
public
void
setReadListener
(
ReadListener
arg0
)
{
// TODO Auto-generated method stub
}
};
}
}
backend/src/main/java/io/dataease/config/FilterConfig.java
0 → 100644
浏览文件 @
5e34d52d
package
io
.
dataease
.
config
;
import
io.dataease.commons.filter.SqlFilter
;
import
org.springframework.boot.web.servlet.FilterRegistrationBean
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
@Configuration
public
class
FilterConfig
{
@Bean
public
FilterRegistrationBean
registration
(){
FilterRegistrationBean
filterRegistrationBean
=
new
FilterRegistrationBean
();
filterRegistrationBean
.
setFilter
(
new
SqlFilter
());
//实例化Filter类
filterRegistrationBean
.
addUrlPatterns
(
"/*"
);
//设置匹配模式,这里设置为所有,可以按需求设置为"/hello"等等
filterRegistrationBean
.
setName
(
"SqlFilter"
);
//设置过滤器名称
filterRegistrationBean
.
setOrder
(
1
);
//设置执行顺序
return
filterRegistrationBean
;
}
}
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论