如何获取文件有效权限?win32security等工具使用遇阻求助
要实现和PowerShell Get-EffectiveAccess 完全一致的效果,最优的方式是基于Windows原生的ACL权限计算逻辑,结合Python的win32security库来处理——核心是正确构造TRUSTEE参数,同时考虑用户的所有身份(包括嵌套组)和权限优先级(拒绝权限优先)。下面一步步拆解解决你的问题:
1. 解决PyTRUSTEE参数的配置问题
GetEffectiveRightsFromAcl需要的TRUSTEE对象其实是Windows原生的结构体,在win32security里可以直接实例化并配置关键属性:
TrusteeForm:指定主体的标识形式,常用TRUSTEE_IS_NAME(用用户名/组名)或TRUSTEE_IS_SID(用SID字符串)TrusteeType:指定主体类型,用户用TRUSTEE_IS_USER,组用TRUSTEE_IS_GROUP,未知类型用TRUSTEE_IS_UNKNOWNptstrName:对应的用户名(如DOMAIN\Username)或SID字符串
2. 基础版实现:单用户/组的有效权限计算
先从基础的单主体权限计算开始,这个方法可以直接得到指定用户对文件的有效权限,和Get-EffectiveAccess的核心逻辑对齐:
import win32security def get_single_principal_effective_perms(file_path, principal_name): # 获取文件的DACL(自由访问控制列表) sd = win32security.GetFileSecurity( file_path, win32security.DACL_SECURITY_INFORMATION ) dacl = sd.GetSecurityDescriptorDacl() # 构造TRUSTEE对象 trustee = win32security.TRUSTEE() trustee.TrusteeForm = win32security.TRUSTEE_IS_NAME # 根据主体类型调整:用户用TRUSTEE_IS_USER,组用TRUSTEE_IS_GROUP trustee.TrusteeType = win32security.TRUSTEE_IS_USER trustee.ptstrName = principal_name # 定义要查询的全量文件权限掩码 full_file_access = win32security.FILE_ALL_ACCESS # 调用API计算有效权限 granted_access, access_status = win32security.GetEffectiveRightsFromAcl( dacl, trustee, full_file_access ) # 把权限掩码转换成可读名称 permission_map = { win32security.FILE_READ_DATA: "读取数据", win32security.FILE_WRITE_DATA: "写入数据", win32security.FILE_APPEND_DATA: "追加数据", win32security.FILE_EXECUTE: "执行", win32security.DELETE: "删除", win32security.READ_CONTROL: "读取权限", win32security.WRITE_DAC: "修改权限", win32security.WRITE_OWNER: "获取所有权", # 可以添加更多权限项覆盖所有场景 } granted_perms = [name for mask, name in permission_map.items() if granted_access & mask] return { "主体": principal_name, "有效权限": granted_perms, "状态": "成功" if access_status == 0 else "权限计算失败" } # 使用示例 print(get_single_principal_effective_perms("C:\\temp\\test.txt", "WORKGROUP\\YourUsername"))
3. 进阶版:完全匹配Get-EffectiveAccess的效果
Get-EffectiveAccess会自动考虑用户的所有身份(用户本身、直接组、嵌套组、权限组等),并且遵循拒绝权限优先的规则。要实现这个,你需要:
- 获取用户的所有有效SID(包括用户SID和所有组SID,含嵌套)
- 对每个SID分别计算权限
- 合并权限时,先处理拒绝项,再合并允许项
这里给出核心的身份枚举逻辑:
import win32api import win32security def get_user_all_sids(username): # 获取用户的SID sid, domain, type = win32security.LookupAccountName(None, username) sids = [sid] # 获取用户所属的所有组(包括嵌套组) token = win32security.OpenProcessToken( win32api.GetCurrentProcess(), win32security.TOKEN_QUERY ) groups = win32security.GetTokenInformation(token, win32security.TokenGroups) for group in groups: sids.append(group[0]) # 去重SID unique_sids = list(set(sids)) # 转换为可读的SID字符串 return [win32security.ConvertSidToStringSid(sid) for sid in unique_sids]
之后你可以遍历所有SID,分别调用基础版的权限计算函数,再按照Windows权限规则合并结果(拒绝权限会覆盖同类型的允许权限)。
4. 避免审核失败的注意事项
你提到用Authz.h时出现审核失败,这是因为Authz系列函数需要更高的权限,且会触发Windows的审核策略(比如对令牌操作的审核)。而GetEffectiveRightsFromAcl是直接基于ACL的静态计算,不会涉及令牌操作,因此几乎不会触发审核失败,是更轻量可靠的选择。
至于Aclapi.h的GetEffectiveRightsFromAcl,它和win32security封装的是同一个API,局限性在于单次只能计算一个主体的权限,所以需要自己处理多身份的合并逻辑——这也是进阶版实现要解决的点。
内容的提问来源于stack exchange,提问作者Valeria

