我在開發中常忽視的安全問題

前言

  前不久,開發的任務告一段落。後來得知項目中bug比較多,需要去逐一檢查修復,苦於沒有專業的測試工程師,只好硬着頭皮上(覺得能學到很多東西),也學會了一些安全測試常用軟件基本操作,比如Burpsuite、sqlmap等。今天做一些總結吧,以此提醒日後的開發過程中不僅要考慮代碼的質量規範等問題,還要注意儘量減少安全問題的出現,以往只是埋頭開發,並不太關注安全問題。所以這次對我來說收穫不小!

 


 

一、SQL注入

  Sql注入(SQL injection)是指攻擊者在服務器端構造數據庫執行代碼可以在服務器中數據庫得到執行。由於攻擊代碼在數據庫中執行,根據連接用戶的權限,可以讀、修改數據庫資料甚至執行數據庫外部命令,典型的攻擊方法爲竊取數據庫資料、控制操作系統等。

  使用sqlmap可對url進行SQL注入掃描,進而能攻破DB,獲取表信息等,是十分需要我們開發者關注的問題,但是已經有很多手段能防止SQL注入,最簡單的就是使用Mybatis持久框架,同時摒棄聲明式註解SQL拼接:比如@Select等註解中的SQL語句可能需要拼接,推薦使用XML編寫SQL,儘量使用#{}參數傳入,而不是${}傳入

解決辦法:

  1、增加全局防注入功能,從客戶端獲取到的參數都必須通過安全校驗,防範以下常見攻擊字符:

 

  '|"|>|..|and|exec|insert|select|delete|update|count|*|%|chr|mid|master|truncate|char|declare|script|frame|;|or|-|+|,|)|etc|style|expression

 

  注:對獲取的參數進行安全檢測之前應首先統一字符編碼和大小寫,避免攻擊者通過編碼和大小寫混用繞過安全檢查。

  2、摒棄SQL動態拼接的查詢方式,使用參數化查詢

  3、採用Mybatis等持久化框架官方推薦的SQL方式進行SQL編寫查詢

 

二、XSS漏洞

  與SQL注入類似,SQL注入是注入可執行的SQL代碼到數據庫服務端,而XSS簡單來說就是注入可執行的具有危害的腳本代碼,具體來說:跨站腳本(Cross-site Scripting簡稱XSS)是指攻擊者輸入攻擊代碼到服務器端,代碼在其它用戶的瀏覽器中得到執行。由於攻擊代碼在受害者的瀏覽器中執行,可以讀、修改和傳輸任何瀏覽器可以讀取的資料,典型的攻擊方法爲竊取Cookie、網頁重定向等。

  往往在頁面的一些輸入框:

  

  或者Url中增加後綴或者改寫參數爲xss腳本代碼,如:xxx/name=Lijian&id=123"()%26%25<acx><ScRiPt%20>alert('xss')</ScRiPt>

  

 

  xxx/serviceid=1%22%3e%3cscript%3ealert(1)%3c%2fscript%3e

  

  採取措施:

  1、增加全局防護功能,從客戶端獲取到的參數都必須通過安全校驗,防範常見攻擊字符:注:對獲取的參數進行安全檢測之前應首先統一字符編碼和大小寫,避免攻擊者通過編碼和大小寫混用繞過安全檢查。

  2、將獲取到的數據進行HTML轉碼再存入數據庫或輸出。

  3、通過提高Seesion、Cookie等安全(設置HttpOnly,Secure等屬性)

三、傳輸安全

1、關於Cookie安全:

  1) 加密會話(SSL)缺少HttpOnly屬性

  有效防止客戶端腳本,比如JS腳本獲取Cookie信息並且發送到指定站點提供黑客使用。準確來說是防止非HTTP協議程序接口獲取Cookie(Java後端可以獲取Cookies,前端通過Ajax獲取)

  Java語言設置httpOnly

response.setHeader("Set-Cookie", "cookiename=value;Path=/;Domain=domainvalue;Max-Age=seconds;HTTPOnly");

  2) 加密會話(SSL)缺少Secure屬性

  如果設置了Secure=true,那麼這個cookie只能依靠https協議發送,不能使用http協議。即此時的Cookie是在https時被創建的,如果改爲http頁面則無法使用Cookie,通常結合httpOnly一起配置使用提高Cookie安全

  3) 防Cookie僞造

  傳統的Cookie(name, value)形式,網上流傳的是將value值加上保存時間savaTime、自定義密鑰、簽名等方式

  4) 儘量不要存放敏感信息

  不要在Cookie中放userInf等信息,比如手機號碼,郵箱等,即使放也要加密!

2、關於密碼加密:

  除了規定高強度的複雜性外,還不能只是簡單的MD5加密,網上有很多的MD5解密網站可進行破解

四、敏感信息傳輸

1、Html或者JS代碼不要存在敏感重要的信息

  衆所周知,前端代碼不存在加密,大部分都是可見的,所以在前端開發過程中儘量不要留一些隱私敏感信息,比如測試時候用來測試預留的銀行卡號等信息應該刪除

  至少在前端展示的時候用“●●●●”或者“****”代替,而不是直接顯示在前端!

  如敏感信息App Secret Key

  

  前端中:

  

  而不是:

  

2、除了密碼不要明文傳輸,用戶名視情況而進行加密

  當然像一些手機號碼也需要加解密,比如替換中間的幾位數,對中間幾位數進行加密隱藏等!

3、敏感信息儘量不要放在session中,即使放也要加密

  對Session的key值儘量不要使用簡單的userId等,可以再加UUID,或者SessionId

五、暴力破解

1、用戶名的枚舉

常見登錄頁面,當輸入用戶名之後(還未輸入密碼進行登錄)可能會返回“用戶名不存在”的提示,這樣的提示可能會讓黑客進行大量的用戶枚舉破解用戶名。我們應該統一返回“用戶名或密碼錯誤”的提示,混淆防止黑客對用戶名進行暴力破解。

2、關鍵信息輸入未設置錯誤次數可能會被暴力破解

如常見的密碼輸入,用戶輸入的次數超過一定數量後對用戶進行暫時鎖定或者強制修改密碼等;手機驗證碼輸入次數達到上限後,同樣進行鎖定(時間鎖定/操作鎖定)

3、篡改返回數據包,可繞過驗證碼

當然登錄頁面還會密碼還有驗證碼等的校驗,比如註冊/登錄頁面中往往最後有個輸入(手機)驗證碼的文本框,

   

 

  像我這樣的新手每次都會行雲流水,忘情地寫代碼,自我感覺棒棒噠:嗯…..用戶輸入驗證碼之後我們後端要驗證驗證碼是否正確,我要開發一個checkVeriCode驗證驗證碼是否正確的接口,emmmm……..正確就返回true,錯誤就返回false。然後返回true之後,就可以繼續調我們的/login登錄接口,或者註冊/register接口,So easy!超簡單(無比膨脹)。

  面對自己的ignorance,我只想說:千萬不要單獨開發驗證驗證碼是否正確的接口,進行調用!千萬不要單獨開發驗證驗證碼是否正確的接口,進行調用!千萬不要單獨開發驗證驗證碼是否正確的接口,進行調用!最好就使用一個接口(login接口或者register接口中)將驗證驗證碼環節放到其中,點擊註冊/登錄按鈕之後調用登錄/註冊接口,先進行驗證碼的校驗,正確則直接進入登錄/註冊保存,錯誤則提示驗證碼失敗。簡單來說我們打開F12開發者模式,只能看到一個接口,而不會出現checkVeriCode接口與/login(/register)兩個接口,前一個接口影響後一個接口。

  總結起來就是我們在開發埋頭苦幹忘我地編寫代碼的時候,量減少“多接口強耦合”開發,即後一個接口會受前一個接口返回包影響(這種影響往往是比較重要的),而前一個接口返回包往往很容易被篡改(你說還有比true/fasle更容易被篡改的嘛?)

  Request:輸入錯誤的驗證碼----->調用checkVeriCode--------請求我不攔截你放你走

  Response:checkVeriCode接口返回false----->站住你別走,我要攔截你,把你打(改)成true---->好了,你可以走了--->驗證碼輸入正確---->成功破解登錄/註冊

  我們使用Burpsuite中我們截取校驗驗證碼接口,輸入錯誤的驗證碼123456

  

  返回false數據包,沒有任何問題。這是正確的

  

  下面我們篡改false爲true之後返回到客戶端,即可繞過驗證碼環節

  

4、郵箱/短信轟炸

  這種郵件/短信轟炸是比較好理解的,黑客獲取到相關的接口之後進行返回調用,進而對指定手機號碼/郵箱進行轟炸,嚴重的話郵箱服務器等困難會崩潰。

  那麼此時我們簡單的就認爲那還不簡單,對同一個手機號碼/郵件進行次數限定不就完了?真的是這樣就可以了嗎?當時我一開始的時候也是這麼想的!當時我想的最簡單的做法就是:在規定T時間內每次對同一個手機號碼發送驗證碼後,存入Redis中的次數(有效期T)加1,達到一定數目後,進行“操作頻繁提示”。

  但其實我們還忽略了另外一個問題,如果攻擊者使用同一IP不同手機號碼進行攻擊,他的目標不再是轟炸手機,而是讓服務器崩潰,那麼我們仍然要對同一個IP進行次數限制。需要注意的是對方可能使用的是代理IP,我們還需要檢測真實IP,網上有很多檢測是否是代理IP,獲取真實IP的方法,簡單的判斷:HTTP頭部X-Forward-For第一個IP就是我們的真實IP。

六、服務器泄露

1、 服務器版本泄露

  這個我們通常負載均衡使用Nginx服務器,有時候錯誤輸入URL可能會跳轉到Nginx的錯誤頁面顯示404,此時會顯示一個Nginx的版本號,或者歡迎頁面

解決辦法:

  1)去除歡迎頁面

  找到index.html歡迎頁面,註釋html代碼即可。

[open@dcspap01 ~]$ cd /usr/local/nginx/html

 

  2)去除版本號:

  第一步:修改nginx.conf,http中增加:server_tokens off

[open@dcspap01 ~]$ cd /home/open
[open@dcspap01 ~]$ vi nginx.conf

  第二步:編輯fastcgi.conf文件,找到fastcgi_param SERVER SOFTWARE 去掉後面的參數$nginx_version,即隱藏nginx版本號

[open@dcspap01 ~]$ cd /usr/local/nginx
[open@dcspap01 ~]$ vi fastcgi.conf

 

  第三步:重啓nginx,需要root用戶登錄

[open@dcspap01 ~]$ cd /usr/local/nginx/
[open@dcspap01 ~]$ ./nginx -s reload

2、點擊劫持漏洞

  HTTP 響應頭信息中的X-Frame-Options,可以指示瀏覽器是否應該加載一個 iframe 中的頁面如果服務器響應頭信息中沒有X-Frame-Options,則該網站存在點擊劫持攻擊風險。

修改web服務器配置,添加X-Frame-Options響應頭。賦值有如下三種:

  • DENY:不能被嵌入到任何iframe或者frame中。
  • SAMEORIGIN:頁面只能被本站頁面嵌入到iframe或者frame中。
  • ALLOW-FROM url:只能被嵌入到指定域名url的框架中。

解決辦法

  Java代碼:

  response.addHeader("x-frame-options","SAMEORIGIN");

  Nginx配置:(添加到 'http', 'server' 或者 'location' 的配置中:)

  add_header X-Frame-Options SAMEORIGIN

  Apache配置:

  Header always append X-Frame-Options SAMEORIGIN

3、 謹慎啓用OPTIONS

  OPTIONS方法請求web服務器告知其支持的各種功能。可以詢問服務器通常支持哪些方法,或者對某些特殊資源支持哪些方法。如果單獨再詳細瞭解OPTIONS的話估計又得一大篇了,搜所以這麼簡單的總結下:

  OPTIONS通常存在於前後端分離的跨域請求中:瀏覽器自發起一次preflight request(預檢請求),以檢測實際請求是否安全,這也是黑客通常針對的點,那麼我們後端需要做什麼呢,就需要做一些簡單的跨域設置,允許部分的HTTP METHOD

response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, OPTIONS");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
response.addHeader("Access-Control-Max-Age", "1800");

  啓用OPTIONS請求後,返回Allow頭,表明後端服務器支持的HTTP方法,有些方法DELETE、HEAD等方法是沒必要或者不安全的,需要禁止,同時如果服務器不需要支持WebDAV,請務必禁用它,或禁止不必要的HTTP方法!

  

 


 

總結

  1)我不是專業的安全測試,所以提到的問題可能不是很完善,解決辦法也可能不是很好,我相信肯定有很多的更好的解決辦法;

  2)在這裏我只是想提醒作爲菜鳥開發的話不僅要關注代碼質量,對代碼負責。還要對安全問題負責,我認爲這纔是好的(禿頭)程序猿應該全方位考慮到的;

  3)“不光還要懂開發懂代碼,還要全局掌握一些知識”這是我對自己的要求,這些問題看似簡單但據我經歷來看,很多開發者都會忽視(我爲什麼還要懂安全問題,我又不是測試)。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章