如何在Restful API中隔离数据

时间:2017-06-15 14:20:08

标签: rest restful-authentication restful-architecture restful-url

有一些宁静的apis,如下:

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

并且,每张发票或交易都属于特定帐户。

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

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

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

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

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

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

1 个答案:

答案 0 :(得分:3)

你在这里混合很多东西。

这是 REST问题,这是一个安全问题。更确切地说,它是OWASP top 10 2013 Insecure direct object vulnerability

让它变得简单:你有这样的网址

.../superSensitiveStuff/1

并且您希望阻止" 1"的所有者从访问" .../superSensitiveStuff/2"

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

  1. 在请求网址中强制执行完整性。此策略不适用于所有情况,它仅适用于客户端向先前由服务器传送的资源发出请求的情况。在这种情况下,服务器可以添加像这样的查询参数

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

    其中HMAC是cryptographic HASH function。如果参数丢失,服务器将丢弃请求,如果它在那里,服务器将能够验证它是否完全是授权URL,因为HMAC值保证其完整性(对于其他信息,命中上面的链接)。

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

    .../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