常見Web安全漏洞
1.XSS攻擊
1.1什麼是XSS攻擊手段
XSS攻擊使用Javascript腳本注入進行攻擊例如在提交表單後,展示到另一個頁面,可能會受到XSS腳本注入,讀取本地cookie遠程發送給黑客服務器端。
<script>alert('sss')</script>
<script>window.location.href='http://www.itmayiedu.com';</script>
對應html源代碼: <script>alert('sss')</script>
1.2如何防禦XSS攻擊
將腳本特殊字符,轉換成html源代碼進行展示。
漢子編碼http://www.mytju.com/classcode/tools/encode_gb2312.asp
步驟:編寫過濾器攔截所有getParameter參數,重寫httpservletwrapp方法
將參數特殊字符轉換成html源代碼保存.
// 重寫HttpServletRequestWrapper 防止XSS攻擊
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
private HttpServletRequest request;
/**
* @param request
*/
public XssHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
this.request = request;
}
@Override
public String getParameter(String name) {
// 過濾getParameter參數 檢查是否有特殊字符
String value = super.getParameter(name);
System.out.println("value:" + value);
if (!StringUtils.isEmpty(value)) {
// 將中文轉換爲字符編碼格式,將特殊字符變爲html源代碼保存
value = StringEscapeUtils.escapeHtml(value);
System.out.println("newValue:" + value);
}
return value;
}
}
SpringBoot啓動加上@ServletComponentScan
@SpringBootApplication
@ServletComponentScan
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
2.SQL注入攻擊
2.1什麼是SQL注入
SQL注入:利用現有應用程序,將(惡意)的SQL命令注入到後臺數據庫執行一些惡意的操作。造成SQL注入的原因是因爲程序沒有有效過濾用戶的輸入,使攻擊者成功的向服務器提交惡意的SQL查詢代碼,程序在接收後錯誤的將攻擊者的輸入作爲查詢語句的一部分執行,導致原始的查詢邏輯被改變,額外的執行了攻擊者精心構造的惡意代碼
2.2SQL注入防攻擊手段
不要使用拼接SQL語句方式、最好使用預編譯方式,在mybatis編寫sql語句的時候,最好使用?傳參數方式,不要使用#傳參數,因爲#傳參數方式,可能會受到sql語句攻擊。
演示案例:
http://127.0.0.1:8080/login?userName='liusi'&password='123'
http://127.0.0.1:8080/login?userName='liusi'&password='123' or 1=1
@RestController
public class LoginController {
@Autowired
private UserMapper userMapper;
@RequestMapping("/login")
public String login(UserEntity userEntity) {
System.out.println("賬號密碼信息:userEntity:" + userEntity.toString());
UserEntity login = userMapper.login(userEntity);
return login == null ? "登陸失敗!" : "登陸成功!";
}
}
public interface UserMapper {
@Select(" SELECT * FROM user_info where userName=${userName} and password=${password}")
public UserEntity login(UserEntity userEntity);
}
2.3MyBatis #與?區別
#{}: 解析爲一個 JDBC 預編譯語句(prepared statement)的參數標記符,一個 #{ } 被解析爲一個參數佔位符,可以防止SQL注入問題。
${}: 僅僅爲一個純碎的 string 替換,在動態 SQL 解析階段將會進行變量替換。
3.Http請求防盜鏈
3.1什麼是防盜鏈
比如A網站有一張圖片,被B網站直接通過img標籤屬性引入,直接盜用A網站圖片展示。
3.2如何實現防盜鏈
判斷http請求頭Referer域中的記錄來源的值,如果和當前訪問的域名不一致的情況下,說明該圖片可能被其他服務器盜用。
使用過濾器判斷請求頭Referer記錄請求來源
@WebFilter(filterName = "imgFilter", urlPatterns = "/imgs/*")
public class ImgFilter implements Filter {
@Value("${domain.name}")
private String domainName;
public void init(FilterConfig filterConfig) throws ServletException {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
String referer = req.getHeader("Referer");
if (StringUtils.isEmpty(referer)) {
request.getRequestDispatcher("/imgs/error.png").forward(request, response);
return;
}
String domain = getDomain(referer);
if (!domain.equals(domainName)) {
request.getRequestDispatcher("/imgs/error.png").forward(request, response);
return;
}
chain.doFilter(request, response);
}
/**
* 獲取url對應的域名
*
* @param url
* @return
*/
public String getDomain(String url) {
String result = "";
int j = 0, startIndex = 0, endIndex = 0;
for (int i = 0; i < url.length(); i++) {
if (url.charAt(i) == '/') {
j++;
if (j == 2)
startIndex = i;
else if (j == 3)
endIndex = i;
}
}
result = url.substring(startIndex + 1, endIndex);
return result;
}
public void destroy() {
}
}
注意測試的時候,最好開啓兩個不同的瀏覽器測試,避免圖片緩存的原因
4.CSRF攻擊
4.1CSRF攻擊產生的原因
(Cross Site Request Forgery, 跨站域請求僞造)是一種網絡的攻擊方式,它在 2007 年曾被列爲互聯網 20 大安全隱患之一,也被稱爲“One Click Attack”或者Session Riding,通常縮寫爲CSRF或者XSRF,是一種對網站的惡意利用也就是人們所知道的釣魚網站。儘管聽起來像跨站腳本(XSS),但它與XSS非常不同,並且攻擊方式幾乎相左。XSS利用站點內的信任用戶,而CSRF則通過僞裝來自受信任用戶的請求來利用受信任的網站。與XSS攻擊相比,CSRF攻擊往往不大流行(因此對其進行防範的資源也相當稀少)和難以防範,所以被認爲比XSS更具危險性。
5.API接口冪等性設計
API接口冪等性設計方案
5.1MVCC方案
多版本併發控制,該策略主要使用 update with condition(更新帶條件來防止)來保證多次外部請求調用對系統的影響是一致的。在系統設計的過程中,合理的使用樂觀鎖,通過 version 或者 updateTime(timestamp)等其他條件,來做樂觀鎖的判斷條件,這樣保證更新操作即使在併發的情況下,也不會有太大的問題。例如
select * from tablename where condition=#condition# // 取出要跟新的對象,帶有版本 versoin
update tableName set name=#name#,version=version+1 where version=#version#
在更新的過程中利用 version 來防止,其他操作對對象的併發更新,導致更新丟失。爲了避免失敗,通常需要一定的重試機制。
5.2去重表
在插入數據的時候,插入去重表,利用數據庫的唯一索引特性,保證唯一的邏輯。
5.3悲觀鎖
select for update,整個執行過程中鎖定該訂單對應的記錄。注意:這種在 DB 讀大於寫的情況下儘量少用。
5.4Token機制,防止頁面重複提交
業務要求:頁面的數據只能被點擊提交一次
發生原因:由於重複點擊或者網絡重發,或者 nginx 重發等情況會導致數據被重複提交
解決辦法:
集羣環境:採用 token 加 redis(redis 單線程的,處理需要排隊)
單 JVM 環境:採用 token 加 redis 或 token 加 jvm 內存
處理流程:
數據提交前要向服務的申請 token,token 放到 redis 或 jvm 內存,token 有效時間
提交後後臺校驗 token,同時刪除 token,生成新的 token 返回
token 特點:要申請,一次有效性,可以限流
5.4.1基於Token方式防止API接口冪等
客戶端每次在調用接口的時候,需要在請求頭中,傳遞令牌參數,每次令牌只能用一次。
一旦使用之後,就會被刪除,這樣可以有效防止重複提交。
步驟:
1.生成令牌接口
2. 接口中獲取令牌驗證
生成令牌接口
public class TokenUtils {
private static Map<String, Object> tokenMap = new ConcurrentHashMap<String, Object>();
// 獲取token
public static synchronized String getToken() {
// 1.生成令牌
String token = "token-" + System.currentTimeMillis();
// 2.存入tokenMap
tokenMap.put(token, token);
return token;
}
// 驗證token,並且刪除對應的token
public static Boolean exisToken(String token) {
// 1.從集合中獲取token
Object result = tokenMap.get(token);
if (result == null) {
return false;
}
// 2.刪除對應的token
tokenMap.remove(token);
return true;
}
}
接口中獲取令牌驗證
@RestController
public class OrderController {
@Autowired
private OrderMapper orderMapper;
// 獲取Token
@RequestMapping("/getToken")
public String getToken() {
return TokenUtils.getToken();
}
// 驗證Token
@RequestMapping(value = "/addOrder", produces = "application/json; charset=utf-8")
public String addOrder(@RequestBody OrderEntity orderEntity, HttpServletRequest request) {
String token = request.getHeader("token");
if (StringUtils.isEmpty(token)) {
return "參數錯誤!";
}
if (!TokenUtils.exisToken(token)) {
return "請勿重複提交!";
}
int result = orderMapper.addOrder(orderEntity);
return result > 0 ? "添加成功" : "添加失敗" + "";
}
}
5.5防禦CSRF攻擊手段
使用圖形驗證碼防止機器模擬接口請求攻擊,在調用核心業務接口時,比如支付、下單、等接口,最好使用手機短信驗證驗證或者是人臉識別,防止其他用戶使用Token僞造請求。
6.忘記密碼漏洞
黑客使用抓包工具分析Http請求,在忘記密碼找回時,需要發送一套短信驗證碼,如果驗證碼數字比較短的話,很容易使用暴力破解方式攻擊破。
防禦手段:
忘記密碼驗證碼最好在6-8位。
一旦頻繁調用接口驗證時,應該使用圖形驗證碼攔截,防止機器模擬。
使用黑名單和白名單機制,防禦攻擊
7.上傳文件漏洞
漏洞描述
上傳漏洞這個顧名思義,就是攻擊者通過上傳木馬文件,直接得到WEBSHELL,危害等級超級高,現在的入侵中上傳漏洞也是常見的漏洞。
導致該漏洞的原因在於代碼作者沒有對訪客提交的數據進行檢驗或者過濾不嚴,可以直接提交修改過的數據繞過擴展名的檢驗。
漏洞危害
1)可以得到WEBSHELL
2)上傳木馬文件,可以導致系統癱瘓
8.其他攻擊和漏洞
直接異常信息,會給攻擊者以提示。 可以使用mvc中的工具,把錯誤碼異常等進行封裝。HTML註釋, 會暴露功能,方便攻擊。 上線時去除註釋。
文件上傳, 如果本身功能就是上傳文件去執行,那麼就有可能執行非常危險的命令。 解決方式是,設置文件白名單,限制文件類型,另外還可以重新命名文件,改名爲不可執行的
路徑遍歷, 使用相對路徑來遍歷未開放的目錄。 方式是將JS,CSS部署在獨立的服務器,使用獨立域名。 其他文件不使用靜態URL訪問,動態參數不包含文件路徑信息