從php角度分析預防xss和Sql注入

引言 從php角度分析預防xss和Sql注入,是因爲php對這方面做了很好的支持。

XSS

概念: Xss即跨站腳本攻擊,指攻擊者在網頁中嵌入惡意腳本程序(一般由html,css,js組成),當用戶打開網頁的時候腳本程序便在客戶端執行而產生若干危害的情況。XSS的重點不在於跨站點,而是在於惡意腳本的執行。
一般是攻擊者利用網站對用戶提交數據沒有過濾或者過濾不足的缺點,進而添加一些代碼,嵌入到web頁面中去,使別的用戶訪問都會執行相應的嵌入代碼。

分類 部分參考百度百科
XSS漏洞按照攻擊利用手法的不同,暫且分爲三類: 反射型XSS(非持久型)、存儲型XSS(持久型)和DOM XSS。

類型A:利用本地漏洞,這種漏洞存在於頁面中客戶端腳本自身。其攻擊過程如下所示:

-Charly給Alice發送一個惡意構造的Web URL。

  • Alice點擊並查看了這個URL。
  • 惡意頁面中的JavaScript打開一個具有漏洞的HTML頁面並將其下載到Bob電腦上。
  • 具有漏洞的HTML頁面包含了在Alice電腦本地域執行的JavaScript。
  • Charly的惡意腳本可以在Alice的電腦上執行Alice所持有的權限下的命令。

類型B:反射式漏洞,這種漏洞和類型A有些類似,不同的是Web客戶端使用Server端腳本生成頁面爲用戶提供數據時,如果未經驗證的用戶數據被包含在頁面中而未經HTML實體編碼,客戶端代碼便能夠注入到動態頁面中,具體實例參考文章,其攻擊過程如下:

  • Alice經常瀏覽某個網站,此網站爲Bob所擁有。Bob的站點運行Alice使用用戶名/密碼進行登錄,並存儲敏感信息(比如銀行帳戶信息)。
  • Charly發現Bob的站點存在反射性的XSS漏洞。
  • Charly編寫一個利用漏洞的URL,並將其冒充爲來自Bob的郵件發送給Alice。
  • Alice在登錄到Bob的站點後,瀏覽Charly提供的URL,即點擊郵件。
  • 嵌入到URL中的惡意腳本在Alice的瀏覽器中執行,就像它直接來自Bob的服務器一樣。此腳本盜竊敏感信息(授權、信用卡、帳號信息等),然後在Alice完全不知情的情況下將這些信息發送到Charly的Web站點。

反射式XSS 一般是攻擊者通過特定手法(如電子郵件),誘使用戶去訪問一個包含惡意代碼的 URL,當受害者點擊這些專門設計的鏈接的時候,惡意代碼會直接在受害者主機上的瀏覽器執行。
對於訪問者而言是一次性的,具體表現在我們把我們的惡意腳本通過 URL 的方式傳遞給了服務器,而服務器則只是不加處理的把腳本“反射”回訪問者的瀏覽器而使訪問者的瀏覽器執行相應的腳本。反射型 XSS 的觸發有後端的參與,要避免反射性 XSS,必須需要後端的協調,後端解析前端的數據時首先做相關的字串檢測和轉義處理。

類型C:存儲式漏洞,該類型是應用最爲廣泛而且有可能影響到Web服務器自身安全的漏洞,駭客將攻擊腳本上傳到Web服務器上,使得所有訪問該頁面的用戶都面臨信息泄漏的可能,其中也包括了Web服務器的管理員,具體實例參考文章。其攻擊過程如下

  • Bob擁有一個Web站點,該站點允許用戶發佈信息/瀏覽已發佈的信息。
  • Charly注意到Bob的站點具有類型C的XSS漏洞。
  • Charly發佈一個熱點信息到留言板,吸引其它用戶紛紛閱讀。
  • Bob或者是任何的其他人如Alice瀏覽該信息,其會話cookies或者其它信息將被Charly盜走。

存儲型 XSS一般是攻擊者事先將惡意代碼上傳或儲存到漏洞服務器中,只要受害者瀏覽包含此惡意代碼的頁面就會執行惡意代碼。這就意味着只要訪問了這個頁面的訪客,都有可能會執行這段惡意腳本,因此儲存型XSS的危害會更大。存儲型 XSS 一般出現在網站留言、評論、博客日誌等交互處,惡意腳本存儲到客戶端或者服務端的數據庫中。

類型D:DOM XSS和反射型XSS、存儲型XSS的差別在於DOM XSS的代碼並不需要服務器參與,觸發XSS靠的是瀏覽器端的DOM解析,完全是客戶端的事情,簡單地說就是通過修改頁面的DOM節點形成的XSS,產生的根源是因爲不安全的引用和通過服務器提供的頁面使用不受約束的DOM對象,具體參考文章1文章2。其過程如下:

  • Bob擁有一個Web站點,並且站點有很多用戶,如Alice。
  • Charly注意到Bob的站點具有DOM XSS,構造一個該站點具有DOM XSS的正常URL併發送給Alice等用戶。
  • Alice點擊該URL發生XSS。

DOM XSS發生的前提是易受攻擊的網站有一個HTML頁面採用不安全的方式(沒有經過過濾)從document.location 或document.URL 或 document.referrer獲取數據(或者任何其他攻擊者可以修改的對象),即客戶端的腳本程序可以動態地檢查和修改頁面內容,而不依賴於服務器端的數據。例如客戶端如從 URL 中提取數據並在本地執行,如果用戶在客戶端輸入的數據包含了惡意的 JavaScript 腳本,而這些腳本沒有經過適當的過濾和消毒,那麼應用程序就可能受到 DOM-based XSS 攻擊。需要特別注意以下的用戶輸入源document.location、 document.URL、 location.hash、 location.search、 document.referrer 等。

危害:
1、惡作劇,即單純使客戶端顯示異常信息;

2、盜取用戶信息,簡單的如用戶cookie,還可以獲取用戶各類信息,如機器登錄帳號、用戶網銀帳號、各類管理員帳號,比如2011年6月新浪微博XSS受攻擊事件。

3、獲取各類賬號後就可以控制企業數據,包括讀取、篡改、添加、刪除企業敏感數據的能力,盜竊企業重要的具有商業價值的資料,非法轉賬等;

4、強制用戶賬號做不願做的事情,如發送電子郵件,轉發消息等;

5、控制受害者機器向其它網站發起攻擊,即DDos攻擊,比如3DM(一個遊戲網站)也曾經被植入script代碼對另一個遊戲網站進行了慘無人道的DDOS攻擊;

6、誘惑用戶訪問釣魚網站等;

7、網頁掛馬,即使用戶本地下載執行病毒及木馬程序。

解決方案 究其發生根本,是網站對用戶輸入數據過濾不足,因此網站開發者要始終把Web安全放在心上,簡單點,就是認爲用戶提價的數據都是不可信的,對其進行合適的過濾處理,使用php過濾函數就可以達到很好的目的。
在說解決方法前,還要了解HTML字符實體的概念,具體參考文章
前面講到對用戶數據進行過濾,過濾也分很多種,比如轉義、刪除關鍵字(詞)等。

過濾方針:

1、將重要的cookie標記爲http only, 這樣的話Javascript 中的document.cookie語句就不能獲取到cookie了;

2、表單數據規定值的類型,進行正則等驗證,例如:年齡應爲只能爲int、密碼只能爲n位的字母數字組合等;

4、對數據進行Html Encode 處理;

5、過濾或移除特殊的Html標籤, 例如: <script>、 <iframe> 、<p>、<input>;

6、過濾JavaScript 事件的標籤。例如 “οnclick=”, “onfocus” 等等。

【特別注意】
在有些應用中是允許html標籤出現的,甚至是javascript代碼出現。因此我們在過濾數據的時候需要仔細分析哪些數據是有特殊要求(例如輸出需要html代碼、javascript代碼拼接、或者此表單直接允許使用等等),然後區別處理!

Sql注入

概念: 如果說Xss是用戶輸入的惡意腳本在客戶端執行,那SQL注入,就是用戶把SQL命令插入到Web表單遞交或輸入域名或頁面請求的查詢字符串,最終達到欺騙服務器執行惡意的SQL命令。所以再次強調我們永遠不要信任用戶的輸入,我們必須認定用戶輸入的數據都是不安全的,我們都需要對用戶輸入的數據進行過濾處理。
SQL注入之所以存在,主要是因爲工程師將外部的輸入直接嵌入到將要執行的SQL語句中了。黑客可以利用這一點執行SQL指令來達到自己目的。
幸運的是,如果你在使用MySQL 的話,mysql_query() 函數不允許查詢堆積(query stacking),或者說在一次函數調用中執行多次 SQL 查詢。如果你試圖進行堆積式查詢的話,函數調用將會失敗。
然而,其他的 PHP 數據庫擴展,例如 SQLite 和 PostgreSQL 會愉快地接受堆積式查詢,執行字符串中所有的查詢,並由此產生嚴重的安全問題。,具體參考PHP官方文檔Sql注入,這裏主要講Mysql。

例如:

$db = new \PDO('mysql:host=localhost;port=3306;dbname=**', 'root', '***');  
$pdostatement=$db->query('select * from fpf_user where id ='.$id );	       	
$list=$pdostatement->fetchall();
dump($list);

這裏用用戶輸入的變量$id來拼接SQL語句,存在安全隱患。如果$id = ‘2 or 1=1’,這裏就能輕鬆的獲取到user表的所有信息。
利用SQL注入漏洞,我們能夠獲取想要的信息,同時可以通過猜測和報錯獲取到數據庫其它表的結構和信息,如果數據庫、服務器權限設置不當,甚至有可能能獲取到整個服務器的控制權限。 這些攻擊總是建立在發掘安全意識不強的代碼上的。所以,永遠不要信任外界輸入的數據,特別是來自於客戶端的,包括選擇框、表單隱藏域和 cookie。

解決方案
從產生sql注入的原因說起,就是攻擊者嵌入的惡意sql語句被服務器執行了,所以要解決它,就是防止任何可能的惡意sql被服務器執行。

1.永遠不要使用超級用戶或所有者帳號去連接數據庫。要用權限被嚴格限制的帳號。
2.寫一個ORM(Object Relational Mapping,實現面向對象編程語言裏不同類型系統的數據之間的轉換),這樣可以避免直接拼接SQL 語句,相對安全而且能大大提高開發效率.補充 ORM並不能防止sql注入,而是爲防止sql注入提供了便利的方法,當下的php框架都在ORM中做了防止sql注入的處理,如TP,Laravel;

3.如果非得寫一些原生的SQL拼接語句,則我們必須對輸入的那些變量進行優化過濾;

  • 檢查輸入的數據是否具有所期望的數據格式。PHP 有很多可以用於檢查輸入的函數,從簡單的變量函數和字符類型函數(比如 is_numeric(),ctype_digit())到複雜的 Perl 兼容正則表達式函數都可以完成這個工作;
  • 如果查詢的字段類型是數字等類型,在拼接SQL前先使用 is_numeric() 來檢查輸入是不是一個合法的數字,不合法則終止程序即可,或者直接使用 settype() 來轉換它的類型,也可以用 sprintf() 把它格式化爲數字,如$id=intval($_GET[‘id’]);
  • 如果字段類型是字符串,則記得將輸入裏的的單引號進行轉義,如$id=addslashes($_GET[‘id’])。

注意: addslashes()函數將 轉換爲 \’ 的轉義字符使sql語句成功執行,但 \’ 並未作爲數據存入數據庫,依舊存 ',比如對snow”’‘sun,數據庫保存的是snow”’‘sun 而並不是我們想象的snow’’’'sun,所以不需要stripslashes進行反轉義,順便看看PHP防SQL注入不要再用addslashes和mysql_real_escape_string了

另外,php的mysql或mysqli擴展中的mysql_real_escape_string和mysqli_real_escape_string函數對數據庫查詢字段過濾,即轉義一些預定義字符(NUL (ASCII 0),\n,\r,\,’," 和 Control-Z)。不過php的mysql擴展在php5.5.0中已經棄用,並在php7.0.0中刪除。

當然,pdo也有其防注入措施,最經典的是quote方法,它爲輸入的字符串添加引號(如果有需要),並對特殊字符進行轉義,且引號的風格和底層驅動適配。如果使用此函數構建 SQL 語句,強烈建議使用 prepare() 配合參數構建,而不是用 PDO::quote() 把用戶輸入的數據拼接進 SQL 語句。 使用 prepare處理參數,不僅僅可移植性更好,而且更方便、免疫 SQL 注入;相對於拼接 SQL 更快,客戶端和服務器都能緩存編譯後的 SQL 查詢。但不是所有的 PDO 驅動都實現了此功能(例如 PDO_ODBC),此時考慮使用 prepare 代替,可參考文章sql參數化防注入

還有較爲重要的一點就是攻擊者利用改變注入語句的編碼來繞過轉義的方法,比如將SQL語句轉成 ASCII編碼(類似:char(100,58,92,108,111,99,97,108,104,111,115,116…) 這樣的格式,或者轉成 16進制編碼,甚至還有其他形式的編碼,這樣以來,轉義過濾便被繞過去了,具體參考文章

4.like,regexp 困境

要破解 LIKE 困境,必須有一種專門的轉義機制,將用戶提供的 ‘%’ 和 ‘_’ 轉換爲字面值。爲此你可以使用 addcslashes() 函數,該函數允許指定要進行轉義的字符的範圍。對於REGEXP 困境,同樣如此處理。

$sub = addcslashes("%str_", "%_");  //轉義後 $sub == \%str\_
$db = new \PDO('mysql:host=localhost;port=3306;dbname=**', 'root', '***');  
$pdostatement=$db->mysql_query("select * from messages where subject like '{$sub}%'") ;     	

5.也可以用str_replace以及各種php字符替換函數來防注入,不過這種“黑名單”式的防禦已經被證明是經不起時間考驗的,但也是可以用的。

特別聲明:不要爲了安全濫用這些轉義函數什麼的,重複利用反而會出一些問題,因此要謹慎選擇

php過濾函數

strip_tags($str, [允許標籤]) #從字符串中去除 HTML 和 PHP 標記

htmlentities($str)函數 #轉義html實體

html_entity_decode($str)函數 #反轉義html實體

htmlspecialchars() #特殊字符轉換爲HTML實體

htmlspecialchars_decode() #將特殊的 HTML 實體轉換回普通字符

addcslashes($str, ‘字符’)函數 #給指定字符加上反斜槓

stripcslashes($str)函數 #去掉反斜槓

addslashes ($str )函數 #給預定義符號(單引號、雙引號、反斜線與 NULL)加反斜槓

stripslashes($str)函數 #去掉反斜槓

對於addslashes函數有些文章可能說php開啓魔術引號magic_quotes_gpc,參考文章。但是自從php5.4.0後,魔術引號功能已經移除,官方解釋如下:
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

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