如何在 Restful API 中隔离数据



有一些 restful apis,如下所示:

api/v1/billing/invoices/{invoiceNumber}
api/v1/billing/transactions/{transactionNumber}

而且,每张发票或交易都属于一个特定的帐户。

在实现 restful API 时,我们必须满足:每个帐户只能查看自己的发票或交易。

我们应该如何在 restful apis 中隔离数据?

当然,我们可以将account number传递给 api,例如:

api/v1//billing/invoices/{invoiceNumber}?accoutNumber=XXX
api/v1/billing/{accountNumber}/invoices/{invoiceNumber}

但是Invoice Number已经能够唯一地标识资源。所以我不希望问题变得复杂。

还有其他方法可以解决这个问题吗?

你在这里混合了很多东西。

这不是REST 问题,这是一个安全问题。更准确地说,它是 OWASP 2013 年 10 大不安全直接对象漏洞。

让我们简单一点:您有一个这样的 URL

.../superSensitiveStuff/1

并且你想阻止"1"的所有者访问".../superSensitiveStuff/2">

据我所知,有三种方法可以解决这个问题:

  1. 在请求 URL 中强制实施完整性。此策略并非适用于所有情况,它仅适用于客户端向服务器先前通信的资源发出请求的情况。在这种情况下,服务器可能会添加如下所示的查询参数

    .../superSensitiveStuff/1?sec=HMAC(.../superSensitiveStuff/1)

    其中 HMAC 是一个加密哈希函数。如果缺少参数,服务器将删除请求,如果它在那里,服务器将能够验证它是否正是授权的URL,因为HMAC值保证了其完整性(有关其他信息,请点击上面的链接)。

  2. 使用不可预测的引用。这里的问题是用户可以猜出另一个 id。 ">嗯...我有资源编号 1,让我检查资源编号 2是否存在"。如果你删除序列并移动到随机数,这是很难做到的。资源将成为

    .../superSensitiveStuff/195A23FR3548...32OT465

    这很好,因为它有效且便宜。

  3. 利用RBAC-ABAC混合方法。RBAC 代表 基于角色的访问控制,这就是您正在使用的。第二个首字母缩略词的前导 A 代表属性。这意味着访问权限是根据用户角色属性提供的。在这种情况下是 userId,因为它必须经过身份验证才能访问私有资源。简而言之,当用户请求特定的.../superSensitiveStuff资源时,当您拥有该资源的所有权信息时,将从存储库加载该资源。例如,它可能是一个DB,而你的SuperSensitiveStuff java商业模式可能是这样的。

    public class SuperSensitiveStuff {
    private String userId;
    private String secretStuff;
    ...
    }
    

    现在,在控制器中,您可以执行以下操作

    String principal = getPrincipal(); //you request the logged userId
    SuperSensitiveStuff resource = myService.load(id); //you load the resource using the {id} in the request path
    if (resource.getUserId.equals(principal))
    return resource //200 ok, this is an authorized access
    else
    throw new EvilAttemptException() //401 unauthorized, cheater detected
    

最新更新