关于使用Express-Gateway进行Api访问和使用JWT进行用户身份验证的建议

时间:2020-01-29 11:21:06

标签: express jwt api-key express-gateway

我在Express中有一台服务器,该服务器向Web应用程序公开了一些API。 我正在寻找一种管理最终用户和第三方认证的好方法。

现在,当用户使用电子邮件和密码注册时,服务器会生成与该用户关联的JWT。

function createToken(user, role) {
    var usr = {
        role: role,      // admin | customer | shop
        email: user.email,
        name: user.name
    };

    var expires = (Date.now() / 1000) + 60 * 60 * 24 * 365; // 1 year
    var nbf = Date.now() / 1000;
    usr['nbf'] = nbf;
    usr['exp'] = expires;
    var token = jwts.encode(usr, process.env.SECRET);
    return token;
}

当Web客户端收到该令牌时,它将令牌存储在cookie / web_storage中,并将其用于对服务器的每个API调用以及自动登录。令牌还包含role,因此当服务器收到请求时,它知道该用户/角色是否可以访问所请求的路由/资源。

function checkToken(token, api_name) {
    // verifies secret and checks exp
    jwt.verify(token, process.env.SECRET,
        function (err, decoded) {
            if (err) { throw { msg: "token expired or not authenticated", code: errors.ERR_NOT_AUTH }; }
            else {
                var role = decoded['role'];
                return does_role_can_access_api(role, api_name); // true or false             
            }
    });
}

现在,某些第三方希望访问我的API中的一些。我想创建一个Express-Gateway,以为要使用我的服务器的应用程序创建api密钥,并保留单个用户的现有JWT身份验证。

所以我会

 |----------------|
 |   my Web-App   |
 |----------------|----> |------------|            |------------|
                         |   Express  |            | my Server  |
                         |   Gateway  |----------> |    APIs    |
 |----------------|----> |------------|            |------------|
 |    3rd party   |
 |----------------|
  • 我的Web应用程序应该访问所有API,因为使用了我的Web应用程序 admin s(和我一样)以及用户(customersshops)。
  • 第三方应用程序应仅访问某些API,因为它们将是 仅customersshops

所以我想做这样的事情:

 |----------------|
 |   my Web-App   |
 |     scopes:    |
 | [admin, user]  |
 |                |
 |----------------|----> |------------|            |------------|
                         |   Express  |            | my Server  |
                         |   Gateway  |----------> |    APIs    |
 |----------------|----> |------------|            |------------|
 |    3rd party   |
 |    scopes:     |
 |     [user]     |
 |----------------|

最后,我的Web应用程序将具有包含所有范围的ApiKey,而第三方ApiKeys将仅具有user范围,因此我可以在该范围上过滤路由。无论使用哪种App,单个真实用户都将使用JWT令牌登录并发出请求。

因此,每个请求将具有一个ApiKey(基于所使用的应用程序)和一个JWT令牌(用于标识用户):

  • ApiKey将被第三方服务器添加到标头中,
  • JWT令牌将由用户浏览器的web_storage(检索并)添加到标头中。

听起来不错吗?

1 个答案:

答案 0 :(得分:1)

首先祝贺您在开发安全应用程序方面所做的所有努力,因为并不是每天我们都看到开发人员走得那么远。

澄清可能的误解

在深入探讨您的问题之前,我想先消除一个误解,即通常开发人员会围绕什么来访问后端。 this article中对此进行了详细讨论,我们可以阅读:

什么是向API服务器发出请求的东西。它确实是您的移动应用程序的真正实例,还是机器人,自动脚本还是攻击者使用诸如Postman之类的工具手动在您的API服务器上闲逛?

是移动应用程序的用户,我们可以通过多种方式进行身份验证,授权和标识,例如使用OpenID Connect或OAUTH2流。

虽然本文是在移动应用程序的上下文中,但是为了了解什么正在访问API服务器之间的区别,请参考{{1} }可以替换为mobile app。如果您有疑问,请阅读链接的文章部分,其中还包括一个图形,以帮助您理解这一点。

您的问题

现在,当用户使用电子邮件和密码注册时,服务器会生成与该用户关联的JWT。

web app

我的Web应用程序应该访问所有API,因为管理员(如我)以及我们的用户(客户和商店)都使用我的Web应用程序。

这是一种渴望获得身份验证令牌的方法,特别是当您说管理员可以访问API时,甚至对于普通用户来说也太长了。

根据您的用例,我建议它们在分钟范围内,因此我建议您切换到使用刷新令牌,这将使访问令牌的寿命很短,而刷新令牌的寿命却很长,但是在小时范围内,而不是几天,几周或几年。

刷新令牌流程示例:

Graphic for shorten token lifetimes

Sourced from: Mobile API Security Techniques - part 2

注意:尽管以上图形属于在移动API的上下文中撰写的一系列文章,但它们具有很多信息,这些信息对于服务于Web应用程序和第三方客户端的API也有效。

使用这种方法,客户端在短暂访问令牌失败时将需要通过发送刷新令牌来请求新的令牌,以获取新的访问令牌。

这里重要的一点是,不应将刷新令牌发送到浏览器,而只能发送访问令牌,因此您的第三方客户端必须非常了解这一点,以便不会尝试直接访问您的API从javascript中获取,相反,他们应该将其委托给后端。

API密钥和JWT的

最后,我的Web应用程序将具有包含所有作用域的ApiKey,而第三方ApiKeys将仅具有用户作用域,因此我可以在其上过滤路由。无论使用哪种App,单个真实用户都将使用JWT令牌登录并发出请求。 因此,每个请求都将具有一个ApiKey(基于所使用的应用程序)和一个JWT令牌(用于标识用户):

第3方服务器会将ApiKey添加到标题中, JWT令牌将通过用户浏览器的web_storage(检索并添加)到标头中。

我不确定您是否在说API密钥也将是JWT令牌,但是如果不是,那么我也将使用JWT令牌作为API密钥,但是具有每个域的特定作用域/角色您的第三方客户。

走多远

我不拒绝在任何安全性问题中回答OWASP基金会所做的出色工作,这种情况下与您最相关的是Web Security Testing Guide

OWASP Web安全测试指南包括用户可以在自己的组织中实施的“最佳实践”渗透测试框架,以及描述了用于测试最常见的Web应用程序和Web服务安全问题的技术的“低水平”渗透测试指南。