WEB服務端安全---注入攻擊

注入攻擊是web領域最爲常見的攻擊方式,其本質是把用戶輸入的數據當作代碼執行,主要緣由是違背了數據與代碼分離原則,其發生的兩個條件:用戶能夠控制數據輸入;代碼拼接了用戶輸入的數據,把數據當作代碼執行了。php

下面是幾種常見注入攻擊及其防護方法:前端

SQL注入及常見攻擊技巧

經典注入  如:

$username = $_POST['username'];
$sql = "select * from usertable where username="."'".$username."'"

正常狀況下用戶輸入 ‘Tom’ ,sql爲mysql

"select * from usertable where username='Tom'";

但若是用戶輸入 」Tom' ; drop table usertable--「,sql以下:web

"select * from usertable where username='Tom';drop table usertable--";

若是咱們的服務端代碼,數據庫權限沒作任何處理,那麼結果傷不起。sql

而且當用戶輸入了能夠致使拼接後sql有語法錯的時候,若是服務器開啓了錯誤顯示,那麼將會是攻擊更加便利容易,由於錯誤信息可能會暴露咱們的數據庫信息或者sql語句的雛形等等。shell

 

 

盲注:

大多數狀況下服務器是關閉錯誤回顯的,沒有提示的狀況下,攻擊者又總結出了盲注:sql注入過程當中,sql語句執行的選擇後,選擇的數據不能回顯到前端頁面。此時,攻擊者須要利用一些方法進行判斷或者嘗試,這個過程稱之爲盲注。數據庫

攻擊者經過真假命題的拼接根據頁面返回狀況判斷sql漏洞是否存在。安全

好比:http://news.com/newsIndo.php?id=1,執行的sql爲 select * from newstable where id =1;服務器

攻擊者先是http://news.com/newsIndo.php?id=1 and 1=2  而後  http://news.com/newsIndo.php?id=1 and 1=1 app

and 1=2 時 一般是空頁面 或者錯誤信息,若是 and 1=1的時候頁面正常返回,就說明,and語句成立,也就說明sql漏洞存在,攻擊者不知道會拼接什麼樣的壞心思...

盲注高級技巧Timing Attack 利用數據庫自身函數的的執行形成的返回變化來判斷漏洞是否存在,好比 MySQL BENCHMARK()函數。

 

數據庫攻擊機巧

常見Payload

SQL注入能夠猜解出數據庫的對應版本,好比下面這段Payload,若是MySQL的版本是4,則會返回true。

http://www.site.com/news.php?id=5 and substring(@@version,1,1)=4

下面這段Payload,則是利用union select來分別確認表名admin是否存在,列名passwd是否存在:

id=5 union all select 1,2,3 from admin

id=5 union all select 1,2,passwd from admin

進一步,想要猜解出username和password具體的值,能夠經過判斷字符的範圍,一步步讀出來。

id=5 and ascii(substring((select concat(username,0x3a,passwd) from users limit 0,1),1,1))>64

這個過程很是的繁瑣,因此很是有必要使用一個自動化工具來幫助完成整個過程。

sqlmap.py就是一個很是好的自動化注入工具。

在注入攻擊的過程當中,經常會用到一些讀寫文件的技巧。好比在MySQL中,就能夠經過LOAD_FILE()讀取系統文件,並經過INTO  DUMPFILE寫入本地文件。固然這要求當前數據庫用戶有讀寫系統相應文件或目錄的權限。

命令執行

在MySQL中,除了能夠經過導出webshell間接地執行命令外,還能夠利用「用戶自定義函數」的技巧,即UDF(user-defined functions)來執行命令。

攻擊存儲過程

一些存儲過程也是對攻擊過程有幫助的,好比:SQL Server 中的xp_cmdshell,注入時能夠利用其執行系統命令。存儲過程本省也可能給存在注入漏洞。

編碼問題

有時候不一樣的字符編碼也可能致使注入漏洞的出現,好比 轉義符 ‘\’ 可能會由於字符編碼的不一樣被省略掉,保證數據庫,操做系統,web應用的字符編碼統一能夠避免此類問題。

 

防護SQL注入

使用預編譯語句

通常來講,防護sql注入的最佳方式就是使用預編譯語句,綁定變量。使用預編譯的sql語句,語句的語義不會發生改變。在sql中變量用?表示,攻擊者沒法改變sql的結構,好比下面PHP綁定變量,使用預編譯語句的示例:

1 $sql = "insert into usertable (username,password,phone) value(?,?,?)";
2 $stmt = $mysqli->prepare($sql); 3 $stmt = bind_parm("sss",$username,$password,$phone); 4 $username = 'Tom'; 5 $password = md5('123456'); 6 $phone = '13510345678'; 7 $stmt->execute();

此時就算攻擊者插入相似於 Tom’ or ''='1的字符串,也只會將其當作username來插入,不會改變語句的執行。

檢查數據類型

對輸入數據的數據類型進行檢查,能夠很大程度上對抗sql注入,好比整形integer,亦或是郵箱,時間日期等特定格式數據。

使用安全函數

使用足夠安全的編碼函數,好比:ESAPI.encoder().encodeForSQL( new OracleCodec(), queryparam );

Codec ORACLE_CODEC = new OracleCodec();
String query = "SELECT user_id FROM user_data WHERE user_name = '" + ESAPI.encoder().encodeForSQL( ORACLE_CODEC , req.getParameter("userID")) + "' and  user_password = '" +  ESAPI.encoder().encodeForSQL( ORACLE_CODE , req.getParameter("pwd")) +"'";

最小權限及關閉錯誤回顯

關閉服務器錯誤回顯,避免數據庫信息的暴露,數據庫使用最小權限原則,避免root等高級帳號在web應用中的直接使用,數據庫帳號不該該有建立自定義函數,操做本地文件等權限。

 

 

XML注入

$doc = new DOMDocument('1.0','utf-8');
$doc -> formatOutput = true; $user = $doc -> createElement('user'); $username = $doc -> createElement('username'); $namevalue = $doc -> createTextNode($_POST['username']); $username -> appendChild($namevalue);//將標籤內容賦給標籤 $user -> appendChild($username); $doc -> appendChild($user); $doc -> save("user.xml");

正常狀況下用戶輸入 Tom將保存下面xml文件

<?xml version="1.0" encoding="utf-8"?>
<user>
    <username>Tom</username>
</user>

可是若是用戶輸入惡意數據

Tom</username></user><user><username>Jack</username></user>

此時xml文件

<?xml version="1.0" encoding="utf-8"?>
<user>
    <username>Tom</username>
</user>
<user>
    <username>Jack</username>
</user>

這就是XML注入。XML注入,能夠對用戶輸入數據中的包含」語言自己的保留字符「行進轉義便可。

 

代碼注入

代碼注入與命令注入都是由一些不安全函數或方法引發的如:eval()

$var = 'varname';
$k = $_GET['tag']; eval("/$var = $k;");

攻擊者能夠經過下面Payload實施代碼注入:

/indexPHP?tag=1;phpinfo()

又好比 system()這個函數,能夠經過代碼注入致使命令注入

$error =system('cat '.$_GET['page_id'],$return_var);
echo $error;

攻擊者經過 index.php?page_id=loquesea;ls利用system函數執行本身想要的系統命令。

 

防護對抗代碼注入,命令注入,須要禁用一些像eval(),system()等能夠執行系統命令的函數,非要用到就須要對用戶輸入的數據作處理,此外PHP中動態include遠程文件,也是能避免就避免。

 

CRLF(\r\n)注入

CRLF實際上是兩個字符\n\r,經常被用做語義之間的分隔符,所以CRLF注入極可能改變原有的語義,以下

$log = fopen("login.log", "w");
$txt = "user login failed for: \n"; fwrite($log, $txt); fclose($log);

正常狀況會記錄以下在login.log日誌文件中,

user login failed for :user1
user login failed for :user2

可是由於沒有對換行 \n作處理,當攻擊者輸入 user2\nuser2 login succeeded for :user2 

日誌中結果就會變爲

user login failed for :user1
user login failed for :user2 user login succeeded for :user2

多了一條僞記錄,user2並無登陸成功。

CRLF注入不只僅能夠log注入,凡是利用CRLF做爲分隔符的地方均可能存在這樣的注入,像是」注入HTTP頭「等。

對抗CRLF注入其實只須要處理好 \r \n這兩個保留字符便可。

 

寫在最後:注入攻擊主要是違背了數據與代碼分離原則致使的,其先決條件是用戶能控制數據輸入,而且代碼拼接了用戶輸入的數據,把數據也打個代碼執行了。因此,防護聽從數據域代碼分離原則,在拼接的地方作好安全檢查和處理就能避免此類問題了。

相關文章
相關標籤/搜索