程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> vc教程 >> 解決兩個難懂的安全性問題

解決兩個難懂的安全性問題

編輯:vc教程

  經常討論一些您發現的少量錯誤並讓人們知道它們是很有益的。在本月的專欄中,我想討論兩個主題:

  交互式服務

  調用 _alloca()

  安全性、服務和交互式桌面

  與 Unix 守護程序類似,服務是 Microsoft Windows NT 的中樞,可以向操作系統和用戶提供重要功能而無需用戶的參與。創建服務時,有一些問題需要注意。

  Microsoft Windows 中的服務通常是控制台應用程序,它們的運行無需用戶參與,也沒有用戶界面。但在某些實例中,服務可能需要與用戶進行交互。運行在較高安全環境中的服務(如 SYSTEM)不應作為交互式服務運行。在 Windows 用戶界面中,桌面是安全邊界,在交互式桌面上運行的任何應用程序可以與交互式桌面上的任何窗口交互,即使窗口並不可見。無論創建窗口的應用程序的安全環境和應用程序的安全環境如何,都是這樣。

  由於這些設計特點,任何在交互式桌面上打開窗口的服務都會向登錄用戶所執行的應用程序公開。如果服務試圖使用窗口消息控制其功能,則登錄用戶可以通過使用惡意消息來干擾該功能。

  將服務作為 SYSTEM 運行的做法(即,服務通過調用 OpenWindowStation 和 GetThreadDesktop 來支持交互式桌面)十分不可取。請注意,Windows 將來的版本可能會完全取消對交互式服務的支持。

  我們建議服務編寫人員使用客戶端/服務器技術(例如 RPC、套接字、命名管道或 COM)實現與來自某個服務的登錄用戶的交互,使用帶 MB_SERVICE_NOTIFICATION 的 MessageBox 顯示簡單的狀態。如果您的服務代碼具有以下任何屬性,請提高警惕:

  作為 LocalSystem 運行,並且服務在安全配置管理器中進行了標記(“登錄為”->“允許服務與桌面交互”),或注冊表項 -> HKLMCCSServicesMyServiceType & 0x0100 == 0x0100)

  CreateService,並且 dwServiceType & SERVICE_INTERACTIVE_PROCESS == SERVICE_INTERACTIVE_PROCESS

  調用 MessageBox(),其中 uType and (MB_DEFAULT_DESKTOP_ONLY | MB_SERVICE_NOTIFICATION | MB_SERVICE_NOTIFICATION_NT3X) != 0

  調用 OpenDesktop("winsta0",...) 並在該桌面上創建用戶界面

  在 OpenDesktop 上調用 LoadLibrary/GetProcAddress

  小心 _alloca

  _alloca 函數可以在堆棧中分配動態內存。分配的空間將在調用函數退出時自動釋放,而不只是在分配超出范圍時釋放。下面是使用 _alloca 的示例代碼:

void function(char *szData) {
  PVOID p = _alloca(lstrlen(szData));
  // 使用 p
}

  如果攻擊者提供一個比堆棧大小還要長的 szData,_alloca 會引發一個異常並導致應用程序停止。如果該代碼位於服務器中,則情況會更糟。處理這種錯誤情況的正確方法是將對 _alloca 的調用打包在異常處理程序中,並在出現錯誤時重置堆棧。

void function(char *szData) {
  __try {
    PVOID p = _alloca(lstrlen(szData));
    // 使用 p
  } __except ((EXCEPTION_STACK_OVERFLOW == GetExceptionCode()) ?
          EXCEPTION_EXECUTE_HANDLER :
          EXCEPTION_CONTINUE_SEARCH) {
    _resetstkoflw();
  } 
}

 相關問題:ATL 轉換宏

  您還應當小心某些調用 _alloca 的 ATL 字符串轉換宏。這些宏包括 A2W、W2A 和 CW2CT 等。如果您的代碼是服務器代碼,則調用其中任何轉換函數時都必須考慮數據的長度。這是不要輕易相信輸入的又一個示例。如果攻擊者向您的代碼提供一個 10 MB 的字符串,便會摧毀堆棧並引發異常;或者如果未引發異常,則導致失敗。所以千萬不要這樣做!

  發現缺陷

  沒有人看出上星期的代碼中的錯誤,但很多人已接近目標。其中的問題是為明文和密文使用了相同的緩沖區。您永遠都不能這樣做。

  乍看起來,使用相同的緩沖區存儲明文,然後加密明文產生的密文似乎很好。在大多數情況下也是這樣。但在多線程環境中就不是這樣了。設想一下,您的代碼中出現了一個“競爭狀態”,而您卻並不知道。(競爭狀態是由對軟件中的事件的相對時間產生意外的嚴格依賴而引起的。它們通常與同步錯誤一起出現。)坦白地說,您永遠不會知道存在著嚴重的競爭狀態,等知道時已經太晚了。請再考慮一下,您的應用程序的正常流程如下所示:

  使用明文加載緩沖區。

  加密緩沖區。

  將緩沖區內容發送給接收者。

  這看起來很正常。但是,設想您有一個多線程應用程序,由於某種原因,最後兩個步驟由於競爭狀態而被交換:

  使用明文加載緩沖區。

  將緩沖區環境發送給接收者。

  加密緩沖區。

  接收者只接收到一些明文!這是在 Internet Information Server 4.0 中修復的一個錯誤。在非常特殊的負載和極少數情況下,當使用安全套接字層 (SSL) 保護從服務器至用戶的數據通道時,服務器可能會遵循此模式,並將一個未加密的數據信息包發送給用戶。這種潛在問題的破壞很小;只向用戶(或者可能是一個攻擊者)發送了一個信息包。並且當用戶接收到信息包時,客戶端軟件將斷開連接。據說該問題已被 Microsoft 修復了。有關該缺陷的詳細信息,請訪問 http://www.microsoft.com/technet/treevIEw/default.asp?url=/technet/security/bulletin/ms99-053.ASP(英文)。


  修復的方法是使用兩個緩沖區。一個緩沖區用於明文,另一個用於密文,並確保密文在執行不同調用時已被清空。

  您能指出此代碼中的錯誤嗎?

void ShuffleAndUpdate(char *szName, char *szPwd, 
        DWord index,
        DWord d) {
  DWord dwArray[32]; 
  ZeroMemory(dwArray,sizeof(dwArray));
  BOOL fAllowAccess = FALSE;
  if (IsValidUser(szName,szPwd)) {
   fAllowAccess = TRUE;
   ShuffleArray(dwArray,szName);
     }
  dwArray[index]= d;
  if (fAllowAccess) {
   // 執行某些敏感的操作
  }
}

  Michael Howard 是 Microsoft 的 Secure Windows Initiative 組的安全程序經理,是 Writing Secure Code 的作者之一,也是 Designing Secure Web-based for Applications for Windows 2000 的主要作者。他的主要工作就是確保人們設計、構建、測試和記錄無缺陷的安全系統。他最喜歡的話是“尺有所短,寸有所長”。

  1. 上一頁:
  2. 下一頁:
欄目導航
Copyright © 程式師世界 All Rights Reserved