2012年3月2日 星期五

(轉) Web安全筆記 (1~7) (由淺入深)

1.web應用程序改採用的防衛機制的幾個核心構成:
1、處理用戶對應用程序的數據和功能的訪問,以防止用戶未經授權訪問。
2、處理用戶的輸入,以防止惡意的輸入導致未預期的行為。
3、處理攻擊,以確保應用程序在被直接攻擊時作出恰當的行為,如採取適當的防禦和進攻性措施,以挫敗攻擊。
4、通過使管理員能夠監控應用程序的活動和配置應用程序的功能來管理應用程序本身。

1.1處理用戶訪問

大多數web應用程序都使用下面的三重相關的安全機制來處理訪問:
1、驗證
2、會話管理
3、訪問控制

驗證
驗證機制在一個應用程序的用戶訪問處理中是一個最基本的部分。驗證就是確定該用戶的有效性。大多數的web應用程序都採用常規的驗證模型,即用戶提交一個用戶名和密碼,應用程序檢查它的有效性。在安全性很重要的應用程序中,如在線銀行,這個基本的驗證模型常增加額外的證書和多級登錄過程。在安全性要求更高的時候,其它的一些驗證模型可以被用,如客戶端證書,智能卡或挑戰/應答(challenge-response) tokens。

challenge-response tokens的過程:
用戶要求登錄時,系統產生一個隨機數字串發送給用戶。用戶將這個串輸入到token設備中,token設備將這個串與用戶的秘密口令按特定的算法進行運算並產生一個回應串發送給系統,系統用同樣的算法做驗算即可驗證用戶身份。

除了核心的登錄過程外,驗證機制也常採用其它的一些輔助功能,如自註冊(self-registration,比如註冊後通過郵件中的鏈接激活帳戶),帳戶恢復以及密碼更改功能。儘管驗證機製表面上簡單,但是驗證機制在設計和實現方面卻存在著廣泛的缺陷。一般的問題可能使一個攻擊者能夠識別其他用戶的用戶名,猜測他們的密碼或者通過利用驗證的邏輯缺陷繞過這個登錄函數。當你攻擊一個web應用程序時,你應該花大量的注意力在該web應用程序所包含的各種驗證相關的功能方面。驗證方面的缺陷將使你能夠未經授權地訪問敏感數據和功能

1.1.2會話管理

處理用戶訪問的下一個工作是管理授權用戶的會話。在成功登錄到應用程序後,用戶將從他們的瀏覽發送一系列的HTTP請求來訪問一些頁面和功能。同時,該應用程序將接收無數來自不同用戶的其它的請求,有授權的用戶,也有匿名的用戶。為了實施有效的訪問控制,應用程序需要一個方法來識別和處理這一系列來自每個不同用戶的請求。

實際上大多數的web應用程序都通過為每個用戶創建一個會話和發送給用戶一個令牌(token)來識別會話。會話本身是位於服務上的一套數據結構,它被用來跟蹤與應用程序交互的用戶的狀態。令牌是一個具有唯一性的字符串,應用程序將它映射到會話。當一個用戶已經收到一個令牌時,瀏覽器在隨後的每次HTTP請求中會自動將這個令牌提交給服務器,以使得應用程序能夠將該請求與用戶相關聯起來。儘管許多應用程序使用隱藏的表單域或URL查詢字符串來實現這一目的,但是HTTP cookies是傳送會話令牌的標準方法。如果一個用戶在指定的時間內沒有產生一個請求,那麼會話將被認為結束。對於之後的訪問,web應用程序會要求你重新登錄。

就攻擊而言,會話管理機制高度地依賴於它的令牌的安全性。針對會話管理機制的多數攻擊都是試圖損害發送給別的用戶的令牌。有可能的話,一個攻擊者可以偽裝成受害的授權用戶來使用web應用程序。這一漏洞主要來自於兩方面,其一是令牌生成的方法的缺陷,使得攻擊者能夠猜測到發送給別的用戶的令牌,其二是令牌的後續處理的方法的缺陷,使得攻擊者能夠捕獲別的用戶的令牌。

有少部分的應用程序通過另外的識別方式省掉了會話令牌的需要,比如,如果一個HTTP的內建的授權機制被使用的話,那麼瀏覽器對於每次的請求都自動重新提交用戶的證書,使得應用程序能夠直接從證書識別用戶。也存在其它別的方法,應用程序存儲狀態信息在客戶端而非服務器上,這些狀態信息通常採用加密的形式以防止被篡改。

1.1.3訪問控制

處理用戶訪問的最後一步是正確決定對於每個獨立的請求是允許還是拒絕。如果前面的機制都工作正常,那麼應用程序就知道每個被接受到的請求所來自的用戶的id。它據此決定用戶對所請求要執行的動作或要訪問的數據是否得到了授權。
訪問控制機制通常需要根據對應用程序的不同部分或不同類型的功能的考慮,實現一些小而好的邏輯。一個應用程序可能支持許多不同的用戶角色,每個都牽涉到特定權限的不同組合。個別的用戶可能會被允許訪問該應用程序所容納的整個數據的一個子集。特定的函數能夠實現事務限制和其它的檢查,所有這些都需要基於用戶的id來得到正確的實施。
由於訪問控制本身的複雜性,這使得它成為使得一個攻擊者能夠獲得未授權訪問數據和功能這一安全漏洞的常見根源。開發者經常對用戶會如何與應用程序交互作出有缺陷的假設,以及經常由於省略了對某些應用程序功能的訪問控制檢查而造成疏忽。由於對於每項功能都需要重複相同的檢查,所以探查這些漏洞通常是十分費力的。然而由於訪問控制缺陷的普遍性,當你攻擊一個web應用程序時這種努力是值得的。

1.2 處理用戶的輸入
很多針對web應用程序的攻擊都涉及到提交未預期的輸入,它導致了該應用程序設計者沒有料到的行為。因此,對於應用程序安全性防護的一個關鍵的要求是它必須以一個安全的方式處理用戶的輸入。基於輸入的漏洞可能出現在一個應用程序的功能的任何地方,並與每上通常使用的技術類型相關。對於這種攻擊,輸入驗證是常用的必要防護。不存在通用的單一的防護機制。

1.2.1各種類型的輸入
一個典型的web應用程序在不同範圍形式內處理用戶提供的數據。某種類型的輸入驗證可能對於所有這些輸入形式是不可行的。
在許多情況下,一個應用程序對於特定的輸入項能夠實施非常嚴格的驗證檢查。比如提交給登錄函數的用戶名可以要求最大長度和只能包含字母。
在另外一些情況下,應用程序必須容納更大範圍的可能性的輸入。比如提交給一個個人信息頁面的地址字段,它可以包含字母、數字、空格、連接符,撇號以及其它字符。對於這種類型,仍然需要加以可行限制,如不能超過合適的長度,以及不能包含HTML標記。
在某些情形下,一個應用程序可能需要接受來自用戶的任意的輸入。比如,一個blog應用程序的用戶,他創建的博客的主題的web應用程序攻擊,那麼他提交的內容則可以包含明顯的所要討論的攻擊字符串。該應用程序需要以一個安全的方法把這些輸入存儲在一個數據庫中並寫到磁盤上,以及回顯給用戶。所以該應用程序就不能因為輸入看起來有潛在的惡意簡單拒絕。
除了來自用戶的瀏覽器的各種輸入外,典型的應用程序也接受從服務器到客戶端,然後回傳給服務器的數據。這些項目包括諸如cookies和隱藏的表單字段這些,它們不會被這個應用程序的普通用戶所看到,但是對於攻擊者來說是可見和可修改的。在這些情況中,應用程序可以對所接收的數據進行特定的驗證。例如要求參數必須有一個指定數值集中的值,如表明用戶所偏愛的語言的cookie,或以一個指定的格式,如一個客戶的ID號。進一步說,當應用程序發現返回自用戶的由服務器生成的數據已經被修改了的話,這通常就表明該用戶正在探測應用程序的漏洞。在此類情況下,應用程序應該拒絕請求並記錄下這個探測事件。

1.2.2 處理輸入的方式
處理用戶的輸入有很多方式.不同的方式適合不同的情形和不同的輸入類型,有些時候一個組合的方式是可取的.
1.2.2.1 黑名單
這種方式通常使用一個黑名單,它包含已知的被用在攻擊方面的一套字面上的字符串或模式.驗證機制阻擋任何匹配黑名單的數據.
一般來說,這種方式是被認為對於檢查用戶的輸入效果最差的一種方式.主要有兩個原因,首先是,web應用程序中的一個典型的漏洞可以使用很多種不同的輸入來被利用,輸入可以是被加密的或以各種不同的方法表示.其二,漏洞利用的技術是在不斷地改進的.有關利用已存在的漏洞類型的新的方法不可能被當前黑名單阻擋.
1.2.2.2 白名單
這種方式採用一個白名單,它包含一套字面上的字符串或模式,或一套標準,它們用來匹配符合要求的輸入.這種檢查機制允許匹配白名單的數據,阻止之外的任何數據.這種方式雖然最有效,但不是通用的,比如撇號和連字符可以被用於對數據庫的攻擊,但是有時應用程序卻應該允許它的輸入.
1.2.2.3 過濾
這種方式下,潛在的惡意字符被刪除,留下安全的字符,或者在進一步處理被執行之前,它們被適當地加密或去掉.
基於數據過濾的方式通常是十分有效的,並且在許多情形中,可作為處理惡意輸入的通用解決方案.比如,針對跨站腳本攻擊的通常的防護是在字符被嵌入到應用程序的頁面之前進行HTML加密.然而如果幾種潛在的惡意數據在一個輸入項中話,有效的過濾是困難的.在這種情況下,邊界檢查方法則是更適用的.
1.2.2.4 安全地處理數據
非常多的web應用程序漏洞的出現是因為用戶提供的數據是以不安全的方法被處理的.在一些情況下,存在安全的編程方法能夠避免通常的問題.例如,SQL注入攻擊能夠通過正確的參數查詢被阻止.在另外的情況中,應用程序功能設計的方法存在內在的不安全性,比如把用戶的輸入傳遞給操作系統的命令解釋器.
安全處理數據的方式不能適用於web應用程序需要執行的每種工作,但是它對於處理潛在的惡意輸入是通常有效的方式.
1.2.2.5 語義檢查
語義檢查用於防止各種變形數據的輸入,這些數據的內容被精心製作來干擾應用程序的處理。然而對於有一些漏洞,攻擊者的輸入在表面看來和普通用戶的輸入是一樣的,說到底檢查就失去了作用。例如一個攻擊者可能會通過改變隱藏的表意字段中的帳號來試圖獲得對他人銀行帳戶的訪問。要阻止這種未授權的訪問,應用程序需要驗證帳號是否屬於該用戶。
1.2.2.5 邊界檢查
對於web應用程序,核心安全問題的出現是因為接受自用戶的數據是不可信任的.儘管在客戶端實現的輸入驗證檢查能夠能夠提高性能和用戶體驗,但是這對於實際到達服務器的數據卻沒有任何擔保.用戶的數據在被服務端應用程序第一時間接受到的一刻就是邊界,此時應用程序需要採取步驟來防衛惡意的輸入.
鑑於核心問題的本質,對於互聯網邊界間的輸入檢查這一問題的思考是很有意義的.哪些是"惡意的"或不可信任的,以及服務端應用程序哪些是"好的"或可信任的.我們給出一個簡單的想法:輸入驗證的角色是清除到達的數據中的潛在的惡意數據,然後把乾淨的數據傳遞給可信任的應用程序.據此,這些數據可以被信任和處理而不做進一步的檢查或考慮可能的攻擊.
當我們開始檢查一些實際的漏洞的時候,會很明顯地發現上面的簡單的想法是不充分的.原因如下:

(1).鑑於web應用程序實現的功能的廣泛性,以及所應用的技術的不同,一個典型的web應用程序需要防衛大量的不同的基於輸入的攻擊.每種輸入攻擊都可能採用了一套不同的數據.針對外部邊界僅設計單一的一個機制來防衛所有這些攻擊是非常困難的.

(2).許多應用程序的函數包含相互牽連的一系列不同的處理,單個用戶所提交的一塊數據可能導致不同組件之間的許多操作,上一個的輸出可能作為下一個的輸入.當數據被傳送時,它可能有所變化,與最初的輸入可能有所不同,這樣一個熟練的黑客可能能夠操縱這個應用程序以在處理的關鍵階段導致惡意輸入的產生,也就是攻擊接受該數據的組件.這對於在外部邊界預見用戶輸入的每塊數據的處理的所有結果來實現一個驗證機制是十分困難的.

(3).防衛不同種類的輸入攻擊可能需要對用戶的輸入執行不同的驗證檢查,這些驗證檢查是不兼容的。例如阻止跨站腳本攻擊可以要求HTML加密“>”為"&gt";而阻止命令注入攻擊(command inject)可能需要阻止包含&和;字符的輸入。試圖在應用程序的外部邊界同時阻止所有種類的攻擊有時是不可能的。

一個使用邊界檢查概念的更有效的模型是,服務器端的每個組件或功能單元把它的輸入當作是來自一個潛在的惡意源。數據檢查除了在客戶端和服務端之間的邊界外,也在這些認為可信的邊界被執行。這個模型對前面列出的問題列表提供了一個解決方案。每個組件針對自身可能的漏洞的特定的輸入攻擊能夠自我防衛。當數據在不同的組件間傳遞時,驗證檢查就可以對前面傳來數據進行檢查,由於不同有驗證檢查是在不同的處理階段被執行的,所以他們之間不會產生衝突。下圖演示了一個防衛惡意輸入最有效的方式,用戶登錄致使對用戶提交的輸入進行了幾步處理,並且每步上都執行了適當的檢查。



(1).應用程序接受用戶的登錄的詳細數據.表單處理檢查輸入的每一項,包括允許的字符、長度是否在指定的範圍內、以及不能包含任何已知的攻擊特徵碼.
(2).應用程序執行一個SQL查詢來驗證用戶的證書.為了阻止SQL注入攻擊,用戶輸入的任何可能攻擊數據庫的字符在構造查詢之前都被去掉.
(3).如果登錄成功,應用程序將把來自用戶的數據傳遞給一個SOAP服務器以檢索他的帳戶的更多的信息.為了阻止SOAP注入攻擊,用戶數據中的任何XML元字符都被適當地加密處理.
(4).應用程序把用戶的賬戶信息回傳給用戶的瀏覽器以顯示.為了防止跨站腳本攻擊,應用程序HTML加密嵌在返回的頁面中的用戶提供的任何數據.

總之,所有牽涉的組件間都應作邊界檢查.情況的變化會導致所涉及的組件發生變化.例如如果登錄失敗後,應用程序會發送一個警告郵件給該用戶的話,那麼任何合併到該郵件中的用戶數據可能需要針對SMTP注入攻擊作檢查.

1.2.2.6 多步檢查和恢復

如果對用戶的輸入沒有進行仔細的多級檢查的話,攻擊者構建的輸入就可能會得逞。當一個應用程序試圖通過刪除或加密特定的字符或表達式來過濾用戶的輸入的話,這種情況就可能會出現。例如,一個應用程序可能試圖從用戶提交的數據中通過去掉表達式<script>來防止某些跨站腳本攻擊,那麼攻擊者可能通過輸入<scr<script>ipt>來繞過這個過濾。這是因為這個過濾沒有被遞歸地使用,當<scr<script>ipt>中間的<script>被去掉後,剩下的還是<script>。

類似的情況就是,攻擊者可以利用多步檢查的順序來繞過這個過濾。例如如果一個應用程序第一是遞歸地去掉<script>表達式,然後是去掉"符號的話,那麼<scr"ipt>就可以成功繞過這個過濾。

另一個問題是在用戶輸入的數據被解密時會發生的。從用戶瀏覽器過來的數據會是以不同方法加密了的數據,那麼就需要對這些數據進行恢復,也就是轉換或解密為通常的字符。如果解密是在輸入過濾之後,那麼攻擊者就可以通過加密來繞過這個檢查機制。例如,如果一個應用程序通過刪除用戶輸入數據中"號來防止某些SQL注入攻擊的話,由於過濾先於恢復,那麼攻擊者可以使用"號的URL加密形式%27來繞過這個檢查機制。同理,如果檢查機制也會去掉%27話,只要沒有遞歸處理,那麼%%2727就能夠得逞。

有時候避免多步檢查和恢復中存在的問題是比較困難的。不存在單一的方案能夠解決這些問題。有些情況下,遞歸地處理一個有問題的字符可能會

導致死循環,通常,這只能在所執行的檢查類型上來根據情況處理,情況允許的話,更好的方法就是簡單地拒絕某些類型的惡意輸入。

(轉) PHP網站防攻擊 (PHP開發中必須注意的安全防範知識)


系統講解PHP開發中安全防範知識 

PHP代碼安全和XSSSQL注入等對於各類網站的安全非常中用,尤其是UGC(User Generated Content)網站,論壇和電子商務網站,常常是XSSSQL注入的重災區。這裡簡單介紹一些基本程式設計要點, 相對系統安全來說,php安全防範更多要求程式設計人員對用戶輸入的各種參數能更細心.
  php編譯過程中的安全
  建議安裝Suhosin補丁,必裝安全補丁
  php.ini安全設置
  register_global = off
  magic_quotes_gpc = off
  display_error = off
  log_error = on
  # allow_url_fopen = off
  expose_php = off
  open_basedir =
  safe_mode = on
  disable_function = exec,system,passthru,shell_exec,escapeshellarg,escapeshellcmd,proc_close,proc_open,dl,popen,show_source,get_cfg_var
  safe_mode_include_dir =
  DB SQL預處理
  mysql_real_escape_string (很多PHPer仍在依靠addslashes防止SQL注入,但是這種方式對中文編碼仍然是有問題的。addslashes的問題在於駭客可以用0xbf27來代替單引號,GBK編碼中0xbf27不是一個合法字元,因此addslashes只是將0xbf5c27,成為一個有效的多位元組字元,其中的0xbf5c仍會被看作是單引號,具體見這篇文章)。用mysql_real_escape_string函數也需要指定正確的字元集,否則依然可能有問題。
  prepare + execute(PDO)
  ZendFramework可以用DB類的quote或者quoteInto, 這兩個方法是根據各種資料庫實施不用方法的,不會像mysql_real_escape_string只能用於mysql
  用戶輸入的處理
  無需保留HTML標籤的可以用以下方法
  strip_tags, 刪除string中所有html標籤
  htmlspecialchars,只對”<”,”>”,”;”,”’”字元進行轉義
  htmlentities,對所有html進行轉義
  必須保留HTML標籤情況下可以考慮以下工具:
  HTML Purifier: HTML Purifier is a standards-compliant HTML filter library written in PHP.
  PHP HTML Sanitizer: Remove unsafe tags and attributes from HTML code
  htmLawed: PHP code to purify & filter HTML
  上傳文件
  用is_uploaded_filemove_uploaded_file函數,使用HTTP_POST_FILES[]陣列。並通過去掉上傳目錄的PHP解釋功能來防止用戶上傳php腳本。
  ZF框架下可以考慮使用File_upload模組
  SessionCookieForm的安全處理
  不要依賴Cookie進行核心驗證,重要資訊需要加密, Form Post之前對傳輸資料進行雜湊, 例如你發出去的form元素如下:

<input type="hidden" name="H[name]" value="<?php echo $Oname?>"/> <input type="hidden" name="H[age]" value="<?php echo $Oage?>"/> <?php $sign = md5('name'.$Oname.'age'.$Oage.$secret); ?> <input type="hidden" name="hash" value="<?php echo $sign?>"" />
  POST回來之後對參數進行驗證
  $str = “”;
  foreach($_POST['H'] as $key=>$value) {
  $str .= $key.$value;
  }
  if($_POST['hash'] != md5($str.$secret)) {
  echo Hidden form data modified; exit;
  }
  PHP安全檢測工具(XSSSQL Insertion)
  Wapiti – Web application security auditor(Wapiti – 小巧的網站漏洞檢測工具) (SQL injection/XSS攻擊檢查工具)
  安裝/使用方法:
  apt-get install libtidy-0.99-0 python-ctypes python-utidylib
  python wapiti.py http://Your Website URL/ -m GET_XSS
  Pixy: XSS and SQLI Scanner for PHP( Pixy – PHP 源碼缺陷分析工具)
  安裝: apt-get install default-jdk
 PHP代碼安全和XSSSQL注入等對於各類網站的安全非常中用,尤其是UGC(User Generated Content)網站,論壇和電子商務網站,常常是XSSSQL注入的重災區。這裡簡單介紹一些基本程式設計要點, 相對系統安全來說,php安全防範更多要求程式設計人員對用戶輸入的各種參數能更細心.
  php編譯過程中的安全
  建議安裝Suhosin補丁,必裝安全補丁
  php.ini安全設置
  register_global = off
  magic_quotes_gpc = off
  display_error = off
  log_error = on
  # allow_url_fopen = off
  expose_php = off
  open_basedir =
  safe_mode = on
  disable_function = exec,system,passthru,shell_exec,escapeshellarg,escapeshellcmd,proc_close,proc_open,dl,popen,show_source,get_cfg_var
  safe_mode_include_dir =
  DB SQL預處理
  mysql_real_escape_string (很多PHPer仍在依靠addslashes防止SQL注入,但是這種方式對中文編碼仍然是有問題的。addslashes的問題在於駭客可以用0xbf27來代替單引號,GBK編碼中0xbf27不是一個合法字元,因此addslashes只是將0xbf5c27,成為一個有效的多位元組字元,其中的0xbf5c仍會被看作是單引號,具體見這篇文章)。用mysql_real_escape_string函數也需要指定正確的字元集,否則依然可能有問題。
  prepare + execute(PDO)
  ZendFramework可以用DB類的quote或者quoteInto, 這兩個方法是根據各種資料庫實施不用方法的,不會像mysql_real_escape_string只能用於mysql
  用戶輸入的處理
  無需保留HTML標籤的可以用以下方法
  strip_tags, 刪除string中所有html標籤
  htmlspecialchars,只對”<”,”>”,”;”,”’”字元進行轉義
  htmlentities,對所有html進行轉義
  必須保留HTML標籤情況下可以考慮以下工具:
  HTML Purifier: HTML Purifier is a standards-compliant HTML filter library written in PHP.
  PHP HTML Sanitizer: Remove unsafe tags and attributes from HTML code
  htmLawed: PHP code to purify & filter HTML
  上傳文件
  用is_uploaded_filemove_uploaded_file函數,使用HTTP_POST_FILES[]陣列。並通過去掉上傳目錄的PHP解釋功能來防止用戶上傳php腳本。
  ZF框架下可以考慮使用File_upload模組
  SessionCookieForm的安全處理
  不要依賴Cookie進行核心驗證,重要資訊需要加密, Form Post之前對傳輸資料進行雜湊, 例如你發出去的form元素如下:


<input type="hidden" name="H[name]" value="<?php echo $Oname?>"/> <input type="hidden" name="H[age]" value="<?php echo $Oage?>"/> <?php $sign = md5('name'.$Oname.'age'.$Oage.$secret); ?> <input type="hidden" name="hash" value="<?php echo $sign?>"" />

  POST回來之後對參數進行驗證
  $str = “”;
  foreach($_POST['H'] as $key=>$value) {
  $str .= $key.$value;
  }
  if($_POST['hash'] != md5($str.$secret)) {
  echo Hidden form data modified; exit;
  }
  PHP安全檢測工具(XSSSQL Insertion)
  Wapiti – Web application security auditor(Wapiti – 小巧的網站漏洞檢測工具) (SQL injection/XSS攻擊檢查工具)
  安裝/使用方法:
  apt-get install libtidy-0.99-0 python-ctypes python-utidylib
  python wapiti.py http://Your Website URL/ -m GET_XSS
  Pixy: XSS and SQLI Scanner for PHP( Pixy – PHP 源碼缺陷分析工具)
  安裝: apt-get install default-jdk

自由轉載,轉載請注明: 轉載自WEB開發筆記 www.chhua.com

本文來源於WEB開發筆記 http://www.chhua.com , 原文地址: http://www.chhua.com/web-note698

(轉) 加強PHP安全性的幾個原則




加強PHP安全性的幾個原則

作為PHP程式師,特別是新手,對於互聯網的險惡總是知道的太少,對於外部的入侵有很多時候是素手無策的,他們根本不知道駭客是如何入侵的、提交入侵、上傳漏洞、sql 注入、跨腳本攻擊等等。作為最基本的防範你需要注意你的外部提交,做好第一面安全機制處理防火牆。
  
規則 1:絕不要信任外部資料或輸入
  關於Web應用程式安全性,必須認識到的第一件事是不應該信任外部資料。外部資料(outside data) 包括不是由程式師在PHP代碼中直接輸入的任何資料。在採取措施確保安全之前,來自任何其他來源(比如 GET 變數、表單 POST、資料庫、設定檔、會話變數或Cookie)的任何資料都是不可信任的。
  例如,下面的資料元素可以被認為是安全的,因為它們是在PHP中設置的。
清單 1. 安全無暇的代碼   
$myUsername = ‘tmyer’;   
$arrayarrayUsers = array(‘tmyer’, ‘tom’, ‘tommy’);   
define(“GREETING”, ‘Hello there’ . $myUsername);   
?>  
  但是,下面的資料元素都是有瑕疵的。
清單 2. 不安全、有瑕疵的代碼   
$myUsername = $_POST['username']; //tainted!   
$arrayarrayUsers = array($myUsername, ‘tom’, ‘tommy’); //tainted!   
define(“GREETING”, ‘hello there’ . $myUsername); //tainted!   
?>  
  為什麼第一個變數$myUsername 是有瑕疵的?因為它直接來自表單 POST。使用者可以在這個輸入域中輸入任何字串,包括用來清除檔或運行以前上傳的檔的惡意命令。您可能會問,難道不能使用只接受字母 A-Z 的用戶端(Javascrīpt)表單檢驗腳本來避免這種危險嗎?”是的,這總是一個有好處的步驟,但是正如在後面會看到的,任何人都可以將任何表單下載到自己的機器上,修改它,然後重新提交他們需要的任何內容。
  解決方案很簡單:必須對$_POST['username'] 運行清理代碼。如果不這麼做,那麼在使用$myUsername的任何其他時候(比如在陣列或常量中),就可能污染這些物件。對用戶輸入進行清理的一個簡單方法是,使用規則運算式來處理它。在這個示例中,只希望接受字母。將字串限制為特定數量的字元,或者要求所有字母都是小寫的,這可能也是個好主意。
清單 3. 使用戶輸入變得安全   
$myUsername = cleanInput($_POST['username']); //clean!   
$arrayarrayUsers = array($myUsername, ‘tom’, ‘tommy’); //clean!   
define(“GREETING”, ‘hello there’ . $myUsername); //clean!   
function cleanInput($input){   $clean = strtolower($input);   
$clean = preg_replace(“/[^a-z]/”, “”, $clean);   
$clean = substr($clean,0,12);return $clean;   
}   
?>  
  
規則 2:禁用那些使安全性難以實施的PHP設置
  已經知道了不能信任用戶輸入,還應該知道不應該信任機器上配置 PHP 的方式。例如,要確保禁用 register_globals。如果啟用了 register_globals,就可能做一些粗心的事情,比如使用 $variable 替換同名的 GET POST 字串。通過禁用這個設置,PHP 強迫您在正確的名稱空間中引用正確的變數。要使用來自表單 POST 的變數,應該引用 $_POST['variable']。這樣就不會將這個特定變數誤會成 cookie、會話或 GET 變數。
  
規則 3:如果不能理解它,就不能保護它
  一些開發人員使用奇怪的語法,或者將語句組織得很緊湊,形成簡短但是含義模糊的代碼。這種方式可能效率高,但是如果您不理解代碼正在做什麼,那麼就無法決定如何保護它。例如,您喜歡下面兩段代碼中的哪一段?
清單 4. 使代碼容易得到保護   
//obfuscated code   
$input = (isset($_POST['username']) ? $_POST['username']:”);   
//unobfuscated code   
$input = ”;   
if (isset($_POST['username'])){   
$input = $_POST['username'];   
}else{   
$input = ”;   
}  
  在第二個比較清晰的程式碼片段中,很容易看出 $input 是有瑕疵的,需要進行清理,然後才能安全地處理。
  
規則 4縱深防禦是新的法寶
  本教程將用示例來說明如何保護線上表單,同時在處理表單的 PHP 代碼中採用必要的措施。同樣,即使使用 PHP regex 來確保 GET 變數完全是數位的,仍然可以採取措施確保 SQL 查詢使用轉義的用戶輸入。縱深防禦不只是一種好思想,它可以確保您不會陷入嚴重的麻煩。既然已經討論了基本規則,現在就來研究第一種威脅:SQL 注入攻擊。
  防止SQL注入攻擊
  在SQL注入攻擊中,用戶通過操縱表單或 GET 查詢字串,將資訊添加到資料庫查詢中。例如,假設有一個簡單的登錄資料庫。這個資料庫中的每個記錄都有一個用戶名欄位和一個密碼欄位。構建一個登錄表單,讓用戶能夠登錄。
<html>  
<head>  
<title>Login</title>  
</head>  
<body>  
<form action=”verify.php” method=”post”>  
<p><label for=’user’>Username</label>  
<input type=’text’ name=’user’ id=’user’/>  
</p> <p><label for=’pw’>Password</label>  
<input type=’password’ name=’pw’ id=’pw’/>  
</p> <p><input type=’submit’ value=’login’/></p>  
</form>  
</body>  
</html>  
  這個表單接受使用者輸入的用戶名和密碼,並將使用者輸入提交給名為verify.php的文件。在這個檔中,PHP處理來自登錄表單的資料,如下所示:
清單 5. 不安全的 PHP 表單處理代碼   
<?php  
$okay = 0;   
$username = $_POST['user'];   
$pw = $_POST['pw'];   
$sql = “select count(*) as ctr from users where username=’
”.$username.”‘ and password=’”. $pw.”‘ limit 1;   
$result = MySQL_query($sql);   
while ($data = mysql_fetch_object($result)){   
if ($data->ctr == 1){   
//they’re okay to enter The application!   
$okay = 1;   
}   
}   
if ($okay){   
$_SESSION['loginokay'] = true;   
header(“index.php”);   
}else{   
header(“login.php”);   
}   
?>  
  這段代碼看起來沒問題,對嗎?世界各地成百(甚至成千) PHP/MySQL 網站都在使用這樣的代碼。它錯在哪裡?好,記住不能信任用戶輸入。這裡沒有對來自使用者的任何資訊進行轉義,因此使應用程式容易受到攻擊。具體來說,可能會出現任何類型的SQL注入攻擊。例如,如果用戶輸入 foo 作為用戶名,輸入 or 1=1 作為密碼,那麼實際上會將以下字串傳遞給 PHP,然後將查詢傳遞給 MySQL
<?php  
$sql = “select count(*) as ctr from users where username=
’foo’ and password=” or ’1=’1 limit 1;   
?>  
  這個查詢總是返回計數值 1,因此 PHP 會允許進行訪問。通過在密碼字串的末尾注入某些惡意 SQL,駭客就能裝扮成合法的用戶。解決這個問題的辦法是,將 PHP 的內置 mysql_real_escape_string() 函數用作任何使用者輸入的包裝器。這個函數對字串中的字元進行轉義,使字串不可能傳遞撇號等特殊字元並讓 MySQL 根據特殊字元進行操作。清單7展示了帶轉義處理的代碼。
清單7展示了帶轉義處理的代碼   
<?php     
$okay = 0;     
$username = $_POST['user'];     
$pw = $_POST['pw'];     
$sql = ”select count(*) as ctr from users where username=’”.mysql_real_
_string($username).”‘ and password=’”. mysql_real_escape_string($pw).”‘
 limit 1;      
$result = mysql_query($sql);     
while ($data = mysql_fetch_object($result)){         
       if ($data->ctr == 1){          //they’re okay to enter the 
application!             
       $okay = 1;          
       }     
      }     
       if ($okay){         
           $_SESSION['loginokay'] = true;         
           header(“index.php”);     
           }   
        else{         
        header(“login.php”);     
      }     
?>  
  使用 mysql_real_escape_string() 作為用戶輸入的包裝器,就可以避免用戶輸入中的任何惡意 SQL 注入。如果使用者嘗試通過 SQL 注入傳遞畸形的密碼,那麼會將以下查詢傳遞給資料庫:
select count(*) as ctr from users where username=’foo’ and password=
’’ or ’1’=’1 limit 1 

自由轉載,轉載請注明: 轉載自WEB開發筆記 www.chhua.com

本文來源於WEB開發筆記 http://www.chhua.com , 原文地址: http://www.chhua.com/web-note1413