| 本單元內容 | |
| 目標 | |
| 適用於 | |
| 如何使用本單元 | |
| Web 應用程式的架構及設計 | |
| 部署考量 | |
| 輸入驗證 | |
| 驗證 | |
| 授權 | |
| 設定管理 | |
| 機密資料 | |
| 工作階段管理 | |
| 密碼編譯 | |
| 參數操作 | |
| 例外管理 | |
| 稽核和記錄 | |
| 設計指導方針總結 | |
| 總結 | |
| 其他資源 |
對設計師、設計者、和開發人員而言,Web 應用程式代表了一組複雜的安全性問題。只有在從建置一開始築基向上時,就隨時將安全性納入考慮,才能完成最安全和具「可回復性」的 Web 應用程式。
在早期設計階段,應該套用健全的架構和設計實務,並且結合部署考慮和整體的安全性原則。沒有如此做的話,會導致應用程式部署在有安全性危害的現行架構上。
本單元展示一套安全的架構和設計指導方針。由一般應用程式弱點類別來加以組織分類。這些是 Web 應用程式安全性的關鍵區域,也是最常發生錯誤的區域。
透過本單元即可:
| • | 識別安全的 Web 應用程式的關鍵架構和設計問題。 |
| • | 考慮在設計時期的關鍵部署問題。 |
| • | 設計策略來加強 Web 應用程式輸入驗證。 |
| • | 設計安全的驗證和工作階段管理機制。 |
| • | 選擇適當的授權模型。 |
| • | 執行有效的帳戶管理實務和保護使用者工作階段。 |
| • | 使用密碼編譯來提供隱私性、不可否認性、防止竄改、和驗證。 |
| • | 防止參數操作。 |
| • | 設計稽核和記錄策略。 |
本單元中的資訊雖然是包含在 ASP.NET 安全性書籍中,但卻和對開發安全的 Web 應用程式有興趣的所有人息息相關。
本單元的焦點集中在設計應用程式時所應遵循的指導方針和原則。
若要充分瞭解本單元:
| • | 瞭解針對應用程式的潛在威脅,如此才能確保設計能夠應付這些潛在威脅。請參閱單元 2<潛在威脅及因應對策>,以取得對所關心的潛在威脅的瞭解。單元 2 列出可能損害應用程式的潛在威脅。在設計階段中必須將這些潛在威脅列入考慮。 |
| • | 在應用程式有漏洞容易遭到攻擊的關鍵區域使用系統化的方法。集中注意力在部署考慮;輸入驗證;驗證和授權;密碼編譯和資料機密性;組態、工作階段、和例外管理;和適當的稽核和記錄以確保說明能力。 |
Web 應用程式呈現給設計者和開發人員許多的挑戰。HTTP 無狀態的本質意味著追蹤每一使用者的工作階段狀態成為應用程式的責任。身為此一領域的先驅,應用程式必須能夠使用某種形式的驗證來識別使用者。根據使用者的識別身份來做所有其後授權的決定,安全的驗證過程和用來追蹤已驗證使用者的工作階段處理機制也受到相當良好的保護,這些都是不可或缺的。設計安全的驗證和工作階段處理機制只是 Web 應用程式設計者和開發人員所需面對的許多問題中的兩個。其他挑戰的發生是因為在公用網路上傳送輸入和輸出的資料。其他重要的問題是防止參數被操作和機密資料公開。
[圖 4.1] 顯示在安全設計實作上必須應付的一些首要問題。

[圖 4.1]
Web 應用程式設計問題
本單元中的設計指導方針是由應用程式弱點類別來加以組織分類的。經驗顯示在這些區域的不良設計,特別容易導致安全性弱點。[表 4.1] 列出弱點類別,並針對個別弱點類別強調由於不良設計所可能導致的問題。
[表 4.1] Web 應用程式弱點和由於不良設計所可能導致的問題
| 弱點類別 | 由於不良設計所可能導致的問題 |
輸入驗證 | 在查詢字串、表單欄位、Cookie、和 HTTP 標頭中的嵌入惡意字串所執行的攻擊。這些包括命令的執行、跨網站指令碼 (XSS)、SQL 注入、和緩衝區溢位攻擊。 |
驗證 | 偽造識別身份、密碼破解、權限提升、和未授權存取。 |
授權 | 存取機密或限制的資料、竄改、和未授權操作的執行。 |
設定管理 | 未授權存取管理介面、更新組態資料的能力、和未授權存取使用者帳戶與帳戶設定檔。 |
機密資料 | 機密資料公開和資料竄改。 |
工作階段管理 | 擷取工作階段識別元而導致連線劫持和偽造識別身份。 |
密碼編譯 | 存取機密資料或帳戶憑證,或兩者皆是。 |
參數操作 | 路徑橫越攻擊、命令的執行、在其他的機制之間跳過存取控制機制、導致資料公開、權限提升、和拒絕服務。 |
例外管理 | 拒絕服務和機密系統層級詳細資料公開。 |
稽核和記錄 | 未能認出入侵的徵兆、沒有能力證明使用者的動作、和在問題的判斷上有困難。 |
在應用程式設計的階段,應該檢閱整體的安全性原則和程序,以及應用程式即將被部署所在的架構。通常,目標環境是固定不動的,應用程式設計必須反映這些限制。有時候,設計必須做出折衷,例如,因為通訊協定或連接埠的限制,或特定的部署拓樸。在設計階段及早識別出限制以避免事後的意外,和拖累網路和架構團隊的成員來協助處理。
[圖 4.2] 顯示需要在設計時期考慮的不同部署觀點。

[圖 4.2]
部署時的考慮事項
安全性原則決定應用程式被許做什麼和應用程式的使用者被允許做什麼。更重要地,它們定義了決定應用程式和使用者不被允許做什麼的限制。在設計應用程式時必須要在整體安全性原則定義的架構下識別和工作,以確認沒有破壞原則而妨礙應用程式的部署。
確認您瞭解目標環境所支援的網路架構,以及關於篩選規則、連接埠限制、支援通訊協定等等的網路基礎安全性需求。
識別防火牆和防火牆原則會如何影響應用程式的設計和部署。可能會有防火牆來將網際網路專用的應用程式和內部網路隔開。在資料庫的前端可能有額外的防火牆。這些會影響可能的通訊連接埠,進而影響從 Web 伺服器到遠端應用程式和資料庫伺服器的驗證選項。例如,Windows 驗證需要額外的連接埠。
在設計階段,考慮允許外圍網路的 Web 伺服器使用什麼通訊協定、連接埠、和服務來存取內部的資源。同時也識別應用程式設計需求的通訊協定和連接埠,並且分析開啟新的連接埠或使用新的通訊協定會發生的可能潛在威脅。
溝通並記錄任何關於網路和應用程式層級安全性所做的假設,以及哪個元件會處理什麼。當開發和網路團隊都以為對方已經處理了這個問題時,如此做可以防止安全性控制被遺漏。如果伺服器是倚賴網路來提供安全性時,請特別注意安全性防衛。考慮網路組態變更的蘊涵。如果執行特定的網路變更會喪失多少的安全性?
應用程式的部署拓樸和是否有遠端應用程式階層是必須併入到設計的關鍵考慮。如果有遠端應用程式階層,必須考慮如何應付網路竊聽的潛在威脅以保障伺服器之間網路的安全,和如何提供機密資料的隱私性與完整性。
同時當應用程式連結到遠端伺服器時,也要考慮識別身份流程以及用於網路驗證的帳戶。一般的方法是使用最小權限處理序帳戶,以及在遠端伺服器上使用相同密碼建立一個複製 (鏡像) 帳戶。也可以交替的使用網域處理帳戶來提供較為簡便的管理但是比較不安全,因為要在網路上處處限制該帳戶使用有實際上的困難。在中間有防火牆或是沒有信任關係的分隔網域,經常會造成本機帳戶方式成為唯一可行的選項。
內部網路、外部網路、和網際網路應用程式的狀況,每一個都代表著設計上的挑戰。應該考慮的問題包括:如何將呼叫者的識別身份經由多重應用程式階層流往後端的資源?在哪裡執行驗證?是否可以信任前端的驗證,然後使用受信任的連線來存取後端的資源?在外部網路的狀況,也必須考慮是否信任夥伴的帳戶。
如需更多關於這些和其他特定狀況問題的詳細資料,請參閱在《Building Secure ASP.NET Web Applications: Authentication, Authorization, and Secure Communication (英文)》中的<Intranet Security>、<Intranet Security>、和<Internet Security>各章節,網址為 http://msdn.microsoft.com/library/en-us/dnnetsec/html/secnetlpMSDN.asp。
輸入驗證是一個有挑戰性的問題,也是落在應用程式開發人員肩上的應用程式的主要負擔。然而,正確的輸入驗證是對抗今日應用程式攻擊的最有力防衛手段之一。正確的輸入驗證是可以用來幫助防止 XSS、SQL 注入、緩衝區溢位、和其他輸入攻擊的有效因應對策。
輸入驗證很有挑戰性,因為跨越應用程式或甚至在應用程式之內,有效的輸入是由什麼組成的並沒有唯一的答案。同樣地,惡意的輸入也沒有唯一的定義。應用程式使用輸入做了什麼會影響到利用的風險,也對此增加了困難度。例如,是否儲存資料供其他應用程式使用,或應用程式消耗由其他應用程式建立的資料來源的輸入?
以下的做法可以加強 Web 應用程式的輸入驗證:
| • | 「假設所有的輸入是惡意的」。 |
| • | 「使用集中的方法」。 |
| • | 「不要倚賴用戶端的驗證」。 |
| • | 「小心標準化的問題」。 |
| • | 「對輸入加以限制、拒絕、和安全性過濾」。 |
輸入驗證開始的基本假設是,在證明不是之前所有的輸入都是有惡意的。不論輸入是來自服務、檔案共用、使用者、或資料庫,如果輸入的來源是在信任界限之外都要加以驗證。例如,如果呼叫外部的 Web 服務並得到回覆字串,如何知道有沒有出現惡意的命令?同樣的,如果好幾個應用程式寫入一個共用的資料庫,當讀取資料時如何知道資料是否安全?
把輸入驗證策略作為應用程式設計的核心元素。考慮使用集中的方法來驗證,例如,在共用程式庫使用一般驗證和篩選程式碼。如此可確保套用驗證規則的一致性。也可以減少開發的投入和協助未來的維護。
在許多個案中,個別的欄位需要特定的驗證,例如,使用特別開發的規則運算式。然而,經常會析出一般常式的因數來驗證常用的欄位,例如電子郵件地址、主旨、名稱、郵政地址包括 ZIP 或郵遞區號等等。[圖 4.3] 顯示這個方法。

[圖 4.3]
輸入驗證的集中方法
伺服器端的程式碼應該執行自己的驗證。如果攻擊者跳過用戶端,或關閉用戶端指令檔常式,例如停用 JavaScript 時要怎麼辦?使用用戶端驗證來協助減少到伺服器的來回次數,但是不能倚賴它做為安全性的依靠。這是一個潛在防衛的範例。
在標準格式 (canonical form) 中的資料是在它最標準或最簡單的格式。標準化是將資料轉換成它的標準格式的過程。檔案路徑和 URL 特別容易犯標準化問題的錯誤,許多已知的利用就是標準化問題的直接結果。例如,想想看下列的字串在它的標準格式中包括檔案和路徑。
c:\temp\somefile.dat
下列的字串也可以代表同一個檔案。
somefile.dat c:\temp\subdir\..\somefile.dat c:\ temp\ somefile.dat ..\somefile.dat c%3A%5Ctemp%5Csubdir%5C%2E%2E%5Csomefile.dat
在最後的例子中,字元是使用特定的十六進位格式:
| • | %3A 是冒號 (:) 符號。 |
| • | %5C 是反斜線 (\) 符號。 |
| • | %2E 是句點 (.) 符號。 |
You should genera一般設計應用程式時應該試著避免接受使用者輸入檔案名稱以避免標準化問題。考慮替代的設計方案。例如,讓應用程式替使用者決定檔案名稱。
如果真的需要接受輸入檔案名稱,請在做安全性決定前,例如同意或拒絕對特定檔案的存取,確認輸入檔案的名稱嚴格地遵守格式的規定。
有關如何安全的處理檔案名稱和執行檔案 I/O 的詳細資料,請參閱單元 7<建置安全的組件>中的「檔案 I/O」章節和單元 8<程式碼存取安全性實務>。
驗證輸入慣用的方法是從一開始就約束什麼是容許的。從已知正確的類型、模式和範圍來驗證資料,遠比尋找已知的錯誤字元來驗證資料容易的多了。當設計應用程式時,您知道應用程式的期待是什麼。和可能的惡意輸入相較,正確資料的範圍通常比較有限。然而,做為潛在防衛可能也要拒絕已知錯誤字元,然後對輸入做安全性過濾。[圖 4.4] 顯示建議策略。

[圖 4.4]
輸入驗證策略:對輸入進行限制、拒絕、和安全性過濾。
若要建立有效的輸入驗證策略,請注意下列方法和取捨:
| • | 限制輸入。 |
| • | 確認資料的類型、長度、格式、和範圍。 |
| • | 拒絕已知的錯誤輸入。 |
| • | 對輸入進行安全性過濾。 |
限制輸入的意思差不多就是容許正確資料。這是慣用的方法。在此的想法是使用類型、長度、格式、和範圍來定義可接受輸入的篩選器。定義什麼是應用程式欄位可接受的輸入並強制實施。其他所有事物都視為錯誤資料加以拒絕。
輸入的限制可能會牽涉到在伺服器上設定字元集,所以可以用本地化的方式建立輸入的標準格式。
只要在可能的地方就對輸入資料使用增強式類型的檢查,例如,在慣於操作和處理輸入資料的類別和在資料存取常式。例如,對於資料存取使用參數化的預存程序,可受益於輸入欄位的增強式類型的檢查。
字串欄位應該也要做長度的檢查,而在許多例子中也要檢查正確的格式。例如,ZIP 程式碼、個人識別碼等等有適當的定義格式,可以使用規則運算式來加以驗證。徹底的檢查不僅是良好的程式設計實作;也讓攻擊者更難以利用程式碼。攻擊者或許可以闖過類型檢查,但是長度檢查會使攻擊的執行更加困難。
拒絕「錯誤」資料;但是不能完全地倚賴這個方法。通常這個方法比不上使用之前說明的「容許」的方法有效,而且最好要混合使用。拒絕錯誤資料是假設應用程式知道惡意輸入的所有變種。請記住字元有多重的表示方法。這也是為什麼「容許」是慣用的方法的另一個理由。
當對於已經部署的應用程式有益和無法負擔做出重大的改變時,「拒絕」的方法不像「容許」的方法那麼強大,因為錯誤資料,例如模式可用於驗證一般攻擊,但是無法維持穩定。當錯誤資料的範圍隨著時間變動時,有效資料仍然穩定。
安全性過濾可使潛在惡意資料變安全。當容許的輸入範圍不能保證輸入是安全的時候,安全性過濾是很有用的。這包括從使用者所提供字串的結尾刪去空 (Null) 值,到將值逸出以使它們能被視為文字等情況。
另一個在 Web 應用程式常見對輸入進行安全性過濾的範例是,使用 URL 編碼或 HTML 編碼來包裹資料,並將其視為文字而非可執行的指令檔。「HtmlEncode」方法編譯 HTML 字元,以及「UrlEncode」方法編碼 URL 所以是有效的 URI 要求。
以下是使用前面的方法適用於一般輸入欄位的範例:
| • | 「姓氏欄位」。這是正確的限制輸入的好例子。在這個例子中,可以容許字串資料的範圍是 ASCII AZ 和 az,以及連字號和捲曲的撇號 (捲曲的撇號對 SQL 並不重要) 來處理名字例如 O'Dell。也要將長度限制到所預期最長的值。 | ||||
| • | 「數量欄位」。這是另一個有良好限制輸入的例子。在這個例子中,可以使用簡單的類型和範圍限制。例如,輸入資料必須是介於 0 和 1000 的正整數。 | ||||
| • | 「自由文字欄位」。範例包括討論欄的註解欄位。在這個例子中,可以容許字母和空格,以及一般符號例如撇號、逗號、和連字號。所容許的組合不包括小於和大於符號、括弧、和大括弧。 有一些應用程式容許使用者使用有限組合的指令字元來標識文字,例如粗體的「<b>」,斜體的「<b>」,或甚至包括到喜愛的 URL 的連結。在 URL 的例子,驗證應該將值編碼,如此值才會被視為是 URL。 有關驗證自由文字欄位的詳細資訊,請參閱單元 10<建置安全的 ASP.NET 網頁和控制項>中的「輸入驗證」。 | ||||
| • | 「不驗證使用者輸入的現有 Web 應用程式」。在理想狀況下,應用程式會檢查可接受輸入的每個欄位或進入點。然而,如果現有的 Web 應用程式並不驗證使用者輸入,在加強應用程式的輸入驗證策略之前,需要有權宜的方法來減輕風險。儘管以下的方法都不能確保安全的處理輸入,因為取決於輸入從何而來和應用程式如何使用輸入,然而在今日的實務操作上,它們是短期內改進安全性的快速修補之道:
|
有關更多詳細資料以及使用規則運算式和 ASP.NET 驗證控制元來做輸入編碼的範例,請參閱單元 10<建置安全的 ASP.NET 網頁和控制項>中的「輸入驗證」。
驗證是決定呼叫者識別身份的過程。有三個層面需要考慮:
| • | 識別在應用程式中哪裡需要驗證。通常是在跨過信任界限時需要驗證。信任界限通常包括組件、處理程序、和主機。 |
| • | 驗證呼叫者是誰。使用者典型是用使用者名稱和密碼來驗證他們的身份。 |
| • | 在後續的要求時識別使用者。這需要某些形式的驗證權杖。 |
許多 Web 應用程式使用密碼機制來驗證使用者,使用者以 HTML 的形式提供使用者名稱和密碼。在此要考慮的問題包括:
| • | 「使用者名稱和密碼是否在不安全的通道上以純文字傳送」?如果是的話,攻擊者就可以使用網路監控軟體竊聽來擷取憑證。在此的因應對策是使用 Secure Socket Layer (SSL) 來保障通訊通道的安全。 |
| • | 「如何儲存憑證」?如果您在檔案或資料庫中以純文字儲存使用者名稱和密碼,那麼您是在自找麻煩。如果應用程式目錄沒有正確設定,而攻擊者能瀏覽到檔案並下載檔案內容或增加新的特殊權限登入帳戶時怎麼辦?如果有不滿的系統管理員取得使用者名稱和密碼的資料庫時怎麼辦? |
| • | 「如何確認憑證」?如果唯一的目的只是要確認使用者知道密碼值,並不需要儲存使用者密碼。可以替代的以雜湊值的形式儲存一個檢查器,在登入過程中以使用者提供的值重新計算雜湊。若要減輕目錄攻擊對於憑證儲存的潛在威脅,使用增強式密碼以及將亂數產生的 salt 值和密碼雜湊合併起來。 |
| • | 「在初始登入後如何識別已驗證使用者」?需要某些形式的驗證票證,例如驗證 Cookie。如何保障 Cookie 的安全?如果在不安全的通道上傳送 Cookie,攻擊者就可以擷取它並用來存取應用程式。驗證 Cookie 被竊取就等於登入被偷。 |
以下的做法可以加強 Web 應用程式的驗證:
| • | 隔開公共區域和限制區域。 |
| • | 對一般使用者帳戶使用帳戶鎖定原則。 |
| • | 支援密碼到期日。 |
| • | 有停用帳戶的能力。 |
| • | 不要將密碼儲存在使用者存放區。 |
| • | 要求增強式密碼。 |
| • | 不要在網路連線上以純文字傳送密碼。 |
| • | 保護驗證 Cookie。 |
站台的公共區域可供任何使用者匿名存取。只有特定的個體和必須經過站台驗證的使用者才能存取限制區域。考慮典型的零售網站。可以匿名瀏覽產品型錄。當新增項目到購物推車 (shopping cart) 時,應用程式會使用工作階段識別元來對您加以識別。最後,當您下訂單時,就開始執行安全的交易。在 SSL 上您需要登入以驗證交易。
將站台分開成公共和限制存取區域,您可以對站台不同區域套用不同的驗證和授權原則並限制 SSL 的使用。若要避免因為使用 SSL 所造成效能的負荷,可以設計站台只在需要驗證存取的區域使用 SSL。
在達到預先設定的登入失敗次數之後,停用一般使用者帳戶或將事件寫入記錄檔。如果使用 Windows 驗證,例如 NTLM 或 Kerberos 通訊協定,作業系統會自動設定和套用這些原則。對於表單驗證,這些原則是應用程式的責任並且必須結合到應用程式的設計中。
小心帳戶鎖定原則遭到拒絕服務攻擊的濫用。例如,熟知預設服務帳戶像 IUSR_MACHINENAME 就應該用自訂帳戶名稱來代替,以避免攻擊者藉由鎖定這個關鍵帳戶來取得網際網路資訊服務 (IIS) Web 伺服器名稱。
密碼不應該是靜態的,而且密碼的變更應該經由密碼到期日做為例行密碼維護的一部份。在應用程式設計時,考慮提供這一類的裝置。
如果系統受損了,能夠考慮使憑證失效或停用帳戶以避免其他的攻擊。
即使必須確認密碼,也並不需要實際地儲存密碼。可以替代的儲存單向的雜湊值,然後以使用者提供的密碼重新計算雜湊。若要減輕目錄攻擊對於使用者存放區的潛在威脅,使用增強式密碼以及將亂數產生的 salt 值和密碼雜湊合併起來。
不要讓攻擊者得以輕易破解密碼。有許多可行的指導方針,但是通常的實作是要求密碼至少要有八個字元而且要是大寫和小寫字元、數字、和特殊符號的組合。無論是使用平台來強制這些或開發自己的驗證,當攻擊者有系統地以嘗試錯誤的方法破解密碼,這個步驟在反制此類暴力攻擊時是必要的。使用規則運算式來協助增強式密碼驗證。
有關規則運算式輔助密碼驗證的詳細資訊,請參閱單元 10<建置安全的 ASP.NET 網頁和控制項>中的「輸入驗證」。
在網路上傳送純文字密碼容易遭到竊聽。若要應付這個潛在威脅,就要保障通訊通道的安全,例如使用 SSL 來加密資料傳輸。
驗證 Cookie 被竊取就等於登入被偷。使用加密和安全的通訊通道來保護驗證票證。同時也限制驗證票證維持有效的時間間隔,以反制可能導致重新執行攻擊的欺騙潛在威脅,重新執行攻擊的攻擊者會擷取 Cookie 並用它來取得對站台的違法存取。降低 Cookie 的逾時並不能防止重新執行攻擊,但是可以限制攻擊者使用偷來的 Cookie 存取站台的時間總數。
授權決定已驗證的識別身份可以做什麼和存取什麼資源。不適當或安全性不足的授權會導致資料公開和資料竄改。潛在防衛是適用於應用程式授權策略的關鍵安全性原則。
以下的做法可以加強 Web 應用程式的授權:
| • | 使用多重閘道管理。 |
| • | 限制使用者存取系統層級的資源。 |
| • | 考量授權細微性。 |
在伺服器端,可以使用 IP 安全性通訊協定 (IPSec) 原則來提供主機限制以限制伺服器到伺服器的通訊。例如,IPSec 原則可以限制除了指定的 Web 伺服器之外,任何主機都不能連結到資料庫伺服器。IIS 提供 Web 使用權限和網際網路通訊協定/網域名稱系統 (IP/DNS) 限制。不論使用者是誰,IIS Web 使用權限適用於在 HTTP 上所要求的所有資源。如果攻擊者操縱了伺服器上的記錄檔,它們並不提供保護。針對於此,NTFS 使用權限容許指定每一使用者的存取控制清單。最後,ASP.NET 提供 URL 授權和檔案授權以及主要權限要求。經由合併這些閘道管理可以發展出有效的授權策略。
系統層級的資源包括檔案、資料夾、登錄機碼、Active Directory 物件、資料庫物件、和事件日誌等等。使用 Windows 存取控制清單 (ACL) 來限制使用者可以存取什麼資源和執行什麼操作類型。請特別注意匿名 Internet 使用者帳戶;對於明確拒絕匿名使用者存取的資源請使用 ACL 來鎖定。
有關使用 Windows ACL 鎖定匿名 Internet 使用者帳戶的詳細資訊,請參閱單元 16<保障 Web 伺服器的安全>。
有三個常見的授權模型,每一個都有不同程度的細微性和擴充性。
最常用的等級分級方法是倚賴模擬。使用呼叫者的安全性內容來產生資源存取。在被保護的資源上 (典型是檔案或表單,或者二者皆是) 使用 Windows ACL 來決定呼叫者是否被容許存取資源。如果應用程式主要是提供存取到使用者特定資源,這個方法就有效。附加好處是應用程式可以跨階層執行作業系統層級的稽核,因為原始呼叫者的安全性內容是在作業系統層級流動並用做資源存取。然而,這個方法受限於應用程式的擴充性不良,因為沒有用於資料庫存取的有效連結集區。結果,這個方法最常用於規模有限以內部網路為主的應用程式。[圖 4.5] 顯示模擬模型。

[圖 4.5]
模擬模型提供每一個一般使用者授權細微性
使用應用程式處理程序識別身份來存取資源,是最細微但最具擴充性的方法。這個方法支援資料庫連結集區,但是也意味著資料庫所賦予應用程式識別身份的權限是普通的,與原始呼叫者的識別身份無關。應用程式的邏輯中間層使用角色來執行主要的授權,在應用程式中有相同權限的使用者會被分組到同樣的角色。根據呼叫者的角色成員資格來限制存取的類別和方法。若要支援擷取每一使用者的資料,普遍的方法是在資料庫表單納入一個識別身份欄以及使用查詢參數來限制擷取資料。例如,經由預存程序參數將原始呼叫者的識別身份傳送到應用程式 (不是作業系統) 層級的資料庫,並且寫入類似下面的查詢:
SELECT field1, field2, field3 FROM Table1 WHERE {some search criteria} AND
UserName = @originalCallerUserName
這個模型被稱為受信任子系統或有時候叫做受信任伺服器模型。顯示在 [圖 4.6]。

[圖 4.6]
支援資料庫連結集區的受信任子系統模型
第三個選項是根據呼叫者的角色成員資格來使用有限組合的識別身份做資源存取。這是前面所說明兩種模型的混合體。在應用程式的邏輯中間層呼叫者被對應至角色,然後基於角色的成員資格來限制可存取的類別和方法。根據現行呼叫者的角色成員資格,來使用限制組合的識別身份執行下游的資源存取。這個方法的好處是在資料庫權限可以被指定到不同的登入,以及在多重連結集區時連結集區仍然有效。不利的是,對於使用 Windows 驗證的下游資源存取,建立用於其不同安全性內容的多執行緒存取憑證是特殊權限操作,需要有特殊權限處理序帳戶。這是對最小權限原則的反制。[圖 4.7] 顯示混合體模型使用多重受信任服務識別身份來存取下游資源。

[圖 4.7]
混合體模型
請謹慎考慮 Web 應用程式的設定管理功能性。大部份的應用程式需要有介面讓內容開發者、操作員、和系統管理員來設定應用程式,和管理例如網頁內容、使用者帳戶、使用者設定檔資訊、與資料庫連結字串等項目。如果有支援遠端管理,要如何保障管理介面的安全呢?管理介面遭到安全性破壞的後果是很嚴重的,因為攻擊者經常會使用系統管理員權限終止執行和直接存取到整個站台。
以下的做法可以加強 Web 應用程式的設定管理安全性:
| • | 保障管理介面的安全。 |
| • | 保障組態存放區的安全。 |
| • | 維護區隔的管理權限。 |
| • | 使用最小權限處理序和服務帳戶。 |
只有被授權的操作員和系統管理員才能存取設定管理功能是很重要的。關鍵部份是在管理介面上強制使用增強式驗證,例如使用憑證。
如果可能的話,限制或避免遠端管理並且要求系統管理員在本機登入。如果需要支援遠端管理,那就使用加密通道,例如 SSL 或 VPN 技術,因為管理介面上傳送的資料本質上都是屬於機密的。也可以考慮使用 IPSec 原則來限制對內部網路上電腦的遠端管理,以進一步降低風險。
以文字為主的組態檔案、登錄、和資料庫,是儲存應用程式組態資料的一般選項。如果可能的話,在應用程式的 Web 空間避免使用組態檔案,以防止可能的伺服器組態弱點導致組態檔案下載。無論使用什麼方法,保障到組態存放區的存取安全,例如,使用 Windows ACL 或資料庫權限。也要避免以純文字儲存機密資料,例如資料庫連結字串或帳戶憑證。使用加密來保障這些項目的安全,然後限制對有包含加密資料的登錄機碼、檔案、或表單的存取。
如果根據系統管理員的角色不同,應用程式設定管理功能所支援的功能性有所差異的話,考慮使用以角色為主的授權來區隔每個角色的授權。例如,負責更新站台靜態內容的人就不需要容許去變更客戶的信用額度。
應用程式組態的一個重點是用於執行 Web 伺服器處理程序的處理序帳戶和用於存取下游資源和系統的服務帳戶。確認這些帳戶設定為最小權限。即使攻擊者控制了處理程序,由於處理程序的識別身份對存取檔案系統和其他系統資源受到很大的限制,所以能夠造成的損害也有限。
處理信用於號碼、地址、醫療記錄等等個人隱私資料的應用程式,應該採取特別的步驟來確保資料維持隱密和沒有被改變。此外,用於應用程式實作的機密資料,例如密碼和資料庫連結字串也必須要保障安全。當機密資料存放在永續性的儲存或在網路上傳送時,它的安全性是一個問題。
機密資料包括密碼、資料庫連結字串、和信用卡號碼。以下的做法可以加強 Web 應用程式處理機密資料的安全性:
| • | 如果可以避免的話,不要儲存機密資料。 |
| • | 不要在程式碼中儲存機密資料。 |
| • | 不要以純文字儲存資料庫連結、密碼、或金鑰。 |
| • | 避免在本機安全性授權 (LSA) 中儲存機密資料。 |
| • | 使用 Data Protection API (DPAPI) 對機密資料進行加密。 |
用軟體儲存機密資料的完全安全辦法是不可能的。實體存取到伺服器的系統管理員可以存取資料。例如,當您必須要做的是確認使用者是否知道機密資料時,並不需要儲存機密資料。在這個例子中,可以儲存一個代表機密資料的雜湊值,然後以使用者提供的值計算雜湊來檢驗使用者是否知道機密。
不要在程式碼中硬式編碼機密資料。即使在 Web 伺服器上並沒有暴露來源碼,也有可能從已編譯的可執行檔案擷取出字串常數。組態的弱點會容許攻擊者擷取可執行檔。
避免以純文字儲存機密,例如資料庫連結字串、密碼、和金鑰。使用加密和儲存加密字串。
避開 LSA,因為應用程式需要有系統管理員權限才能存取它。這和使用最小權限執行的核心安全性原則相抵觸。同時,LSA 也只有有限數目的插槽可以用來儲存機密。較好的方法是使用 DPAPI,適用於 Microsoft Windows® 2000 和更新版本的作業系統。
使用 DPAPI 來儲存機密資料,例如資料庫連結字串或服務帳戶憑證。使用 DPAPI 主要的好處是由平台系統來管理加密/解密金鑰,而不再是應用程式的問題。端視傳送給 DPAPI 功能的旗標而定,金鑰可能和 Windows 使用者帳戶或特定的電腦相結合。
DPAPI 最適合用在加密那些當主要金鑰遺失時可以手動重建的資料,例如因為伺服器故障而需要重新安裝作業系統。因為不知道純文字的值所以資料無法復原,例如,客戶信用卡詳細資料,需要有使用傳統對稱金鑰為主的密碼編譯法的替代方案,例如使用 tripleDES。
有關從 Web 應用程式使用 DPAPI 的詳細資訊,請參閱單元 10<建置安全的 ASP.NET 網頁和控制項>。
機密資料例如登入憑證,和應用程式層級資料例如信用卡號碼、銀行帳戶號碼等等,都必須加以保護。經由加密達到隱私性和經由訊息驗證碼 (MAC) 達到完整性是關鍵的元素。
以下的做法可以加強 Web 應用程式對機密的每一使用者資料的安全性:
| • | 根據需要擷取機密資料。 |
| • | 加密資料或保障通訊通道的安全。 |
| • | 不要在永續性的 Cookie 中儲存機密資料。 |
| • | 不要使用 HTTP-GET 通訊協定來傳送機密資料。 |
慣用的方法是當有需要時根據需要擷取機密資料,而不是留存或快取在記憶體中。例如,當有需要時擷取加密的機密、解密、使用、然後清除用來保存純文字機密的記憶體 (變數)。如果效能有問題,請考慮下列的選項:
| • | 快取加密的機密。 |
| • | 快取純文字的機密。 |
快取加密的機密
當應用程式載入時擷取機密,然後將加密的機密快取到記憶體,當應用程式要用到它時再解密。當不再需要時清除純文字的備份。這個方法避免以每一要求的基礎存取資料存放區。
快取純文字的機密
避免多次解密機密造成負荷以及在記憶體中儲存機密的純文字備份。這是最不安全的方法,但是提供最佳化的效能。在推測額外取得的效能相對於增加的安全性風險是否值得之前,請評比其他的方法。
如果在網路上傳送機密資料給用戶端,加密資料或保障通訊通道的安全。一般的實作是在用戶端和 Web 伺服器之間使用 SSL。在伺服器之間,日益增加的常見作法是使用 IPSec。保障流經好幾個中間層的機密資料的安全,例如 Web 服務簡易物件存取通訊協定 (SOAP) 訊息,請使用訊息層級的加密。
避免在永續性的 Cookie 中儲存機密資料。如果儲存純文字資料,一般使用者將能夠看到和修改資料。如果加密資料,金鑰管理會是一個問題。例如,用來加密 Cookie 中資料的金鑰逾期並回收,新的金鑰就不能解密從用戶端的瀏覽器傳來的永續性 Cookie。
應該避免使用 HTTP-GET 通訊協定來儲存機密資料,因為這個通訊協定是使用查詢字串來傳送資料。使用查詢字串並不能保障機密資料的安全,而且查詢字串經常會被伺服器記錄。
Web 應用程式是建立在無狀態的 HTTP 通訊協定之上,所以工作階段管理是應用程式層級的責任。工作階段安全性是應用程式全面安全性的關鍵。
以下的做法可以加強 Web 應用程式的工作階段管理安全性:
| • | 使用 SSL 保護工作階段的驗證 Cookie。 |
| • | 加密驗證 Cookie 的內容。 |
| • | 限制工作階段存留期。 |
| • | 保護工作階段狀態免於遭到未授權存取。 |
不要在 HTTP 的連線上傳送驗證 Cookie。在驗證 Cookie 中設定安全的 Cookie 內容,指示瀏覽器只有在 HTTPS 的連線上才能將 Cookie 送回伺服器。如需詳細資訊,請參閱單元 10<建置安全的 ASP.NET 網頁和控制項>。
即使您使用 SSL,也請加密 Cookie 的內容。如果攻擊者經由 XSS 攻擊偷到 Cookie,這可防止他檢視或修改 Cookie。在這個事件中,攻擊者仍可以使用偷來的 Cookie 存取應用程式,但只限於 Cookie 的有效期間。
降低工作階段存留期以減輕連線劫持和重新執行攻擊的風險。工作階段越短,攻擊者擷取工作階段 Cookie 並用它存取應用程式的時間越少。
考慮如何儲存工作階段狀態。為了最佳化效能,可以將工作階段狀態儲存在 Web 應用程式的處理程序位址空間。然而,這個方法在 Web 伺服器陣列的狀況下擴充性和意義有限,因為來自同一使用者的要求不能保證是由相同的伺服器處理。在這個狀況下,需要在指定的狀態伺服器儲存不在處理程序中的狀態,或在共用資料庫儲存永續性的狀態。ASP.NET 支援全部的三種選項。
應該使用 IPSec 或 SSL 保障從 Web 應用程式到狀態存放區的網路連線的安全,以減輕竊聽的風險。同時也要考慮狀態存放區如何驗證 Web 應用程式。儘可能的使用 Windows 驗證以避免在網路上傳送純文字驗證憑證,並可受益於安全的 Windows 帳戶原則。
密碼編譯的基本形式提供下列功能:
| • | 隱私性 (機密性)。這個服務可讓機密保持秘密。 |
| • | 不可否認性 (驗證性)。這個服務可確保使用者不能否認送出特定的訊息。 |
| • | 防止竄改 (完整性)。這個服務防止資料被改變。 |
| • | 驗證。這個服務確認訊息傳送者的識別身份。 |
Web 應用程式通常會使用密碼編譯來保障資料在永續性存放區或當在網路上傳輸時的安全。以下的做法可以加強 Web 應用程式使用密碼編譯時的安全性:
| • | 不要自行開發密碼編譯。 |
| • | 保持未加密的資料儘量靠近演算法。 |
| • | 使用正確的演算法和正確的金鑰大小。 |
| • | 保障加密金鑰的安全。 |
加密演算式和常式難以開發成功是有名的。因此,應該使用平台所提供已嘗試和已測試過的加密服務。包括 .NET Framework 和基礎作業系統。不要發展自訂的加密實作,因為這些經常都會導致安全性不足的保護。
當傳送純文字到演算法時,在準備好要使用時再取得資料,同時儘可能以最少的變數來儲存。
確認針對工作選對了演算法是很重要的,並且確認所使用的金鑰大小提供足夠等級的安全性。較大的金鑰大小通常會增加安全性。下列的清單總結主要的演算法以及每個所使用金鑰的大小:
| • | Data Encryption Standard (DES) 64 位元金鑰 (8 位元組) |
| • | TripleDES 128 位元金鑰或 192 位元金鑰 (16 或 24 位元組) |
| • | Rijndael 128 256 位元金鑰 (16 32 位元組) |
| • | RSA 384 16,384 位元金鑰 (48 2,048 位元組) |
大型資料的加密,使用 TripleDES 對稱加密演算法。對大型資料較慢和增強式的加密,使用 Rijndael。若要加密短期儲存的資料,可以考慮使用較快但安全性不足的演算法例如 DES。對於數位簽章,使用 Rivest、Shamir、和 Adleman (RSA) 或數位簽章演算法 (DSA)。對於雜湊,使用安全雜湊演算法 (SHA)1.0。對於金鑰式 (Keyed) 雜湊,使用以雜湊為主的訊息驗證碼 (HMAC) SHA1.0。
加密金鑰是在加密和解密的過程用來當作輸入的機密數目。為了保持加密資料的安全必須保護金鑰。如果攻擊者入侵了解密金鑰,加密資料就不再安全了。
以下的做法可以協助保障加密金鑰的安全:
| • | 使用 DPAPI 以避免金鑰管理。 |
| • | 定期循環金鑰。 |
如同之前所提到的,使用 DPAPI 主要的好處是由作業系統來處理金鑰管理問題。DPAPI 所使用的金鑰是由關聯到名為 DPAPI 功能的處理程序帳戶的密碼所得到的。使用 DPAPI 將金鑰管理的負荷轉移給作業系統。
通常,在一段時間之後靜態金鑰比較可能被發現。要記得的問題是:您是否把它寫在某處?知道機密資料的系統管理員 Bob 在公司內是否已調職或已離開公司?請不要過度使用金鑰。
使用參數操作攻擊,攻擊者修改在用戶端和 Web 應用程式之間傳送的資料。包括使用查詢字串、表單欄位、Cookie、和 HTTP 標頭所傳送的資料。以下的做法可以協助保障 Web 應用程式的參數操作安全:
| • | 加密機密的 Cookie 狀態。 |
| • | 確認使用者不會跳過檢查。 |
| • | 驗證從用戶端送來所有的值。 |
| • | 不要信任 HTTP 標頭的資訊。 |
Cookie 可能包括機密資料,例如工作階段識別元或用於組成伺服器端授權處理程序部分的資料。若要保護這個類型的資料避免未授權操作,使用密碼編譯來加密 Cookie 的內容。
確認使用者不會經由操作參數來跳過檢查。一般使用者可經由瀏覽器的位址文字方塊來操作 URL 參數。例如,URL http://www.<您的網站>/<您的應用程式>/sessionId=10 有一個值 10 可以改變為其他的亂數來接受不同的輸出。確認有在伺服器端程式碼檢查,而不是檢查可在瀏覽器中停用的用戶端 JavaScript。
限制使用者可以輸入和修改的欄位,並且驗證所有來自用戶端的值。如果在表單欄位中有預先設定的值,使用者可以改變它們然後張貼回去以接收不同的結果。盡可能只允許已知正確的值。例如,如果輸入欄位是用於省,只有符合省的郵遞區號的輸入才能被允許。
在 HTTP 要求和 HTTP 回應時,一開始傳送的就是 HTTP 標頭。應該確認 Web 應用程式沒有根據 HTTP 標頭的資訊作出任何安全性決策,因為攻擊者很容易操作標頭。例如,標頭的「referer」欄位包含要求發源網頁的 URL。不要根據「referer」欄位的值作出任何安全性決策,例如,檢查要求是否來自 Web 應用程式所產生的網頁,因為該欄位太容易被竄改了。
安全的例外處理可以幫助防止某些應用程式層級的拒絕服務攻擊,也可以預防對攻擊者有用的重要系統層級資訊被回覆給用戶端。例如,沒有正確的意外處理,像資料庫架構詳細資料、作業系統版本、堆疊追蹤、檔案名稱和路徑資訊、SQL 查詢字串、和其他對攻擊者有用的貴重資訊就可能被回覆給用戶端。
一個好方法是設計集中例外管理和記錄解決方案,並且考慮在例外管理系統中提供陷阱,以支援測試設備和集中監控來協助系統管理員。
以下的做法可以協助保障 Web 應用程式例外管理的安全:
| • | 不要洩露資訊給用戶端。 |
| • | 記錄詳細的錯誤訊息。 |
| • | 捕捉例外。 |
在失敗的事件中,不要暴露會導致資料公開的資訊。例如,在偵錯版 (不應該用在產品伺服器) 的例子中不要暴露包括函數名稱和行數的堆疊追蹤詳細資料。替代的回覆一般性的錯誤訊息給用戶端。
傳送詳細的錯誤訊息給錯誤記錄檔。傳送給服務或應用程式的客戶最小的資訊,例如一般性的錯誤訊息和其後可對應到事件日誌中詳細訊息的客戶錯誤記錄識別碼。確認沒有記錄密碼或其他機密資料。
使用結構化的例外處理和捕捉例外狀況。如此作可以避免把應用程式留在不一致的狀態,而可能導致資料公開。也可以幫助保護應用程式免於拒絕服務的攻擊。決定在應用程式內部如何傳播例外,並特別考慮在應用程式界限會發生什麼。
有關對於 .NET 應用程式設計和執行例外管理架構的詳細資訊,請參閱 MSDN 文章,《Exception Management Architecture Guide (英文)》,網址為 http://msdn.microsoft.com/library/en-us/dnbda/html/exceptdotnet.asp。
應該稽核和記錄應用程式中跨階的活動。使用記錄檔,可以偵測看似可疑的活動。這通常可以對完全成熟的攻擊提供早期的徵兆,而且記錄也可以協助應付使用者否認他們行為的否認潛在威脅。記錄檔案需要有合法的程序來證明個體的不正當行為。如果稽核是在資源存取的準確時間而且是經由存取資源的相同常式所產生的,通常稽核被認為是最可靠的。
以下的做法可以加強 Web 應用程式的安全性:
| • | 稽核和記錄跨應用程式各階的存取。 |
| • | 考慮識別身份流量。 |
| • | 記錄關鍵事件。 |
| • | 保障記錄檔案的安全。 |
| • | 定期備份和分析記錄檔。 |
針對不可否認性稽核和記錄跨應用程式各階的存取。混合使用應用程式層級的記錄和平台稽核功能,例如 Windows、IIS、和 SQL Server 稽核。
考慮應用程式如何將呼叫者的識別身份流程跨應用程式的多個階層。有兩個基本的選擇。可以在作業系統層級使用 Kerberos 通訊協定委派來流動呼叫者的識別身份。這容許使用作業系統層級的稽核。這個方法的缺點是影響擴充性,因為在中間層缺乏有效的資料庫連結集區。或者,您可以在應用程式層級保留呼叫者的識別身份,然後使用受信任的識別身份來存取後端資源。使用這個方法,必須信任中間層而且有可能的否認風險。應該產生可以相互關聯到後端稽核記錄的中間層稽核記錄。為此,必須確認伺服器的時鐘同步化,雖然 Microsoft Windows 2000 和 Active Directory 已經為您做了這些。
應該記錄的事件類型包括成功和失敗的登入嘗試、資料修改、資料擷取、網路通訊、和管理功能例如啟用或停用記錄。記錄應該包括事件的時間、事件的位置包括機器名稱、現行使用者的識別身份、啟動事件的處理程序的識別身份、和事件的詳細說明。
使用 Windows ACL 和限制對記錄檔案的存取來保障記錄檔案的安全。如此使得攻擊者更難竄改記錄檔案來掩蓋他們的痕跡。將可以操作記錄檔案的個人數目最小化。僅對高度信任的帳戶授權存取,例如系統管理員。
如果記錄檔案從來沒有被分析過,那麼記錄活動就沒有意義了。記錄檔案應該定期從生產伺服器上移除。移除的頻率視應用程式層級的活動而定。設計時應該考慮到記錄檔案被擷取並移到離線伺服器進行分析的方式。在 Web 伺服器上為此目的所開啟的任何額外的通訊協定和連接埠都必須安全地鎖定。
[表 4.1] 總結本單元中討論的的設計指導方針,並且使用應用程式弱點類別來將它們組織分類。
[表 4.1] 應用程式的設計指導方針
| 類別 | 指導方針 |
輸入驗證 | 不要信任輸入;考慮集中式輸入驗證。 |
驗證 | 將站台劃分為匿名、已識別、和已驗證區域。使用增強式密碼。支援密碼到期日和帳戶停用。不要儲存憑證 (使用單向雜湊合併 salt 值)。加密通訊通道來保護驗證權杖。只有在 HTTPS 連線上才傳送表單驗證 Cookie。 |
授權 | 使用最小權限帳戶。考量授權細微性。強制權限的分離。限制使用者存取系統層級的資源。 |
設定管理 | 使用最小權限處理序和服務帳戶。不要以純文字儲存憑證。在管理介面使用增強式驗證和授權。不要使用 LSA。保障遠端管理通訊通道的安全。避免在 Web 空間儲存機密資料。 |
機密資料 | 避免儲存機密資料。透過網路傳輸機密資料時要進行加密。保障通訊通道的安全。在機密資料存放區提供增強式的存取控制。不要在永續性的 Cookie 中儲存機密資料。不要使用 HTTP-GET 通訊協定來傳送機密資料。 |
工作階段管理 | 限制工作階段存留期。保障通道的安全。加密驗證 Cookie 的內容。保護工作階段狀態免於遭到未授權存取。 |
密碼編譯 | 不要自行開發加密。使用嘗試及測試平台功能。保持未加密的資料儘量靠近演算法。使用正確的演算法和金鑰大小。避免金鑰管理 (使用 DPAPI)。定期循環金鑰。將金鑰儲存在限制的位置。 |
參數操作 | 加密機密的 Cookie 狀態。不要信任用戶端可以操作的欄位 (查詢字串、表單欄位、Cookie、或 HTTP 標頭)。驗證從用戶端送來所有的值。 |
例外管理 | 使用結構化例外處理。不要洩露機密應用程式執行的詳細資料。不要記錄隱私的資料,例如密碼。考慮集中式的例外管理架構。 |
稽核和記錄 | 識別惡意的行為。知道正確的資料傳輸看起來是怎麼樣。經由應用程式所有的階層稽核和記錄活動。保障記錄檔案存取的安全。備份和定期分析記錄檔。 |
安全性應該普及到產品開發生命週期的每一階段,而且應該是應用程式設計的焦點。特別注意到堅固的驗證和授權策略的設計。同時記住大多數應用程式層級的攻擊是依賴惡意格式輸入資料和不良的應用程式輸入驗證。在本單元顯示的指南會幫助您克服這些,和其他對設計和建置安全的應用程式方面的挑戰。
有關其他詳細資訊,請參閱下列資源:
| • | 目前的指南是一系列專門用來幫助客戶加強網頁應用程式安全性書籍的第二冊。有關架構、設計、建置、和設定驗證、授權、和在分散式 Web 應用程式保障各階間通訊的安全的詳細資料,請參閱《Microsoft patterns & practices Volume I, 建置安全的 ASP.NET 應用程式: 驗證、授權和安全通訊》,網址為 http://www.microsoft.com/taiwan/msdn/books/ataglance/secnetlpMSDN.htm。 |
| • | MSDN 文章《Security Models for ASP.NET Applications(英文)》,網址為 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/SecNetch02.asp?frame=true。 |
| • | MSDN 文章《Designing Authentication and Authorization(英文)》,網址為 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/SecNetch03.asp?frame=true。 |
| • | "本指南<檢查清單>章節中的<檢查清單:架構及設計檢閱>。 |