异步 I/O、完成端口与 Windows 对象安全
1. 异步 I/O 与完成端口
在创建可扩展服务器时,有多种实现异步 I/O 的方法。
-
线程方法
:线程提供了最通用和简单的技术。每个线程负责一个或多个顺序的、阻塞的 I/O 操作序列,并且每个线程应该有自己的文件或管道句柄。
-
重叠 I/O
:允许单个线程对单个文件句柄执行异步操作,但每个操作必须有一个事件句柄,而不是线程和文件句柄对。需要专门等待每个 I/O 操作完成,然后执行任何所需的清理或排序操作。
-
扩展 I/O
:自动调用完成代码,并且不需要额外的事件。
重叠 I/O 的一个重要优势是能够创建 I/O 完成端口。以下是一个使用 I/O 完成端口的服务器示例:
修改后的程序创建了一个小的服务器线程池和一个较大的重叠管道句柄池,每个句柄都有一个完成键。重叠句柄被添加到完成端口并发出调用,服务器线程等待与客户端连接和读取操作相关的完成事件。读取操作检测到后,处理相关的客户端请求并将结果返回给客户端。
客户端管道会经历一系列的状态,这些状态存储在每个管道的特定结构中,具体如下:
1.
连接状态
:管道与服务器线程连接。
2.
读取请求状态
:服务器线程从客户端读取请求,并从单独的“计算”线程启动处理过程,该计算线程在处理完成时调用
PostQueuedCompletionStatus
。由于进程管理在计算线程中,服务器线程不会阻塞。
3.
读取临时文件记录状态
:服务器线程读取包含响应第一条记录的第一个临时文件记录,然后将该记录写入客户端。
4.
发送额外响应记录状态
:服务器线程一次发送一条额外的响应记录,直到最后一条响应记录发送给客户端,然后返回读取请求状态。
5.
发送终止记录状态
:服务器线程向客户端发送一个终止的空记录。
下面是客户端管道状态的 mermaid 流程图:
graph LR
A[连接状态] --> B[读取请求状态]
B --> C[读取临时文件记录状态]
C --> D[发送额外响应记录状态]
D -->|最后一条记录发送| E[发送终止记录状态]
D -->|非最后一条记录| B
2. 不同系统的异步 I/O 支持
不同操作系统对异步 I/O 的支持有所不同:
| 操作系统 | 异步 I/O 支持情况 |
| ---- | ---- |
| Windows | 支持线程、重叠 I/O 和扩展 I/O 三种异步 I/O 方法 |
| UNIX(Pthreads) | 通过 Pthreads 支持线程 |
| System V UNIX | 异步 I/O 仅限于流,不能用于文件或管道操作 |
| BSD Version 4.3 | 使用信号组合来指示文件描述符上的事件,并使用
select
函数确定文件描述符的就绪状态,仅适用于终端和网络通信 |
3. Windows 对象安全概述
Windows 支持全面的安全模型,可防止对文件、进程和文件映射等对象的未经授权访问。程序可以使用 Windows 安全 API 来保护对象,以下是相关的关键概念和操作步骤。
3.1 安全属性
几乎任何使用系统调用创建的对象都有一个安全属性参数。要实现安全,需要在系统调用中包含
SECURITY_ATTRIBUTES
结构,其中重要的元素是
lpSecurityDescriptor
,它是指向安全描述符的指针,描述对象的所有者并确定哪些用户被允许或拒绝各种权限。
一个单独的进程由其访问令牌标识,该令牌指定了所属用户和组的成员身份。当进程尝试访问对象时,Windows 内核可以使用令牌确定进程的身份,并根据安全描述符中的信息决定该进程是否具有访问该对象的所需权限。
3.2 安全描述符
安全描述符使用
InitializeSecurityDescriptor
函数初始化,它包含以下内容:
-
所有者安全标识符(SID)
:标识对象的所有者。
-
组 SID
:标识对象所属的组。
- ** discretionary 访问控制列表(DACL)
:一个明确授予和拒绝访问权限的条目列表。
-
系统 ACL(SACL)**:有时称为“审计访问 ACL”,控制程序访问可安全对象时的审计消息生成,需要系统管理员权限才能设置。
下面是构建安全描述符的步骤列表:
1. 初始化安全描述符:
InitializeSecurityDescriptor
2. 设置安全描述符的所有者:
SetSecurityDescriptorOwner
3. 设置安全描述符的组:
SetSecurityDescriptorGroup
4. 初始化 ACL:
InitializeAcl
5. 添加访问拒绝 ACE:
AddAccessDeniedAce
6. 添加访问允许 ACE:
AddAccessAllowedAce
7. 设置安全描述符的 DACL:
SetSecurityDescriptorDacl
这些步骤可以用以下 mermaid 流程图表示:
graph LR
A[InitializeSecurityDescriptor] --> B[SetSecurityDescriptorOwner]
B --> C[SetSecurityDescriptorGroup]
C --> D[InitializeAcl]
D --> E[AddAccessDeniedAce]
D --> F[AddAccessAllowedAce]
E --> G[SetSecurityDescriptorDacl]
F --> G
3.3 访问控制列表(ACL)
每个 ACL 是一组访问控制条目(ACE),有两种类型的 ACE:允许访问和拒绝访问。
初始化 ACL 后,可以使用
AddAccessDeniedAce
和
AddAccessAllowedAce
函数添加 ACE。每个 ACE 包含一个 SID 和一个访问掩码,指定要授予或拒绝给由 SID 指定的用户或组的权限。
可以使用
DeleteAce
函数移除 ACE,使用
GetAce
函数检索 ACE。
通过这些步骤和方法,可以有效地使用 Windows 安全 API 来保护对象,防止未经授权的访问。
异步 I/O、完成端口与 Windows 对象安全
4. 安全标识符(SIDs)
Windows 使用 SIDs 来识别用户和组。程序可以从账户名查找 SID,账户可以是用户、组、域等,甚至可以在远程系统上。
-
获取 SID 的步骤
:
1. 确定系统和账户名,参数
lpSystemName
和
lpAccountName
分别指向它们,通常
lpSystemName
为
NULL
表示本地系统。
2. 提供一个足够大的缓冲区来存储返回的 SID 信息,其大小为
cbSid
。如果缓冲区不够大,函数会失败并返回所需的大小。
3. 提供一个长度为
cchReferencedDomainName
字符的字符串,长度参数应初始化为缓冲区大小,用于存储返回的域名信息。
4. 指向一个
SID_NAME_USE
(枚举类型)变量的指针
peUse
,可用于测试各种值,如
SidTypeUser
、
SidTypeGroup
等。
| 参数 | 描述 |
|---|---|
lpSystemName
|
系统名,通常为
NULL
表示本地系统
|
lpAccountName
| 账户名 |
cbSid
| 存储 SID 信息的缓冲区大小 |
cchReferencedDomainName
| 存储域名信息的字符串长度 |
peUse
|
指向
SID_NAME_USE
变量的指针
|
-
获取账户和用户名
:
-
已知 SID 时,可以使用
LookupAccountSid函数反向获取账户名。 -
使用
GetUserName函数可以获取进程的用户账户名(即登录用户),用户名和长度以常规方式返回。
-
已知 SID 时,可以使用
创建和管理 SIDs 可以使用
AllocateAndInitializeSid
和
FreeSid
等函数,但示例主要使用从账户名获取的 SIDs。
5. 管理 ACLs
管理 ACLs 包括初始化 ACL 结构、将 ACL 与安全描述符关联以及添加 ACE 等操作。
5.1 初始化 ACL
首先要初始化一个 ACL 结构,虽然其内部结构不相关,但程序需要提供一个缓冲区作为 ACL,由函数来管理其内容。
InitializeAcl(pAcl, dwAclSize, ACL_REVISION);
其中
pAcl
是程序员提供的缓冲区地址,大小为
dwAclSize
字节,通常 1KB 对于大多数情况足够。
ACL_REVISION
是固定值。
5.2 添加 ACE
初始化 ACL 后,按照所需顺序使用
AddAccessDeniedAce
和
AddAccessAllowedAce
函数添加 ACE。
AddAccessDeniedAce(pAcl, ACL_REVISION, dwAccessMask, pSid);
AddAccessAllowedAce(pAcl, ACL_REVISION, dwAccessMask, pSid);
pAcl
指向之前初始化的 ACL 结构,
dwAccessMask
是访问掩码,确定要授予或拒绝给由
pSid
指定的用户或组的权限。
5.3 关联 ACL 与安全描述符
最后一步是将 ACL 与安全描述符关联。对于 discretionary ACL,使用
SetSecurityDescriptorDacl
函数。
SetSecurityDescriptorDacl(pSecurityDescriptor, TRUE, pAcl, FALSE);
pSecurityDescriptor
指向相应的安全描述符,
pAcl
是 ACL 的地址。
下面是管理 ACLs 的 mermaid 流程图:
graph LR
A[InitializeAcl] --> B[AddAccessDeniedAce]
A --> C[AddAccessAllowedAce]
B --> D[SetSecurityDescriptorDacl]
C --> D
6. 对象访问与权限
对象(如文件)在创建时会获得其安全描述符,程序也可以在稍后更改该描述符。
-
访问请求
:进程使用系统调用(如
CreateFile
)请求对象句柄时,会在参数中包含所需的访问权限(如
GENERIC_READ
)。如果安全描述符授予该进程访问权限,则请求成功。同一对象的不同句柄可能具有不同的访问权限。
-
权限设置
:在创建 ACL 时,允许和拒绝权限的访问标志值相同。
与标准 UNIX 相比,Windows 的安全模型更全面,UNIX 仅限于文件并基于文件权限,而本章的示例程序模拟了 UNIX 权限。
7. 总结与展望
通过上述内容,我们了解了异步 I/O 和完成端口的相关知识,以及 Windows 对象安全的关键概念和操作步骤。在实际应用中,根据不同的需求和场景,可以选择合适的异步 I/O 方法和安全策略来优化程序性能和保护对象安全。
对于异步 I/O,可以根据编程的简单性和性能要求选择线程、重叠 I/O 或扩展 I/O 方法。而在 Windows 对象安全方面,通过合理设置安全描述符、ACL 和 SIDs 等,可以有效地防止未经授权的访问。
未来,可以进一步探索这些技术在不同应用场景中的优化和扩展,例如在处理大量客户端请求时如何更好地利用 I/O 完成端口,以及如何更精细地设置安全权限以满足不同的安全需求。同时,也可以研究不同操作系统之间的兼容性和互操作性,以便在跨平台开发中更好地应用这些技术。
超级会员免费看
1327

被折叠的 条评论
为什么被折叠?



