Hibernate/Spring:是不是存在行级安全性?

Posted

技术标签:

【中文标题】Hibernate/Spring:是不是存在行级安全性?【英文标题】:Hibernate/Spring: Is There Row-Level Security?Hibernate/Spring:是否存在行级安全性? 【发布时间】:2015-12-15 22:04:11 【问题描述】:

我不确定 Spring Security 的能力是否正确。

我的问题是,我想prevent a logged in user to send arbitrary IDs to my server and therefore access data that does not belong to him。但我能找到的每个教程都是关于一个简单的login procedure。但是我怎么能用它来摆脱

if(item .getStore().getId() == store.getId())  /* .. */ 

在这个例子中:

// StoreService.java

@Transactional
public ItemDTO deleteItem(String sessionId, Long storeId, ItemDTO itemDto) 

    // sessionId is the cookie I have placed in my database
    // This way I want to ensure that I am only accessing a store
    // that is associated with the logged in store owner (the user basically)
    Store store = this.storeOwnerRepository.getStore(sessionId, storeId);

    Item item = ConvertDTO.convertItem(store, itemDto);

    // THIS CHECK IS WHAT I WANT TO GET RID OF:
    // Check if the store ID that I got using the cookie is the
    // same ID as the store ID from the item that should be deleted
    if(item.getStore().getId() == store.getId()) 
        item = this.storeOwnerRepository.deleteItem(item);
     else 
        // If this didn't work we have a potentially hostile user:
        throw new RuntimeException("Is somebody trying to delete items from a store he doesn't own?");
    

    itemDto = ConvertEntity.convertItem(item);
    return itemDto;

使用 Spring 注解? Spring Security 甚至可以做到这一点吗?

可能起作用的另一件事是Hibernate Filters,但我不确定我是否希望我的数据库了解我的数据的安全方面。

所以我很困惑如何正确地做到这一点。有什么想法吗?

【问题讨论】:

如果查询数据库,看看用户是否与该商店关联的商店正在尝试修改,如果是,则执行查询,如果不是,返回其他内容? @jpganz18 这就是我在 item.getStore().getId() == store.getId() 的示例代码中所做的,但我认为 Spring Security 可以帮助我摆脱这种代码。 Spring Security 中是否有与特定商店相关的角色? @jpganz18 好吧,不。目前我没有使用 Spring Security,因为我不知道如何做到这一点。但是如果有一个角色,那么StoreOwner(在我的代码中由storeOwnerRepository 表示)实际上是一个“拥有”一个或多个商店的登录用户。该用户基本上将拥有ADMIN 的角色,但由于我只有一个角色,我不确定这是否重要。问题是这个用户可以简单地向我发送任意 ID 并修改他不拥有的商店,除非我在那里进行此检查,但我找不到任何可以帮助我的 Spring Security 示例代码。 1.你关心与其他用户“共享”实体,还是只关心用户(或管理员)看到他们自己的东西? 2. 哪个数据库品牌,在db做的感觉如何? 3. Spring Security 4? 【参考方案1】:

我们已经使用Spring's ACL API 在域对象上实现了这种安全性。这涉及:

创建 Spring 的 org.springframework.security.acls.model.AclService 接口的实现,该接口知道如何返回给定主体对给定域对象的权限。例如。如果主体与此域对象有关系 foo,则授予 READ 和 WRITE 权限;如果是关系栏,则授予 READ、WRITE 和 DELETE 权限。 向服务方法添加对域对象注释(如org.springframework.security.access.prepost.PreAuthorizeorg.springframework.security.access.prepost.PreAuthorize),这些注释定义了要强制执行的访问控制断言。例如。此方法要求当前经过身份验证的用户对类型 X 的参数具有“WRITE”权限,或者该方法要求当前经过身份验证的用户对返回对象具有“READ”权限。如果任一断言失败,将抛出 AccessDeniedException。 调整您的 Spring Social 配置以打开方法级安全性。我在 Spring Security 的 XML 命名空间中使用了 global-method-security 元素。

有很多细节需要考虑,但我们在几个 Web 应用程序中使用这种方法效果很好。它允许您将 who-gets-what-permissions-on-which-objects 逻辑与 what-permissions-are-need-to-perform-this-action 逻辑分开,并且它使两者远离您的数据库查询。

当然,在某些情况下,您会希望在查询中实施访问控制,而不是先查询,然后过滤结果。我见过术语“早期绑定”用于描述在数据库查询中执行访问控制,而“后期绑定”用于描述对查询结果的访问控制。 Spring Security ACL API 是一个非常好的、健壮的后期绑定解决方案。

您最终会得到以下业务服务方法:

@PostAuthorize("hasPermission(returnObject, 'READ')")
public MyItem getMyItem(Long id) 
    return dao.getMyItem(id);


@PreAuthorize("hasPermission(#toDelete, 'DELETE')")
public void deleteMyItem(MyItem toDelete) 
    dao.delete(toDelete);

还有一个 AclService,其方法如下:

public Acl readAclById(ObjectIdentity objectIdentity, List<Sid> sids) throws NotFoundException 
    /*
examines objectIdentity which identifies domain object in question, and sids which identifies the principal who wants permissions on the domain object, then returns an ACL instance with permission grants on that domain object for that/those principals
    */
    return new AclImpl(...);

以及您的applicationContext-security.xml中的以下内容:

<beans:bean id="permissionEvaluator"
    class="org.springframework.security.acls.AclPermissionEvaluator">
    <beans:constructor-arg ref="aclServiceImpl" />
</beans:bean>
<beans:bean id="expressionHandler"
    class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
    <beans:property name="permissionEvaluator" ref="permissionEvaluator" />
</beans:bean>
<global-method-security pre-post-annotations="enabled">
    <expression-handler ref="expressionHandler" />
</global-method-security>

【讨论】:

我不确定我是否做对了。假设我拥有storeId=1storeId=2。如果我将storeId=3(不属于我,而是由另一个用户拥有)发送到服务器并调用getMyItem(3);,会发生什么情况?那会抛出异常吗?因为看起来我仍然需要在 DAO 对象内部进行检查。我对Item 有读/写/删除访问权限,但仅限于itemId=1itemId=2 的访问权限。这里有保证吗? 您的 AclService 将通过标识符查找域对象,并且它可能会通过相同的 DAO 进行。然后它(AclService)将确定您在该对象上获得哪些权限。然后,业务服务方法上的注释说明目标域对象需要哪些权限。当您的业务服务方法被调用时,Spring ACL 库调用 AclService,获取授予的权限,将它们与声明的权限进行比较,如果某些声明的权限未授予,则抛出安全异常。 关键是您的 DAO 不需要执行任何权限检查,它只进行检索(和其他存储操作)。您的业​​务逻辑也不需要任何权限检查;它只需要对您要保护的服务方法进行适当的安全注释。 但是具有READ 权限的any 用户可以通过any ID 并在此处获取any Item。我没看到什么?我真的不明白这如何将用户限制为实体的某些特定 ID。我知道只有拥有READ 权限的用户才会收到Item 返回。但这如何保护我免受将anyurl.com/index.html?getItem=1 更改为anyurl.com/index.html?getItem=1337 的用户(1337 不是他的Item)? Id 4337 将与用户的身份一起传递给 AclService。然后 AclService 确定用户是否对 4337 具有 READ 权限;如果不是,则 AclService 返回的权限对象没有设置 READ 位。当@PostAuthorize 注解查看该权限对象时,发现需要 READ(根据 hasPermission 表达式)但未在从 AclService 返回的权限对象上设置,则会引发异常。【参考方案2】:

您可能应该实现 Spring 安全性和工作角色和权限,这样您将能够确保您不会收到非管理员用户的请求(通过使用 @Secured("ROLE_SOMEROLE")) 分隔方法,这可以帮助您以防万一将来你会担任其他角色。

那么你应该更多地使用角色权限

Spring Security with roles and permissions

然后添加对存储的权限,以读取或写入它们。您可以将许多权限关联到一个用户,因此,只能对您想要的商店进行读/写/任何操作。

查看本教程,它可以帮助你。

http://slackspace.de/articles/roles-permissions-with-spring-security-3/

http://springinpractice.com/2010/10/27/quick-tip-spring-security-role-based-authorization-and-permissions

【讨论】:

对不起,我不明白这怎么能满足我的要求。假设我只有一个角色,那就是ADMIN。我页面上的任何人都是管理员,但每个管理员都有自己的资源。我没有看到 Spring Security 在哪里阻止管理员向我发送 storeID 3,即使他只拥有商店 1 和 2。我仍然需要在那里进行检查 - 或者我真的没有得到它?我需要smthng。像@RejectAlwaysIf("storeOwner.id != store.storeOwner.id") public void deleteItem(/* .. */) /* .. */; - 但当然这个约束应该是配置的一部分或其他任何东西。 您可以关联存储的权限,例如write-store-1、write-store-2、write-store-3,然后检查哪些权限有 但我会为每家商店都这样做,对吧?因为会有很多的商店。 ^^ 好吧,在那种情况下,是的,我真的没有看到只有 spring security 拥有的任何解决方案,因为它只是一个安全层,这更像是一个业务逻辑问题 这很奇怪 - 我真的认为 Spring 可以在这里帮助我。感觉这是一个非常普遍的问题。我不想依赖一个程序员,他在任何时候都不会忘记这个检查。例如,这会容易得多。对该关系有约束。但也许我必须把这个约束放在 Hibernates 手中的某个地方。无论如何,谢谢你试图帮助我!【参考方案3】:

我认为您所说的更多是与验证有关,而不是安全性。

只要您将多个客户/客户的数据存储在同一个数据库中,您就必须注意防止用户无意(或恶意)访问彼此的数据。

我建议您在 Web 服务层执行此验证,并使业务逻辑专注于需要完成的细节。

【讨论】:

嗨!您在那里看到的确实是服务器代码。它是使用 Springs @Transactional 进行休眠会话管理的服务层。在storeOwnerRepository 中是实际的Hibernate 代码,它删除数据库中StoreOwner 拥有的Item 这是一个经典的授权问题:如何控制对资源的访问(在这种情况下是多租户系统中的资源),所以分类作为一般 validation 而不是 security 的问题是不正确的。

以上是关于Hibernate/Spring:是不是存在行级安全性?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Hibernate 4、Spring 3、JPA 2 配置 MySQL5 最终有 1 个异常

数据库的锁:行级锁表锁乐观锁悲观锁的实现原理

java中的Web开发存在哪些Spring+JSF/Facelets的替代品?

Spring + Hibernate + Spring Security 配置

Spring第四天——SSH整合

innodb基本的行级锁和表级锁