上一篇文章中弄完了xss過濾器,今天來弄一下防sql注入的過濾器儒喊。為什么呢镣奋?我怎么知道為什么,去問問產(chǎn)品經(jīng)理/客戶吧怀愧∏染保總之,像這種安全性的過濾器芯义,就像一個藤上的葫蘆娃一樣哈垢,一個接著一個的出現(xiàn)。平時沒有啥作用毕贼,但關(guān)鍵時候來個合體温赔,能將邪惡的大魔王擋在門外蛤奢。
現(xiàn)在后端的框架也做了防止sql注入的手段鬼癣,比如使用PreparedStatement+占位符。但加一層過濾器總歸更加安全一點啤贩。這里的防sql注入的過濾器可以對普通get/post請求進(jìn)行參數(shù)過濾待秃,也可以對post+application/json等請求進(jìn)行參數(shù)過濾。該過濾器使用了請求的包裝類痹屹,具體參考我的上一篇文章章郁。
好,現(xiàn)在是代碼時刻志衍,把這個防sql注入過濾器放在xss過濾器之前暖庄。為什么呢?因為xss過濾器會把一些字符進(jìn)行轉(zhuǎn)義楼肪,這個時候如果再進(jìn)行防sql注入的過濾培廓,就會讓該過濾器以為是sql注入的請求,就會報錯春叫。
package cn.wjp.mydaily.common.filter;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import javax.servlet.FilterConfig;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Map;
/**
* 防止SQL注入的攔截器 放在xssFilter之后 xssFilter轉(zhuǎn)義之后的字符會被該過濾器當(dāng)作sql注入
* @author wjp
*
*/
public class SqlInjectFilter implements Filter {
/**
* 需要過濾的sql關(guān)鍵字肩钠,可以手動添加
*/
public static final String BAD_PARAM_STR ="'|and|exec|execute|insert|select|delete|update|count|drop|*|%|chr|mid|master|truncate|" +
"char|declare|sitename|net user|xp_cmdshell|;|or|-|+|,|like'|and|exec|execute|insert|create|drop|" +
"table|from|grant|use|group_concat|column_name|" +
"information_schema.columns|table_schema|union|where|select|delete|update|order|by|count|*|" +
"chr|mid|master|truncate|char|declare|or|;|-|--|+|,|like|//|/|%|#";
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request =(HttpServletRequest)req;
HttpServletResponse response =(HttpServletResponse)res;
String contentType = request.getContentType();//獲取contentType請求頭
String method = request.getMethod();//獲取請求方法 post/get
//1 處理get請求 get請求的Content-Type一般為application/x-www-form-urlencoded 或者 text/html
if(method.trim().equalsIgnoreCase(HttpConst.GET_METHOD)){
if(isValidParamForGet(request)){
chain.doFilter(request, response);
return;
}else {
response.sendError(403,"發(fā)送的參數(shù)可能會引起sql注入,系統(tǒng)拒絕服務(wù)暂殖!");
return;
}
}
//2 處理post請求 只處理application/x-www-form-urlencoded application/json,對于multipart/form-data价匠,直接放行
if(method.trim().equalsIgnoreCase(HttpConst.POST_METHOD)){
if(contentType.trim().toLowerCase().contains(HttpConst.MULTIPART_CONTENT_TYPE)){
chain.doFilter(request, response);
return;
}
//處理application/x-www-form-urlencoded
if(contentType.trim().toLowerCase().contains(HttpConst.FORM_URLENCODED_CONTENT_TYPE)){
if(isValidParamForPost(request)){
chain.doFilter(request, response);
return;
}else {
response.sendError(403,"發(fā)送的參數(shù)可能會引起sql注入,系統(tǒng)拒絕服務(wù)呛每!");
return;
}
}
//處理application/json
if(contentType.trim().toLowerCase().contains(HttpConst.JSON_CONTENT_TYPE)){
HttpServletRequestBodyReaderWrapper wrapperRequest = new HttpServletRequestBodyReaderWrapper(request);
String body = wrapperRequest.getBody();
if(isValidParamForJsonPost(body)){
chain.doFilter(wrapperRequest, response);
return;
}else {
response.sendError(403,"發(fā)送的參數(shù)可能會引起sql注入踩窖,系統(tǒng)拒絕服務(wù)!");
return;
}
}
}
chain.doFilter(request, response);
return;
}
//sql注入效驗
protected static boolean isSqlValidate(String str) {
if(str==null||str.trim().isEmpty()){
return true;
}
str = str.toLowerCase();//統(tǒng)一轉(zhuǎn)為小寫
String[] badStrs = BAD_PARAM_STR.split("\\|");
for (int i = 0; i < badStrs.length; i++) {
if (Pattern.matches("^"+badStrs[i]+"$",str)) {
return false;
}
}
return true;
}
/**
* get請求的參數(shù)是否無害 無害:true 有害:false
* @param request
* @return
*/
public boolean isValidParamForGet(HttpServletRequest request){
Enumeration params = request.getParameterNames();//獲得所有請求參數(shù)名
System.out.println("SqlInjectFilter:發(fā)送的請求參數(shù)值串:"+params);
while (params.hasMoreElements()) {
String name = params.nextElement().toString(); //得到參數(shù)名
String[] value = request.getParameterValues(name);//得到參數(shù)對應(yīng)值
if(!isSqlValidate(name)){
return false;
}
for (int i = 0; i < value.length; i++) {
if(!isSqlValidate(value[i])){
return false;
}
}
}
return true;
}
/**
* post請求的參數(shù)是否無害 無害:true 有害:false
* @param request
* @return
*/
public boolean isValidParamForPost(HttpServletRequest request){
return isValidParamForGet(request);
}
/**
* post請求的參數(shù)是否無害 無害:true 有害:false
* @param body 請求體
* @return
*/
public boolean isValidParamForJsonPost(String body){
System.out.println("SqlInjectFilter:發(fā)送的請求參數(shù)值串:"+body);
if(body==null||body.trim().isEmpty()||body.trim().equalsIgnoreCase("{}")||!body.trim().contains(":")){
return true;
}
Map<String,Object> map = JSON.parseObject(body,new TypeReference<Map<String,Object>>(){});
if(map==null||map.size()==0){
return true;
}
for (Map.Entry<String,Object> entry : map.entrySet()) {
String key = entry.getKey();
if(!isSqlValidate(key)){
return false;
}
Object value = entry.getValue();
String valueStr = String.valueOf(value);
if(valueStr==null||valueStr.trim().isEmpty()||valueStr.trim().equalsIgnoreCase("null")){
valueStr = null;
}
if(!isSqlValidate(valueStr)){
return false;
}
}
return true;
}
@Override
public void destroy() {
}
@Override
public void init(FilterConfig arg0) {
}
}
烏拉拉晨横,這樣就寫完了洋腮。好廉沮,打完收工。旁邊的前端妹子向我投來羨慕的眼神徐矩,我心里好亂滞时,難道我的代碼注釋寫的很好嘛,可我覺得一般吧滤灯。算了坪稽,不要在意這些細(xì)節(jié),我還是去搭地鐵吧鳞骤。