springboot-防止sql注入,xss攻擊,cros惡意訪問
springboot-防止sql注入,xss攻擊,cros惡意訪問
文章目錄
完整程式碼下載連結:
https://github.com/2010yhh/springBoot-demos.git
環境
idea2018,jdk1.8,
springboot版本:springboot1.5.9.RELEASE
1.sql注入
sql注入:
把SQL命令插入到Web表單遞交或輸入域名或頁面請求的查詢字串,最終達到欺騙伺服器執行惡意的SQL命令
解決方法:
1)無論是直接使用資料庫還是使用如mybatis元件,使用sql的預編譯,不要用拼接字串。
2)後臺過濾檢測:使用正則表示式過濾傳入的引數**;**.字串過濾
3)前端檢測sql常見關鍵字,如or and drop之類的
測試:
1.sql直接拼接,訪問:http://localhost:8180/webapp2/testSql1?userName=1&passWord=1 or 1=1
實際執行sql:sql1:select user_name,pass_word from cas_user where user_name= '1' and pass_word=1 INVALID 1=1
結果:輸入錯誤資訊也能查詢
2.sql預編譯(其他mybais元件類似),訪問:http://localhost:8180/webapp2/testSql2?userName=1&passWord=1 or 1=1
實際執行sql:sql2:select user_name,pass_word from cas_user where user_name= '1' and pass_word= '1 INVALID 1=1'
結果:
2種不同的sql寫法:
3.程式碼中增加了過濾器檢測表單輸入後,sql關鍵欄位會被過濾掉;訪問:http://localhost:8180/webapp2/testSql2?userName=1&passWord=1 or 1=1
結果:非法輸入被過濾器過濾掉了(或者替換了)
2.xss攻擊
xss攻擊:
其原理是攻擊者向有XSS漏洞的網站中輸入(傳入)惡意的HTML程式碼,當其它使用者瀏覽該網站時,這段HTML程式碼會自動執行,從而達到攻擊的目的。如,盜取使用者Cookie、破壞頁面結構、重定向到其它網站等
解決方法:對使用者輸入的表單資訊進行檢測過濾
測試:訪問:http://localhost:8180/webapp2/testXss?userName=1&passWord=
結果:非法輸入被過濾器過濾掉了
3.csrf/cros
關於csrf/cros攻擊的詳細介紹:
https://www.cnblogs.com/lailailai/p/4528092.html
關於跨域的詳細介紹:
https://www.cnblogs.com/keyi/p/6726089.html
CSRF - Cross-Site Request Forgery - 跨站請求偽造:
攻擊可以在受害者毫不知情的情況下以受害者名義偽造請求傳送給受攻擊站點,從而在未授權的情況下執行在許可權保護之下的操作
CORS - Cross Origin Resourse-Sharing - 跨站資源共享:
惡意訪問內網敏感資源
解決方法:
有效的解決辦法是通過多種條件遮蔽掉非法的請求,例如HTTP頭、引數等
1、不信任未經身份驗證的跨域請求,應該首先驗證Session ID或者Cookie。
2、對於請求方來說驗證接收的資料有效性,服務方僅暴露最少最必須的功能。
3、通過多種條件遮蔽掉非法的請求,例如HTTP頭、引數等。
服務端程式碼跨域設定,設定了nginx轉發,也可設定在nginx中:
4.服務端程式碼處理,以springboot為例:
可利用過濾器進行設定,如下所示:
@WebFilter public class CrosXssFilter implements Filter { private static final Logger logger = LoggerFactory.getLogger(CrosXssFilter.class); @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { request.setCharacterEncoding("utf-8"); response.setContentType("text/html;charset=utf-8"); //跨域設定 if(response instanceof HttpServletResponse){ HttpServletResponse httpServletResponse=(HttpServletResponse)response; //通過在響應 header 中設定 ‘*’ 來允許來自所有域的跨域請求訪問。 httpServletResponse.setHeader("Access-Control-Allow-Origin", "*"); //通過對 Credentials 引數的設定,就可以保持跨域 Ajax 時的 Cookie //設定了Allow-Credentials,Allow-Origin就不能為*,需要指明具體的url域 //httpServletResponse.setHeader("Access-Control-Allow-Credentials", "true"); //請求方式 httpServletResponse.setHeader("Access-Control-Allow-Methods", "*"); //(預檢請求)的返回結果(即 Access-Control-Allow-Methods 和Access-Control-Allow-Headers 提供的資訊) 可以被快取多久 httpServletResponse.setHeader("Access-Control-Max-Age", "86400"); //首部欄位用於預檢請求的響應。其指明瞭實際請求中允許攜帶的首部欄位 httpServletResponse.setHeader("Access-Control-Allow-Headers", "*"); } //sql,xss過濾 HttpServletRequest httpServletRequest=(HttpServletRequest)request; logger.info("CrosXssFilter.......orignal url:{},ParameterMap:{}",httpServletRequest.getRequestURI(), JSONObject.toJSONString(httpServletRequest.getParameterMap())); XssHttpServletRequestWrapper xssHttpServletRequestWrapper=new XssHttpServletRequestWrapper( httpServletRequest); chain.doFilter(xssHttpServletRequestWrapper, response); logger.info("CrosXssFilter..........doFilter url:{},ParameterMap:{}",xssHttpServletRequestWrapper.getRequestURI(), JSONObject.toJSONString(xssHttpServletRequestWrapper.getParameterMap())); } @Override public void destroy() { } }
XssHttpServletRequestWrapper類:
/**
* 防止sql注入,xss攻擊
* 前端可以對輸入資訊做預處理,後端也可以做處理。
*/
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
private final Logger log = LoggerFactory.getLogger(getClass());
private static String key = "and|exec|insert|select|delete|update|count|*|%|chr|mid|master|truncate|char|declare|;|or|-|+";
private static Set<String> notAllowedKeyWords = new HashSet<String>(0);
private static String replacedString="INVALID";
static {
String keyStr[] = key.split("\\|");
for (String str : keyStr) {
notAllowedKeyWords.add(str);
}
}
private String currentUrl;
public XssHttpServletRequestWrapper(HttpServletRequest servletRequest) {
super(servletRequest);
currentUrl = servletRequest.getRequestURI();
}
/**覆蓋getParameter方法,將引數名和引數值都做xss過濾。
* 如果需要獲得原始的值,則通過super.getParameterValues(name)來獲取
* getParameterNames,getParameterValues和getParameterMap也可能需要覆蓋
*/
@Override
public String getParameter(String parameter) {
String value = super.getParameter(parameter);
if (value == null) {
return null;
}
return cleanXSS(value);
}
@Override
public String[] getParameterValues(String parameter) {
String[] values = super.getParameterValues(parameter);
if (values == null) {
return null;
}
int count = values.length;
String[] encodedValues = new String[count];
for (int i = 0; i < count; i++) {
encodedValues[i] = cleanXSS(values[i]);
}
return encodedValues;
}
@Override
public Map<String, String[]> getParameterMap(){
Map<String, String[]> values=super.getParameterMap();
if (values == null) {
return null;
}
Map<String, String[]> result=new HashMap<>();
for(String key:values.keySet()){
String encodedKey=cleanXSS(key);
int count=values.get(key).length;
String[] encodedValues = new String[count];
for (int i = 0; i < count; i++){
encodedValues[i]=cleanXSS(values.get(key)[i]);
}
result.put(encodedKey,encodedValues);
}
return result;
}
/**
* 覆蓋getHeader方法,將引數名和引數值都做xss過濾。
* 如果需要獲得原始的值,則通過super.getHeaders(name)來獲取
* getHeaderNames 也可能需要覆蓋
*/
@Override
public String getHeader(String name) {
String value = super.getHeader(name);
if (value == null) {
return null;
}
return cleanXSS(value);
}
private String cleanXSS(String valueP) {
// You'll need to remove the spaces from the html entities below
String value = valueP.replaceAll("<", "<").replaceAll(">", ">");
value = value.replaceAll("<", "& lt;").replaceAll(">", "& gt;");
value = value.replaceAll("\\(", "& #40;").replaceAll("\\)", "& #41;");
value = value.replaceAll("'", "& #39;");
value = value.replaceAll("eval\\((.*)\\)", "");
value = value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"");
value = value.replaceAll("script", "");
value = cleanSqlKeyWords(value);
return value;
}
private String cleanSqlKeyWords(String value) {
String paramValue = value;
for (String keyword : notAllowedKeyWords) {
if (paramValue.length() > keyword.length() + 4
&& (paramValue.contains(" "+keyword)||paramValue.contains(keyword+" ")||paramValue.contains(" "+keyword+" "))) {
paramValue = StringUtils.replace(paramValue, keyword, replacedString);
log.error(this.currentUrl + "已被過濾,因為引數中包含不允許sql的關鍵詞(" + keyword
+ ")"+";引數:"+value+";過濾後的引數:"+paramValue);
}
}
return paramValue;
}
}