关于Spring Data JPA Rest的安全问题(JpaRepository)

时间:2018-05-24 08:56:35

标签: java spring spring-boot spring-security dto

我(尝试:)在我的春季启动应用中使用 spring-boot-starter-data-rest ,通过真实,全面的,restFULL api快速提供模型。这很有效。

问题1(安全):

Spring JpaRepository的优点是我不需要编写基本函数(save,findAll等)。是否有可能在不覆盖所有这些方法的情况下保护这些自动实现的方法(浪费了Spring为我提供的内容)?即:

public interface BookRepository extends JpaRepository<Book, Long> {

    @PreAuthorize("hasRole('ROLE_ADMIN')")
    <S extends Book> Book save(Book book);
}

问题2(安全):

如何保护JpaRepository以防止更新loggeg-in用户不是所有者的项目? 即:允许用户仅修改他/她自己的属性。 即:2:允许用户仅修改/删除他/她创建的帖子。 这里非常欢迎示例代码。

问题3(DTO):

前段时间我与一位开发人员朋友争论:他认为必须从Spring MVC控制器返回DTO。即使DTO是模型对象的1-1副本。然后我留下来,问其他人并确认:DTO需要分割/隔离应用程序层。

这与JpaRepositories有何关系?如何在Spring自动服务器休息回购中使用DTO?我应该进行DTO吗?

提前感谢您的提示/答案!

1 个答案:

答案 0 :(得分:1)

问题1 :安全性

有些old docs提到:

  

[...]您向不受您控制的客户端公开了一组预定义的操作,直到现在它几乎全有或全无。在完全隐藏状态更改操作的情况下,似乎没有办法只显示读取操作。

这意味着所有方法都会自动继承(同样,根据标准java继承行为)。

根据@PreAuhtorize文档,您也可以将注释放在类/接口声明中。

所以你可以只有一个基本界面扩展JpaRepository

@NoRepositoryBean // tell Spring not create instances of this one
@PreAuthorize("hasRole('ROLE_ADMIN')") // all methods will inherit this behavior
interface BaseRepository<T, ID extends Serializable> extends Repository<T, ID> {}

然后让所有Repository扩展BaseRepository

问题2 :安全性

我会对这一点更加一般。

为了正确规范对应用程序中实体的访问并定义 what-c​​an-see-what ,您应该始终将项目分成不同的层。

一个很好的起点是:

  • layer-web(或表示层):访问layer-business,无法访问db-layer。可以查看DTO模型,但不能查看DB models
  • layer-business(或业务层):访问db-layer但无法访问DAO
  • layer-db(或数据层):转换DTO -> DB model。持久化对象并提供查询结果

在您的情况下,我认为正确的做法是在请求到达layer-business课程之前检查Repository中的角色。

@Service
public interface BookService {

    @PreAuthorize("hasRole('ROLE_ADMIN')")
    ActionResult saveToDatabase(final BookDTO book);
}

或者,如前所见

@Service
@PreAuthorize("hasRole('ROLE_ADMIN')")
public interface BookService {

    ActionResult saveToDatabase(final BookDTO book);
}

此外,确保用户只能修改自己的对象可以通过多种方式完成。

Spring提供了所有必要的资源,正如this answer指出的那样。

或者,如果您熟悉AOP,则可以实现自己的逻辑。

例如(dummyCode):

@Service
public interface BookService {
    // custom annotation here
    @RequireUserOwnership(allowAdmin = false)
    ActionResult saveToDatabase(final BookDTO book);
}

支票:

public class EnsureUserOwnershipInterceptor implements MethodInterceptor {

    @Autowired
    private AuthenticationService authenticationService;

    @Override
    public Object invoke(Invocation invocation) throws Throwable {
        // 1. get the BookDTO argument from the invocation
        // 2. get the current user from the auth service
        // 3. ensure the owner ID and the current user ID match
        // ...
    }
}

有关AOP的有用资源可以找到herehere

问题3 DTO&#39; s和DB models

  

我应该进行DTO吗?

是的,是的,你应该。即使你的项目只有几个模型,你只是为了好玩而编程(只在localhost上部署,学习......)。

越早养成分离模型的习惯,就越好。

另外,从概念上讲,一个是来自未知来源的对象,另一个是数据库中的表。

  

这与JpaRepositories有何关系?   如何在Spring自动服务器休息回购中使用DTO?

现在这就是重点!您无法DTO放入@Repository s。你被迫将一个转换为另一个。同时,您还必须验证转换是否有效。

您基本上确保DTO(脏数据)不会以任何方式触及数据库,并且您在数据库和应用程序的其余部分之间放置了由逻辑约束构成的墙。

我也知道Springmodel-conversion frameworks很好地融合。

那么,multi-layer / modular网络应用的优势是什么?

  • 应用程序可以快速增长。特别是当你有很多开发人员在研究它时。一些开发人员倾向于寻找最快的解决方案并实现肮脏的技巧或更改访问修饰符以尽快完成工作。您应该强制人们仅通过一些明确定义的渠道访问某些资源。 您从一开始就设置的规则越多,遵循正确的编程模式的时间就越长。在不到一年的时间里,我看到银行应用程序变得一团糟。当需要hotfix时,更改一些代码会创建其他两个错误

  • 您可能会遇到应用程序占用过多OS资源的问题。如果你让我们说你的应用程序有一个包含后台作业的模块module-batch,那么提取它并将其实现到另一个应用程序中会更容易。如果您的模块包含查询数据库的逻辑,访问任何类型的数据,为前端提供API,ecc ...您将基本上被迫将所有代码导出到新应用程序中。在那时,重构将是一个痛苦的问题。

  • 想象一下,您希望聘请一些数据库专家来分析您的应用程序所执行的查询。使用定义明确且分离的逻辑,您可以只访问必要的modules而不是整个应用程序。这同样适用于前端自由职业者ecc ......我也曾经历过这种情况。该公司希望数据库专家修复应用程序完成的查询,但不希望他们访问整个代码。最后,他们放弃了数据库优化,因为这会在外部暴露出过多的敏感信息。

DTO / DB model分离有什么好处?

  • DTO&#39}不会触及数据库。这为您提供了更高的安全性来抵御来自外部的攻击
  • 你可以决定另一方面的情况。您的DTO不需要将所有字段都实现为数据库模型。实际上,你甚至可以在许多DAO或其他方面拥有DTO地图。有很多信息不应该到达前端,而DTO可以很容易地做到这一点。
  • DTO一般比@Entity型号升。实体被映射(例如@OneToMany)到其他实体,DTO可能只包含映射对象的id字段。
  • 您不希望数据库对象停留太久;并且不会被您的申请方法传播。许多框架在每个方法的末尾提交数据库事务,这意味着对数据库实体进行的任何非自愿更改都可以提交到数据库中。

就个人而言,我认为任何尊重的网络应用程序都应该强烈地分离各个层,每个层都有其责任,并且对其他层的可见性有限。

数据库模型和数据传输对象之间的区别也是一个很好的模式。

最后,这只是我的意见;许多人认为DTO模式已经过时并且导致不必要的代码重复,许多人认为很多分离倾向于难以维护代码。因此,您应该始终咨询不同的来源,然后应用最适合您的方式。

同样有趣: