多租户系统 - 在服务端对租户选择进行安全检测

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

当使用 tenant2 身份登录并打开它的编辑窗体,没有显示选择 Tenant 下拉列表,因此就不能改变它的 Tenant 吗?

错!

如果是一个普通的用户,就不能改变 Tenant。但如果有一些 Serenity 及服务器工作原理的知识,就能修改 Tenant

当你正在使用 web 时,你得更认真地对待安全。

非常容易就在 web 应用程序中创建安全漏洞,除非你在客户端和服务器端都进行验证处理。

我们来演示一下。当使用 tenant2 身份登录时,打开 Chrome 控制台。

复制下面的代码,并把它粘贴到控制台:

  1. Q.serviceCall({
  2. service: 'Administration/User/Update',
  3. request: {
  4. EntityId: 2,
  5. Entity: {
  6. UserId: 2,
  7. TenantId: 1
  8. }
  9. }
  10. });

现在刷新用户管理页面,你将看到 tenant2 现在可以看到 admin 用户。

我们使用 javascript 调用 User Update 服务,并把 tenant2 用户的 TenaNntId 修改为 1 (主租客)

让我们把它还原回 第二承租人(2),然后我们将修复这个安全漏洞:

  1. Q.serviceCall({
  2. service: 'Administration/User/Update',
  3. request: {
  4. EntityId: 2,
  5. Entity: {
  6. UserId: 2,
  7. TenantId: 2
  8. }
  9. }
  10. });

打开 UserRepository.cs,定位到 MySaveHandler 类,并修改它的 GetEditableFields 方法:

  1. protected override void GetEditableFields(HashSet<Field> editable)
  2. {
  3. base.GetEditableFields(editable);
  4. if (!Authorization.HasPermission(Administration.PermissionKeys.Security))
  5. {
  6. editable.Remove(fld.Source);
  7. editable.Remove(fld.IsActive);
  8. }
  9. if (!Authorization.HasPermission(Administration.PermissionKeys.Tenants))
  10. {
  11. editable.Remove(fld.TenantId);
  12. }
  13. }

生成你的项目,然后尝试再次在控制台输入:

  1. Q.serviceCall({
  2. service: 'Administration/User/Update',
  3. request: {
  4. EntityId: 2,
  5. Entity: {
  6. UserId: 2,
  7. TenantId: 1
  8. }
  9. }
  10. });

你将得到这个错误:

  1. Tenant field is read only!

SaveRequestHandler 调用 GetEditableField 方法来决定哪些字段是可编辑的,因此由用户更新。默认情况下,这些字段通过检索行(row)属性的 UpdatableInsertable 特性决定。

除非特别指定,所有字段是可插入和可更新的。

如果我们没有租户管理权限,我们从自动确定可编辑字段列表中删除 TenantId