多租户系统 - 防止编辑其他租户的用户

优质
小牛编辑
126浏览
2023-12-01

记住,使用 tenant2 可以在一些服务调用中更新自己的 TenantId,我们需要在服务器端对它进行安全检测。

与此类似,即使默认情况下,不能看到其他租户的用户,但实际上可以检索和更新他们。

又到了黑客时间。

打开 Chrome 的控制台,并输入:

  1. new MultiTenancy.Administration.UserDialog().loadByIdAndOpenDialog(1)

什么?可以打开 Admin 的用户对话框并更新内容!

MultiTenancy.Administration.UserDialog 是当你在用户管理页面单击用户名时所打开的对话框类。

我们创建一个新的对话框实例,并且使用 ID 加载用户实体。Admin 用户的 ID 是 1。

因此,对话框调用 UserRepositoryRetrieve 服务加载 ID 为 1 的实体。

记住,我们在 UserRepositoryList 方法做过滤。所以,服务也不知道是否应该返回另一租户的记录。

此时,应该在 UserRepository 对 retrieve 服务做安全检测。

  1. private class MyRetrieveHandler : RetrieveRequestHandler<MyRow>
  2. {
  3. protected override void PrepareQuery(SqlQuery query)
  4. {
  5. base.PrepareQuery(query);
  6. var user = (UserDefinition)Authorization.UserDefinition;
  7. if (!Authorization.HasPermission(PermissionKeys.Tenants))
  8. query.Where(fld.TenantId == user.TenantId);
  9. }
  10. }

我们之前在 MyListHandler 中做了同样的修改。

如果你现在尝试运行同样的 Javascript 代码,你将得到一个错误:

  1. Record not found. It might be deleted or you don't have required permissions!

但是,我们依然可以手工调用 Update 服务更新记录。所以,也需要在 MySaveHandler 中做安全检测。

ValidateRequest 方法修改为:

  1. protected override void ValidateRequest()
  2. {
  3. base.ValidateRequest();
  4. if (IsUpdate)
  5. {
  6. var user = (UserDefinition)Authorization.UserDefinition;
  7. if (Old.TenantId != user.TenantId)
  8. Authorization.ValidatePermission(PermissionKeys.Tenants);
  9. // ...

我们在这里检测是否是更新,如果要更新记录的 TenantId(Old.TenantId) 与当前登录用户的 TenantId 不相等时,我们调用 Authorization.ValidatePermission 方法确保该用户有租户的管理权限,如果没有该权限,将抛出错误。

  1. Authorization has been denied for this request!

防止删除其他租户的用户

在 UserRepository 中有删除和更新处理,并且他们有类似的安全漏洞。

使用类似的方法,我们也需要对它们进行安全检测:

  1. private class MyDeleteHandler : DeleteRequestHandler<MyRow>
  2. {
  3. protected override void ValidateRequest()
  4. {
  5. base.ValidateRequest();
  6. var user = (UserDefinition)Authorization.UserDefinition;
  7. if (Row.TenantId != user.TenantId)
  8. Authorization.ValidatePermission(PermissionKeys.Tenants);
  9. }
  10. }
  11. private class MyUndeleteHandler : UndeleteRequestHandler<MyRow>
  12. {
  13. protected override void ValidateRequest()
  14. {
  15. base.ValidateRequest();
  16. var user = (UserDefinition)Authorization.UserDefinition;
  17. if (Row.TenantId != user.TenantId)
  18. Authorization.ValidatePermission(PermissionKeys.Tenants);
  19. }
  20. }