37、异步 I/O、完成端口与 Windows 对象安全

异步 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 函数可以获取进程的用户账户名(即登录用户),用户名和长度以常规方式返回。

创建和管理 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 完成端口,以及如何更精细地设置安全权限以满足不同的安全需求。同时,也可以研究不同操作系统之间的兼容性和互操作性,以便在跨平台开发中更好地应用这些技术。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值