1. XSS跨站腳本攻擊
① XSS漏洞介紹
跨站腳本攻擊XSS是指攻擊者往Web頁面裡插入惡意Script代碼,當使用者浏覽該頁之時,嵌入其中Web裡面的Script代碼會被解析執行,進而達到惡意攻擊使用者的目的。XSS攻擊針對的是使用者層面的攻擊!
② XSS漏洞分類
存儲型XSS: 存儲型XSS,持久化,代碼是存儲在伺服器中的,如在個人資訊或發表文章等地方,插入代碼,如果沒有過濾或過濾不嚴,那麼這些代碼将儲存到伺服器中,使用者通路該頁面的時候觸發代碼執行。這種XSS比較危險,容易造成蠕蟲,盜竊cookie
反射型XSS: 非持久化,需要欺騙使用者自己去點選連結才能觸發XSS代碼(伺服器中沒有這樣的頁面和内容),一般容易出現在搜尋頁面
DOM型XSS: 不經過後端,DOM-XSS漏洞是基于文檔對象模型(Document Objeet Model,DOM)的一種漏洞,DOM-XSS是通過url傳入參數去控制觸發的,其實也屬于反射型XSS。
③ 防護建議
- 限制使用者輸入,表單資料規定值得類型,例如年齡隻能是int,name為字母數字組合。
- 對資料進行html encode處理。
- 過濾或移除特殊的html标簽。
- 過濾javascript事件的标簽。
2. SQL注入攻擊
① SQL注入漏洞介紹
SQL注入(SQLi)是一種注入攻擊,可以執行惡意SQL語句。它通過将任意SQL代碼插入資料庫查詢,使攻擊者能夠完全控制Web應用程式後面的資料庫伺服器。攻擊者可以使用SQL注入漏洞繞過應用程式安全措施;可以繞過網頁或Web應用程式的身份驗證和授權,并檢索整個SQL資料庫的内容;還可以使用SQL注入來添加,修改和删除資料庫中的記錄;關注公衆号:碼猿技術專欄,回複關鍵詞:1111 擷取阿裡内部Java性能優化手冊!
SQL注入漏洞可能會影響使用SQL資料庫(如MySQL,Oracle,SQL Server或其他)的任何網站或Web應用程式。犯罪分子可能會利用它來未經授權通路使用者的敏感資料:客戶資訊,個人資料,商業機密,知識産權等。SQL注入攻擊是最古老,最流行,最危險的Web應用程式漏洞之一。
②防護建議
使用mybatis中#{}可以有效防止sql注入。
使用#{}時:
<select id="getBlogById" resultType="Blog" parameterType=”int”>
select id,title,author,content
from blog where id=#{id}
</select>
列印出執行的sql語句,會看到sql是這樣的:
select id,title,author,content from blog where id = ?
不管輸入什麼參數,列印出的sql都是這樣的。這是因為mybatis啟用了預編譯功能,在sql執行前,會先将上面的sql發送給資料庫進行編譯,執行時,直接使用編譯好的sql,替換占位符“?”就可以了。因為sql注入隻能對編譯過程起作用,是以像#{}這樣預編譯成?的方式就很好地避免了sql注入的問題。
mybatis是如何做到sql預編譯的呢?
其實在架構底層,是jdbc中的PreparedStatement類在起作用,PreparedStatement是我們很熟悉的Statement的子類,它的對象包含了編譯好的sql語句。這種“準備好”的方式不僅能提高安全性,而且在多次執行一個sql時,能夠提高效率,原因是sql已編譯好,再次執行時無需再編譯。
使用${}時
<select id="orderBlog" resultType="Blog" parameterType=”map”>
select id,title,author,content
from blog order by ${orderParam}
</select>
仔細觀察,内聯參數的格式由“#{xxx}”變為了${xxx}。如果我們給參數“orderParam”指派為”id”,将sql列印出來,是這樣的:
select id,title,author,contet from blog order by id
顯然,這樣是無法阻止sql注入的,參數會直接參與sql編譯,進而不能避免注入攻擊。但涉及到動态表名和列名時,隻能使用“${}”這樣的參數格式,是以,這樣的參數需要我們在代碼中手工進行處理來防止注入。
其實,這些都在Java面試庫小程式上都有答案,如果你近期準備面試跳槽,建議在上面刷題,涵蓋 2000+ 道 Java 面試題,幾乎覆寫了所有主流技術面試題。
3. SpringBoot中如何防止XSS攻擊和sql注入
對于Xss攻擊和Sql注入,我們可以通過過濾器來搞定,可根據業務需要排除部分請求
① 建立Xss請求過濾類XssHttpServletRequestWraper
代碼如下:
public class XssHttpServletRequestWraper extends HttpServletRequestWrapper {
Logger log = LoggerFactory.getLogger(this.getClass());
public XssHttpServletRequestWraper() {
super(null);
}
public XssHttpServletRequestWraper(HttpServletRequest httpservletrequest) {
super(httpservletrequest);
}
//過濾springmvc中的 @RequestParam 注解中的參數
public String[] getParameterValues(String s) {
String str[] = super.getParameterValues(s);
if (str == null) {
return null;
}
int i = str.length;
String as1[] = new String[i];
for (int j = 0; j < i; j++) {
//System.out.println("getParameterValues:"+str[j]);
as1[j] = cleanXSS(cleanSQLInject(str[j]));
}
log.info("XssHttpServletRequestWraper淨化後的請求為:==========" + as1);
return as1;
}
//過濾request.getParameter的參數
public String getParameter(String s) {
String s1 = super.getParameter(s);
if (s1 == null) {
return null;
} else {
String s2 = cleanXSS(cleanSQLInject(s1));
log.info("XssHttpServletRequestWraper淨化後的請求為:==========" + s2);
return s2;
}
}
//過濾請求體 json 格式的
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream bais = new ByteArrayInputStream(inputHandlers(super.getInputStream ()).getBytes ());
return new ServletInputStream() {
@Override
public int read() throws IOException {
return bais.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) { }
};
}
public String inputHandlers(ServletInputStream servletInputStream){
StringBuilder sb = new StringBuilder();
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(servletInputStream, Charset.forName("UTF-8")));
String line = "";
while ((line = reader.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (servletInputStream != null) {
try {
servletInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return cleanXSS(sb.toString ());
}
public String cleanXSS(String src) {
String temp = src;
src = src.replaceAll("<", "<").replaceAll(">", ">");
src = src.replaceAll("\\(", "(").replaceAll("\\)", ")");
src = src.replaceAll("'", "'");
src = src.replaceAll(";", ";");
//bgh 2018/05/30 新增
/**-----------------------start--------------------------*/
src = src.replaceAll("<", "& lt;").replaceAll(">", "& gt;");
src = src.replaceAll("\\(", "& #40;").replaceAll("\\)", "& #41");
src = src.replaceAll("eval\\((.*)\\)", "");
src = src.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"");
src = src.replaceAll("script", "");
src = src.replaceAll("link", "");
src = src.replaceAll("frame", "");
/**-----------------------end--------------------------*/
Pattern pattern = Pattern.compile("(eval\\((.*)\\)|script)",
Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(src);
src = matcher.replaceAll("");
pattern = Pattern.compile("[\\\"\\'][\\s]*javascript:(.*)[\\\"\\']",
Pattern.CASE_INSENSITIVE);
matcher = pattern.matcher(src);
src = matcher.replaceAll("\"\"");
// 增加腳本
src = src.replaceAll("script", "").replaceAll(";", "")
/*.replaceAll("\"", "").replaceAll("@", "")*/
.replaceAll("0x0d", "").replaceAll("0x0a", "");
if (!temp.equals(src)) {
// System.out.println("輸入資訊存在xss攻擊!");
// System.out.println("原始輸入資訊-->" + temp);
// System.out.println("處理後資訊-->" + src);
log.error("xss攻擊檢查:參數含有非法攻擊字元,已禁止繼續通路!!");
log.error("原始輸入資訊-->" + temp);
throw new CustomerException("xss攻擊檢查:參數含有非法攻擊字元,已禁止繼續通路!!");
}
return src;
}
//輸出
public void outputMsgByOutputStream(HttpServletResponse response, String msg) throws IOException {
ServletOutputStream outputStream = response.getOutputStream(); //擷取輸出流
response.setHeader("content-type", "text/html;charset=UTF-8"); //通過設定響應頭控制浏覽器以UTF-8的編碼顯示資料,如果不加這句話,那麼浏覽器顯示的将是亂碼
byte[] dataByteArr = msg.getBytes("UTF-8");// 将字元轉換成位元組數組,指定以UTF-8編碼進行轉換
outputStream.write(dataByteArr);// 使用OutputStream流向用戶端輸出位元組數組
}
// 需要增加通配,過濾大小寫組合
public String cleanSQLInject(String src) {
String lowSrc = src.toLowerCase();
String temp = src;
String lowSrcAfter = lowSrc.replaceAll("insert", "forbidI")
.replaceAll("select", "forbidS")
.replaceAll("update", "forbidU")
.replaceAll("delete", "forbidD").replaceAll("and", "forbidA")
.replaceAll("or", "forbidO");
if (!lowSrcAfter.equals(lowSrc)) {
log.error("sql注入檢查:輸入資訊存在SQL攻擊!");
log.error("原始輸入資訊-->" + temp);
log.error("處理後資訊-->" + lowSrc);
throw new CustomerException("sql注入檢查:參數含有非法攻擊字元,已禁止繼續通路!!");
}
return src;
}
}
② 把請求過濾類XssHttpServletRequestWraper添加到Filter中,注入容器
@Component
public class XssFilter implements Filter {
Logger log = LoggerFactory.getLogger(this.getClass());
// 忽略權限檢查的url位址
private final String[] excludeUrls = new String[]{
"null"
};
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) arg0;
HttpServletResponse response = (HttpServletResponse) arg1;
String pathInfo = req.getPathInfo() == null ? "" : req.getPathInfo();
//擷取請求url的後兩層
String url = req.getServletPath() + pathInfo;
//擷取請求你ip後的全部路徑
String uri = req.getRequestURI();
//注入xss過濾器執行個體
XssHttpServletRequestWraper reqW = new XssHttpServletRequestWraper(req);
//過濾掉不需要的Xss校驗的位址
for (String str : excludeUrls) {
if (uri.indexOf(str) >= 0) {
arg2.doFilter(arg0, response);
return;
}
}
//過濾
arg2.doFilter(reqW, response);
}
public void destroy() {
}
public void init(FilterConfig filterconfig1) throws ServletException {
}
}
上述代碼已經可以完成 請求參數、JSON請求體 的過濾,但對于json請求體還有其他的方式實作,有興趣的請看下面的擴充!
擴充:還可以重寫spring中的MappingJackson2HttpMessageConverter來過濾Json請求體
因為請求體在進出Contoroller時,會經過MappingJackson2HttpMessageConverter的一個轉換,把請求體轉換成我們需要的json格式,是以可以在這裡邊做一些修改!
@Configuration
public class MyConfiguration {
@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(){
//自定義轉換器
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
//轉換器日期格式設定
ObjectMapper objectMapper = new ObjectMapper();
SimpleDateFormat smt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
objectMapper.setDateFormat(smt);
converter.setObjectMapper(objectMapper);
//轉換器添加自定義Module擴充,主要是在這裡做XSS過濾的!!,其他的是其他業務,不用看
SimpleModule simpleModule = new SimpleModule();
//添加過濾邏輯類!
simpleModule.addDeserializer(String.class,new StringDeserializer());
converter.getObjectMapper().registerModule(simpleModule);
//設定中文編碼格式
List<MediaType> list = new ArrayList<>();
list.add(MediaType.APPLICATION_JSON_UTF8);
converter.setSupportedMediaTypes(list);
return converter;
}
}
真正的過濾邏輯類StringDeserializer:
//檢驗請求體的參數
@Component
public class StringDeserializer extends JsonDeserializer<String> {
@Override
public String deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
String str = jsonParser.getText().trim();
//sql注入攔截
if (sqlInject(str)) {
throw new CustomerException("參數含有非法攻擊字元,已禁止繼續通路!");
}
return xssClean(str);
}
public boolean sqlInject(String str) {
if (StringUtils.isEmpty(str)) {
return false;
}
//去掉'|"|;|\字元
str = org.apache.commons.lang3.StringUtils.replace(str, "'", "");
str = org.apache.commons.lang3.StringUtils.replace(str, "\"", "");
str = org.apache.commons.lang3.StringUtils.replace(str, ";", "");
str = org.apache.commons.lang3.StringUtils.replace(str, "\\", "");
//轉換成小寫
str = str.toLowerCase();
//非法字元
String[] keywords = {"master", "truncate", "insert", "select", "delete", "update", "declare", "alert","alter", "drop"};
//判斷是否包含非法字元
for (String keyword : keywords) {
if (str.indexOf(keyword) != -1) {
return true;
}
}
return false;
}
//xss攻擊攔截
public String xssClean(String value) {
if (value == null || "".equals(value)) {
return value;
}
//非法字元
String[] keywords = {"<", ">", "<>", "()", ")", "(", "javascript:", "script","alter", "''","'"};
//判斷是否包含非法字元
for (String keyword : keywords) {
if (value.indexOf(keyword) != -1) {
throw new CustomerException("參數含有非法攻擊字元,已禁止繼續通路!");
}
}
return value;
}
}
使用這種形式也可以完成json請求體的過濾,但個人更推薦使用XssHttpServletRequestWraper的形式來完成xss過濾!!
最後說一句(别白嫖,求關注)
每一篇文章都是精心輸出,如果這篇文章對你有所幫助,或者有所啟發的話,幫忙點贊、關注、轉發,你的支援就是我堅持下去的最大動力!