锐英源软件
第一信赖

精通

英语

开源

擅长

开发

培训

胸怀四海 

第一信赖

当前位置:锐英源 / 开源技术 / C++API和类开源 / Windows访问控制模型的确保自己的类安全
服务方向
人工智能数据处理
人工智能培训
kaldi数据准备
小语种语音识别
语音识别标注
语音识别系统
语音识别转文字
kaldi开发技术服务
软件开发
运动控制卡上位机
机械加工软件
软件开发培训
Java 安卓移动开发
VC++
C#软件
汇编和破解
驱动开发
联系方式
固话:0371-63888850
手机:138-0381-0136
Q Q:396806883
微信:ryysoft

Windows访问控制模型的确保自己的类安全


18. Making Your Own Classes Secure确保自己的类安全

Q. This security descriptor model seems cool. Is there anyway I can use this to secure my own objects?问:此安全描述符模型看起来很酷。无论如何,我可以使用它来保护自己的对象吗?

It is possible to have a class member that has type PSECURITY_DESCRIPTOR to secure access to your object. If you want to make your security descriptor writable, you'll have to add special logic to your property functions. In particular when updating, you are expected to merge the new security descriptor into the current security descriptor.

You can use your own logic to manage the security descriptors (it will be easier to manage in SDDL form). Or you can make use of a special API, CreatePrivateObjectSecurity(), to do it for you. First, you must decide which methods of your class you want to restrict (you can restrict up to 16 methods per security descriptor). These methods must include generic actions specified in the GENERIC_MAPPING structure (even if you don't support them—just provide empty methods in this case).

The class given in the Platform SDK sample defines the actions in fig. 26 as part of its private object. Not only should the class map its own methods to these actions, it should map a GENERIC_MAPPING structure onto this structure (without this GENERIC_MAPPING structure, the AccessCheck() function will not work).

可能有一个类成员,其类型PSECURITY_DESCRIPTOR可以保护对您的对象的访问。如果要使安全描述符可写,则必须在属性函数中添加特殊的逻辑。特别是在更新时,您应该将新的安全描述符合并到当前的安全描述符中。

您可以使用自己的逻辑来管理安全描述符(以SDDL形式进行管理将更加容易)。或者,您可以使用特殊的APICreatePrivateObjectSecurity()来为您完成此任务。首先,必须确定要限制类的哪些方法(每个安全描述符最多可以限制16个方法)。这些方法必须包括GENERIC_MAPPING结构中指定的通用操作(即使您不支持它们,在这种情况下也请提供空方法)。

Platform SDK示例中提供的类定义了图5中的动作。26作为其私有对象的一部分。该类不仅应将其自身的方法映射到这些动作,还应将一个GENERIC_MAPPING结构映射到该结构(没有该GENERIC_MAPPING结构,该AccessCheck()函数将无法工作)。

ACCESS_READ// ==1 <-- GENERIC_MAPPING::GenericRead
ACCESS_MODIFY// ==2 <-- GENERIC_MAPPING::GenericWrite
ACCESS_DELETE // ==4
ACCESS_ALL// ==7 <-- GENERIC_MAPPING::GenericAll

Figure 26: An example of the set of actions performable by a custom class.

In the constructor for your class, make a call to CreatePrivateObjectSecurity() and store the returned security descriptor in one of your class members. You have now associated the security descriptor to your class. Should you need to update the security descriptor (e.g. during a configuration change), make a call to SetPrivateObjectSecurity(). This function will merge the old security descriptor with your own security descriptor.

When you are about to perform an action (i.e. one of your methods are called), you should now make a call to AccessCheckAndAuditAlarm(). You make a call here because if there are any audit entries in the security descriptor, you'll want an audit event to be fired. AccessCheckAndAuditAlarm() requires you to supply information for the audit event log. Once the call has been made, make a call to ObjectCloseAuditAlarm().

在您的类的构造函数中,调用CreatePrivateObjectSecurity()并将返回的安全描述符存储在您的一个类成员中。现在,您已将安全描述符与您的类相关联。如果您需要更新的安全描述符(如结构变更时),请调用SetPrivateObjectSecurity()。此函数将旧的安全描述符与您自己的安全描述符合并。

当你即将要执行的操作(即一个被调用的方法,),你现在应该做一个AccessCheckAndAuditAlarm()调用。您在这里打电话是因为,如果安全描述符中有任何审核条目,您将希望触发审核事件。AccessCheckAndAuditAlarm()要求您提供审核事件日志的信息。调用完成后,再调用ObjectCloseAuditAlarm()。

If your class bears a parent-child relationship model (like a folder), you'll want to support inheritance in your security descriptors. In this case, you'd use the Ex variants of the *PrivateSecurity functions. These functions bear two extra parameters: a GUID (in case your class multiple inherits), and the AutoInheritFlags. The AutoInheritFlags control how inheritance is applied from the parent object, and can also reduce the overhead of enabling privileges.

When you have finished using the class, call DestroyPrivateObjectSecurity() in the destructor to release the resources. ATL provides no special classes to handle privately secure objects. Therefore, just call the private security APIs directly. And for method 1, privately secure objects are only viable for classes (which is not available in C).

如果您的类具有父子关系模型(如文件夹),则需要在安全描述符中支持继承。在这种情况下,您将使用*PrivateSecurity函数的Ex变体。这些功能承担两个额外的参数:一个GUID(如果你的类继承多个),和AutoInheritFlags。该AutoInheritFlags如何继承从父对象施加,并且也可以减少使特权的开销控制。

当您使用类后,调用DestroyPrivateObjectSecurity()析构函数中释放资源。ATL没有提供特殊类来处理私有安全对象。因此,只需直接调用私有安全性API。对于方法1,私有安全对象仅适用于类(在C中不可用)。

class SecureClass
{
private:
  PSECURITY_DESCRIPTOR ppSD;
  double len;
  CAccessToken ProcToken;


  bool CheckClassAccess(DWORD RightsToCheck) const;
  /* This helper is where we do the access check */

public:
  enum Rights { /* The set of rights */
    ReadLen = 1,
    WriteLen = 2,
    SetClassSecurity = 4,
    CopyClass = 8
  };

  ~SecureClass();
  SecureClass(int FullRights, const CHandle &ThreadHandle);

  SecureClass(const SecureClass &OldClass);
  /* Copy constructor needs CopyClass access */

  double get_len(void) const ;
  /* You must have ReadLen rights to access this property */

  void set_len(double Newlen) ;
  /* You must have WriteLen rights to write this property */

  void set_SecDesc(SECURITY_INFORMATION psi,
    PSECURITY_DESCRIPTOR pNewSD);
  /** You need SetClassSecurity rights to access
  * this method
  **/
};

Figure 27: The outline of a class that secures access through security descriptors.

19. Summary总结

Q. The Cramsheet

That's a lot of information just to build a security descriptor (especially if you worked using method 1)! Most of the time you just want to retrieve and edit the security descriptor for an object. I've summarized the required steps, so you won't have to remember all of the above:仅用于构建安全描述符的信息很多(特别是如果您使用方法1进行工作)!大多数时候,您只想检索和编辑对象的安全描述符。我已经总结了所需的步骤,因此您不必记住以上所有内容:

  1. Steps:步骤

    If you need to enable any privileges, do that first.

    1. Find out which object you want to secure.
    2. Obtain a handle to your object with READ_CONTROL/WRITE_DAC access (alternatively get the name of the object).
    3. Call the relevant Get*Security() API, dependent on the type of object. Call InitializeSecurityDescriptor() if the object doesn't exist yet.
    4. Convert the returned self relative security descriptor to an absolute security descriptor.
    5. Split the security descriptor into its parts by calling GetSecurityDescriptor*() and friends.
    6. If necessary set the owner SID, then reapply it to the security descriptor using SetSecurityDescriptorOwner().
    7. Repeat step 7 for the group SID.
    8. If you are editing a DACL, get the current DACL and its size.
    9. From the current size and the size of your new entries, calculate the required size of your resultant DACL.
    10. Allocate a buffer of this size.
    11. Unless you are starting from scratch, copy the old DACL onto this buffer (GetAce() and AddAce()).
    12. Add your new entries to the ACL with FindFirstFreeAce() and AddAce(), reallocating if necessary.
    13. Apply the edited DACL onto your security descriptor using SetSecurityDescriptorDacl().
    14. Repeat steps 9-12 for the SACL.
    15. With the security descriptor built, call the corresponding Set*Security() API dependent on the type of object.
    16. If the object doesn't exist yet, create a SECURITY_ATTRIBUTES structure that holds the security descriptor.
    17. Create the object using the relevant API. Set the SECURITY_ATTRIBUTES parameter to the one you created in step 17.
    18. Pray that you can one day, redo this using method 2 or 3 because this only works on Windows NT 3.x and 4.0.
    19. 如果需要启用任何特权,请先执行此操作。
    20. 找出要保护的对象。
    21. 使用READ_CONTROL/WRITE_DAC访问获取对象的句柄(或者获取对象的名称)。
    22. Get*Security()取决于对象的类型,调用相关的API。如果对象尚不存在,则调用InitializeSecurityDescriptor()。
    23. 将返回的自我相对安全描述符转换为绝对安全描述符。
    24. 通过调用GetSecurityDescriptor*()和友元将安全描述符分成多个部分。
    25. 如有必要,设置所有者SID,然后使用将其重新应用于安全描述符SetSecurityDescriptorOwner()。
    26. 对组SID重复步骤7。
    27. 如果要编辑DACL,请获取当前的DACL及其大小。
    28. 根据当前大小和新条目的大小,计算所需的最终DACL大小。
    29. 分配此大小的缓冲区。
    30. 除非从头开始,否则将旧的DACL复制到此缓冲区(GetAce()和AddAce())上。
    31. 使用FindFirstFreeAce()和将新条目添加到ACL中AddAce(),如有必要,请重新分配。
    32. 使用编辑的DACL应用于安全描述符SetSecurityDescriptorDacl()。
    33. 对SACL重复步骤9-12。
    34. 构建安全描述符后,Set*Security()根据对象的类型调用相应的API。
    35. 如果对象尚不存在,请创建一个SECURITY_ATTRIBUTES包含安全描述符的结构。
    36. 使用相关的API创建对象。将SECURITY_ATTRIBUTES参数设置为您在步骤17中创建的参数。
    37. 祈祷有一天,可以使用方法2或3重做此操作,因为这仅适用于Windows NT 3.x和4.0。
  2. First enable any required privileges. Next build an SDDL string that represents your required security descriptor. Once built, convert the SDDL back into a security descriptor by calling ConvertStringSecurityDescriptorToSecurityDescriptor(). Break the security descriptor into its parts and apply it to the object with Set*SecurityInfo(). If you need to build from an existing security descriptor, you can call Get*SecurityInfo() to retrieve it. Far simpler than method 1, no need to convert it to absolute form plus it supports auto-inheritance.
  3. Obtain a security descriptor by calling AtlGetSecurityDescriptor(), then convert it to SDDL form using the ToString() method. Then proceed as in method 2.
  4. 首先启用任何必需的特权。接下来,构建一个SDDL字符串,该字符串表示您所需的安全描述符。构建完成后,通过调用将SDDL转换回安全描述符ConvertStringSecurityDescriptorToSecurityDescriptor()。将安全描述符分成多个部分,然后使用将其应用于对象Set*SecurityInfo()。如果需要从现有的安全描述符进行构建,则可以调用Get*SecurityInfo()以进行检索。比方法1简单得多,无需将其转换为绝对形式,而且它支持自动继承。
  5. 通过调用获取安全描述符AtlGetSecurityDescriptor(),然后使用ToString()方法将其转换为SDDL形式。然后按照方法2进行。

In this part you were shown how to obtain a SID, print it, convert it into a TRUSTEE, and convert it to a user name. You extracted information from your access token, such as who you are, which groups you are a member of, the list of restricted groups, the list of privileges and their state. You enabled and disabled a privilege, and created a restricted token to run a low privilege application.

Next, you obtained a security descriptor from a file, converted it to absolute form, then extracted the five parts of the security descriptor. You converted the security descriptor to SDDL form, and printed its contents. For the DACL, you were shown how to create and edit an Access Control List, and print out its contents. You then edited a security descriptor, applied inheritance rules to it, and finally secured an object with it (predefined and custom objects).

在这一部分中,向您展示了如何获取SID,打印,将其转换为TRUSTEE以及如何将其转换为用户名。您从访问令牌中提取了信息,例如您是谁,您属于哪个组,受限组列表,特权列表及其状态。您启用和禁用特权,并创建了受限制的令牌来运行低特权应用程序。

接下来,从文件中获取安全描述符,将其转换为绝对格式,然后提取安全描述符的五个部分。您已将安全描述符转换为SDDL格式,并打印了其内容。对于DACL,向您展示了如何创建和编辑访问控制列表以及如何打印其内容。然后,您编辑了安全描述符,对其应用了继承规则,最后使用它保护了一个对象(预定义和自定义对象)。

You were shown how to do all of this in NT3.x-style, 2000-style, and ATL style. This all culminates in the AccessCheck() function, which checks if you are allowed access to a certain resource.

I have left out domain issues and multiple inherited objects since they are out of scope for this series. To learn about these, I recommend checking out the Windows resource kits. The demo project contains all the code for this part, written in methods 1, 2 and 3. Currently the samples are not designed to be reusable, but given sufficient interest, I may change that (I'm saving the real functionality for part 4). In order to compile method 2, you need the boost::regex library and the WMI SDK installed and enabled. To compile method 3, you need the ATL libraries.

向您展示了如何以NT3.x样式,2000样式和ATL样式完成所有这些操作。这一切最终在该AccessCheck()函数中达到顶峰,该函数检查是否允许您访问特定资源。

我没有涉及域问题和多个继承的对象,因为它们超出了本系列的范围。要了解这些信息,建议您查看Windows资源工具包。该演示项目包含用方法1、2和3编写的该部分的所有代码。当前,这些示例并不是为了可重用而设计的,但是由于有足够的兴趣,我可能会做出更改(我将保留第4部分的实际功能))。为了编译方法2,您需要boost::regex安装并启用该库和WMI SDK。要编译方法3,您需要ATL库。

友情链接
版权所有 Copyright(c)2004-2015 锐英源软件

公司注册号:410105000449586 豫ICP备08007559号 最佳分辨率 1024*768

地址:郑州市文化路47号院1号楼4层(47-1楼位于文化路和红专路十字路口东北角,郑州大学工学院招待所南边,工学院科技报告厅西边。)