Java项目如何防止SQL注入
SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。
SQL案列
String sql = "delete from table1 where id = "
+ "
id"
;
这个id从请求参数中获取,若参数被拼接为:
1001 or 1 = 1
最执行语句变为:
String sql = "delete from table1 where id = 1001 or 1 = 1"
;
此时,数据库的数据都会被清空掉,后果非常严重
二、Java项目防止SQL注入方式这里总结4种:
PreparedStatement防止SQL注入
mybatis中#{}防止SQL注入
对请求参数的敏感词汇进行过滤
nginx反向代理防止SQL注入
PreparedStatement具有预编译功能,以上述SQL为例
使用PreparedStatement预编译后的SQL为:
delete from table1 where id= ?此时SQL语句结构已固定,无论"
?"
被替换为任何参数,SQL语句只认为where后面只有一个条件,当再传入 1001 or 1 = 1时,语句会报错,从而达到防止SQL注入效果
mybatis中#{}表达式防止SQL注入与PreparedStatement类似,都是对SQL语句进行预编译处理
注意:
#{} :参数占位符
${} :拼接替换符,不能防止SQL注入,一般用于
传入数据库对象(如:数据库名称、表名)
order by 后的条件
这里是springboot的写法,如下:
import org.springframework.context.annotation.Configuration;import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
import java.util.Enumeration;
/**
* @Auther: 睡竹
* @Date: 2023/03/07
* @Description: sql防注入过滤器
*/
@WebFilter(urlPatterns = "
/*"
,filterName = "
sqlFilter"
)
@Configuration
public class SqlFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
/**
* @description sql注入过滤
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
ServletRequest request = servletRequest;
ServletResponse response = servletResponse;
// 获得所有请求参数名
Enumeration<
String>
names = request.getParameterNames();
String sql = "
"
;
while (names.hasMoreElements()){
// 得到参数名
String name = names.nextElement().toString();
// 得到参数对应值
String[] values = request.getParameterValues(name);
for (int i = 0;
i <
values.length;
i++) {
sql += values[i];
}
}
if (sqlValidate(sql)) {
//TODO 这里直接抛异常处理,前后端交互项目中,请把错误信息按前后端"
数据返回的VO"
对象进行封装
throw new IOException("
您发送请求中的参数中含有非法字符"
);
} else {
filterChain.doFilter(request,response);
}
}
/**
* @description 匹配效验
*/
protected static boolean sqlValidate(String str){
// 统一转为小写
String s = str.toLowerCase();
// 过滤掉的sql关键字,特殊字符前面需要加\\进行转义
String badStr =
"
select|update|and|or|delete|insert|truncate|char|into|substr|ascii|declare|exec|count|master|into|drop|execute|table|"
+
"
char|declare|sitename|xp_cmdshell|like|from|grant|use|group_concat|column_name|"
+
"
information_schema.columns|table_schema|union|where|order|by|"
+
"
'
\\*|\\;
|\\-|\\--|\\+|\\,|\\//|\\/|\\%|\\#"
;
//使用正则表达式进行匹配
boolean matches = s.matches(badStr);
return matches;
}
@Override
public void destroy() {}
} 4、nginx反向代理防止SQL注入
越来越多网站使用nginx进行反向代理,该层我们也可以进行防止SQL注入配置。
将下面的Nginx配置文件代码放入到server块中,然后重启Nginx即可
if ($request_method !~* GET|POST) { return 444;}
#使用444错误代码可以更加减轻服务器负载压力。
#防止SQL注入
if ($query_string ~* (\$|'
|--|[+|(%20)]union[+|(%20)]|[+|(%20)]insert[+|(%20)]|[+|(%20)]drop[+|(%20)]|[+|(%20)]truncate[+|(%20)]|[+|(%20)]update[+|(%20)]|[+|(%20)]from[+|(%20)]|[+|(%20)]grant[+|(%20)]|[+|(%20)]exec[+|(%20)]|[+|(%20)]where[+|(%20)]|[+|(%20)]select[+|(%20)]|[+|(%20)]and[+|(%20)]|[+|(%20)]or[+|(%20)]|[+|(%20)]count[+|(%20)]|[+|(%20)]exec[+|(%20)]|[+|(%20)]chr[+|(%20)]|[+|(%20)]mid[+|(%20)]|[+|(%20)]like[+|(%20)]|[+|(%20)]iframe[+|(%20)]|[\<
|%3c]script[\>
|%3e]|javascript|alert|webscan|dbappsecurity|style|confirm\(|innerhtml|innertext)(.*)$) { return 555;
}
if ($uri ~* (/~).*) { return 501;
}
if ($uri ~* (\\x.)) { return 501;
}
#防止SQL注入
if ($query_string ~* "
[;
'
<
>
].*"
) { return 509;
}
if ($request_uri ~ "
"
) { return 509;
}
if ($request_uri ~ (\/\.+)) { return 509;
}
if ($request_uri ~ (\.+\/)) { return 509;
}
#if ($uri ~* (insert|select|delete|update|count|master|truncate|declare|exec|\*|\'
)(.*)$ ) { return 503;
}
#防止SQL注入
if ($request_uri ~* "
(cost\()|(concat\()"
) { return 504;
}
if ($request_uri ~* "
[+|(%20)]union[+|(%20)]"
) { return 504;
}
if ($request_uri ~* "
[+|(%20)]and[+|(%20)]"
) { return 504;
}
if ($request_uri ~* "
[+|(%20)]select[+|(%20)]"
) { return 504;
}
if ($request_uri ~* "
[+|(%20)]or[+|(%20)]"
) { return 504;
}
if ($request_uri ~* "
[+|(%20)]delete[+|(%20)]"
) { return 504;
}
if ($request_uri ~* "
[+|(%20)]update[+|(%20)]"
) { return 504;
}
if ($request_uri ~* "
[+|(%20)]insert[+|(%20)]"
) { return 504;
}
if ($query_string ~ "
(<
|%3C).*script.*(>
|%3E)"
) { return 505;
}
if ($query_string ~ "
GLOBALS(=|\[|\%[0-9A-Z]{0,2})"
) { return 505;
}
if ($query_string ~ "
_REQUEST(=|\[|\%[0-9A-Z]{0,2})"
) { return 505;
}
if ($query_string ~ "
proc/self/environ"
) { return 505;
}
if ($query_string ~ "
mosConfig_[a-zA-Z_]{1,21}(=|\%3D)"
) { return 505;
}
if ($query_string ~ "
base64_(en|de)code\(.*\)"
) { return 505;
}
if ($query_string ~ "
[a-zA-Z0-9_]=http://"
) { return 506;
}
if ($query_string ~ "
[a-zA-Z0-9_]=(\.\.//?)+"
) { return 506;
}
if ($query_string ~ "
[a-zA-Z0-9_]=/([a-z0-9_.]//?)+"
) { return 506;
}
if ($query_string ~ "
b(ultram|unicauca|valium|viagra|vicodin|xanax|ypxaieo)b"
) { return 507;
}
if ($query_string ~ "
b(erections|hoodia|huronriveracres|impotence|levitra|libido)b"
) {return 507;
}
if ($query_string ~ "
b(ambien|bluespill|cialis|cocaine|ejaculation|erectile)b"
) { return 507;
}
if ($query_string ~ "
b(lipitor|phentermin|pro[sz]ac|sandyauer|tramadol|troyhamby)b"
) { return 507;
}
#这里大家根据自己情况添加删减上述判断参数,cURL、wget这类的屏蔽有点儿极端了,但要“宁可错杀一千,不可放过一个”。
if ($http_user_agent ~* YisouSpider|ApacheBench|WebBench|Jmeter|JoeDog|Havij|GetRight|TurnitinBot|GrabNet|masscan|mail2000|github|wget|curl|Java|python) { return 508;
}
#同上,大家根据自己站点实际情况来添加删减下面的屏蔽拦截参数。
if ($http_user_agent ~* "
Go-Ahead-Got-It"
) { return 508;
}
if ($http_user_agent ~* "
GetWeb!"
) { return 508;
}
if ($http_user_agent ~* "
Go!Zilla"
) { return 508;
}
if ($http_user_agent ~* "
Download Demon"
) { return 508;
}
if ($http_user_agent ~* "
Indy Library"
) { return 508;
}
if ($http_user_agent ~* "
libwww-perl"
) { return 508;
}
if ($http_user_agent ~* "
Nmap Scripting Engine"
) { return 508;
}
if ($http_user_agent ~* "
~17ce.com"
) { return 508;
}
if ($http_user_agent ~* "
WebBench*"
) { return 508;
}
if ($http_user_agent ~* "
spider"
) { return 508;
} #这个会影响国内某些搜索引擎爬虫,比如:搜狗
#拦截各恶意请求的UA,可以通过分析站点日志文件或者waf日志作为参考配置。
if ($http_referer ~* 17ce.com) { return 509;
}
#拦截17ce.com站点测速节点的请求,所以明月一直都说这些测速网站的数据仅供参考不能当真的。
if ($http_referer ~* WebBench*"
) { return 509;
}
#拦截WebBench或者类似压力测试工具,其他工具只需要更换名称即可。
随着互联网技术的发展,防止SQL注入攻击已经成为了Java项目开发中的一个重要问题。SQL注入攻击可以让攻击者获得数据或用户信息。这篇文章将介绍如何防止SQL注入攻击的几种有效实践方式。
1. 使用参数
SQL语句中使用参数,而不是直接将用户输入的数据插入到SQL语句中。使用参数可以防止攻击者使用特殊字符或命令注入到SQL语句中。
2. 防止动态SQL拼接
动态SQL拼接将输入的数据和SQL语句拼接起来,从而构成一个新的SQL语句。攻击者可以利用这个方式构造恶意SQL语句。防止动态SQL拼接应该使用预处理语句。
3. 使用存储过程
存储过程可以有效地防止SQL注入攻击。存储过程是在数据库中预先定义和编译的SQL语句。存储过程需要传递参数来进行操作,而参数可以有效地防止SQL注入攻击。
4. 过滤输入
在用户输入时进行过滤操作,限制输入的数据只允许包含必要的字符和数字。例如,限制用户输入的内容只能是英文字母、数字和一些常见的特殊字符。
5. 使用安全验证
在应用程序和数据库之间添加安全验证层,可以有效地防止SQL注入攻击。例如,使用OAuth2等安全验证方式。
6. 禁止数据库访问
禁止应用程序中所有直接访问数据库的方法,只能通过接口访问。这样可以有效地将接口与数据库分离,从而增强系统的安全性。
7. 审计数据
将应用程序中所有的SQL查询都记录下来,每次查询都要记录查询的条件、执行的时间、查询结果等信息。这样可以让开发人员及时发现SQL注入攻击。
总之,防范SQL注入攻击的方法有很多,但上面所提到的几个方法为最常见的方式。在项目开发过程中,开发人员必须重视这一问题,设计连接数据库的方案时也应考虑到安全性。这样才能确保Java项目的安全性,增强系统的稳定性,降低风险。