托管平台的可安全中立的互斥类






3.93/5 (6投票s)
2006年5月5日
4分钟阅读

39897

174
一篇关于可在任何托管平台上使用的安全中立互斥体类的文章。
引言
本文旨在向您介绍一个新的托管互斥体类 MutexSecurityNeutral
。现有的 .NET 框架提供的 System.Threading.Mutex
类存在一个限制,即只能使用一个安全上下文,也就是创建它的那个上下文。一旦在特定的安全上下文中创建,就无法在不同的用户/安全上下文中打开/创建它。这里提供了一个针对此问题的解决方案——MutexSecurityNeutral
类。
基本思想是通过指定具有空 DACL 的安全描述符来创建一个 Win32 内核互斥体对象。安全描述符中的空 DACL 意味着 **“所有人均可访问”**。好吧,我承认使用空 DACL 创建内核对象确实可能成为拒绝服务 (DoS) 攻击的入口点。是否使用此方法完全取决于您和您系统的安全关键性。
背景
不久前,我的一位朋友在 Web 应用程序中创建互斥体对象时遇到了“访问被拒绝”的错误。这个 ASP.NET – C# Web 应用程序使用的是 Windows 身份验证,并且 `Impersonation` 设置为 true
。如果 `Impersonation` 设置为 false
,则相同的代码可以正常工作。
问题原因分析
当 ASP.NET 应用程序在 Windows 身份验证下运行,并且 `Impersonation` 设置为 true
时,ASP.NET 工作进程 aspnet_wp.exe 将以登录用户的上下文运行。但如果 `Impersonation` 设置为 false
,则被模拟的用户上下文将始终是系统用户 ASPNET。
因此,在 `Impersonation` 设置为 true
的 Windows 身份验证场景中,当第一个请求来自用户(例如 domain1\user1)时,互斥体对象将在 domain1\user1 的上下文中创建。如果下一个请求(发送到 inetinfo.exe,然后是 aspnet_wp.exe)来自同一用户,则不会有问题,因为上下文相同。但如果请求来自另一用户(例如 domain1\user2),则问题会升级。在这种情况下,.aspx 页面将在 domain1\user2 的上下文中运行。然后,互斥体对象的创建将失败,因为已存在的互斥体对象关联的安全描述符属于 domain\user1。IIS、ASP.NET 和 Windows 安全模型的详细阐述超出了本文档的范围。CP 上有许多关于此主题的文章。此外,我正在编写一系列关于 Windows 安全模型和互联网的文章。完成后,我会在此处更新。
尽管 .NET 2.0 提供了 `System.Security.AccessControl.MutexSecurity` 等一套新的 Win32 安全模型封装类,但其对象模型不允许将空的 ACE 添加到 DACL 中。其设计目标之一是防止用户创建不安全的内核对象。这时 MutexSecurityNeutral
这个安全中立的托管类型就派上用场了。由于安全描述符使用空 DACL 进行初始化,因此它可以在任何用户上下文中创建。
作为替代方案,如果不需要进程间同步,我们也可以使用 .NET 的 lock
块。
使用代码
MutexSecurityNeutral
类可以使用方式与 .NET 的 Mutex
类相同。在项目中引用 MutexSecurityNeutral.dll。下面是一个同步共享资源的 C# 示例代码。
SecUtil.MutexSecurityNeutral mutexsecurityneutral =
new SecUtil.MutexSecurityNeutral("yourmutexname");
mutexsecurityneutral.WaitOne();
nSharedResource++;
mutexsecurityneutral.Done();
下面展示了 MutexSecurityNeutral
的实现。
namespace SecUtil
{
public __gc class MutexSecurityNeutral
{
private:
CMutexSecurityNeutralUnmanaged*
m_CMutexSecurityNeutralUnmanaged;
String __gc* m_MutexName;
public:
MutexSecurityNeutral(String __gc* MutexName):
m_MutexName(MutexName){
m_CMutexSecurityNeutralUnmanaged = NULL;
}
~MutexSecurityNeutral(){
delete m_CMutexSecurityNeutralUnmanaged;
}
bool WaitOne(){
char __nogc* szMutexname =
static_cast<CHAR *>(Marshal::StringToHGlobalAnsi(
m_MutexName).ToPointer());
m_CMutexSecurityNeutralUnmanaged = new
CMutexSecurityNeutralUnmanaged(szMutexname);
bool bRtn= m_CMutexSecurityNeutralUnmanaged->WaitOne();
Marshal::FreeHGlobal( IntPtr((void*)szMutexname));
return bRtn;
} bool
Done(){ returnm_CMutexSecurityNeutralUnmanaged->Done();
}
};
}
SecurityNeutralUnmanaged
有两个方法。
WaitOne()
在
wait()
方法中,它创建CMutexSecurityNeutralUnmanaged
对象,并将互斥体名称传递给非托管的wait()
方法。Done()
调用非托管的
CMutexSecurityNeutralUnmanaged->Done()
方法。此CMutexSecurityNeutralUnmanaged
在 MutexSecurityNeutral.h 中声明。
class CMutexSecurityNeutralUnmanaged
{
private:
const char* m_szMutexName;
HANDLE m_hMutex;
public:
CMutexSecurityNeutralUnmanaged(const char*
szMutexName):m_szMutexName(szMutexName){
m_hMutex = NULL;
}
~CMutexSecurityNeutralUnmanaged(){
}
bool WaitOne(){
bool rtn = false;
SECURITY_DESCRIPTOR sd;
SECURITY_ATTRIBUTES sa;
try{
if (!InitializeSecurityDescriptor(&sd,
SECURITY_DESCRIPTOR_REVISION))
return FALSE;
if (!SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE))
return FALSE;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = &sd;
sa.bInheritHandle = FALSE;
m_hMutex = CreateMutex(&sa, true, m_szMutexName);
WaitForSingleObject( m_hMutex, 10000L);
rtn = true;
}
catch(...){
rtn = false;
}
return rtn;
}
bool Done(){
bool rtn = false;
try{
ReleaseMutex(m_hMutex);
CloseHandle(m_hMutex);
rtn = true;
}
catch(...){
rtn = false;
}
return rtn;
}
};
SecurityNeutralUnmanaged
类有两个方法。
WaitOne()
此方法创建
SECURITY_DESCRIPTOR
变量,并通过调用SetSecurityDescriptorDacl
为其关联一个空 DACL。然后,它调用CreateMutex
来创建互斥体对象,并使用WaitForSingleObject
等待互斥体句柄。Done()
此方法仅释放互斥体并关闭句柄。
摘要
所有 Win32 内核对象都与特定的用户/安全上下文相关联。因此,对于在特定用户安全上下文中创建的 Win32 互斥体对象,它无法在不同的用户上下文中重新创建/打开。换句话说,这些内核对象具有用户亲和性。在桌面应用程序场景中,这可能不是问题,因为所有程序通常都在登录用户的上下文中运行,除非通过编程进行模拟。但如果我们 Web 应用程序场景中使用互斥体之类的内核对象,并且 `Impersonation` 设置为 true
,情况就不同了。这确实会带来麻烦。
那么,作为 Web 开发人员,这个内核对象的“用户亲和性”对您有什么影响?.NET 提供了(1.1 和 2.0 版本都有)System.Threading.Mutex
类,但它不能在具有 Windows 身份验证且 `Impersonation` 设置为 true
的 Web 应用程序中使用。对象创建将以“访问被拒绝”错误失败。作为替代方案,您可以使用 MutexSecurityNeutral
类,但它存在使用空 DACL 的安全漏洞。我再次强调,是否使用此类完全取决于您自己决定。
修订历史
- 2006 年 5 月 5 日 - 版本 1.0 - 首次发布。