在NodeJS后端中使用JWT和Active Directory身份验证

时间:2023-02-07 02:56:57

I am building an intranet web application consisting of an Angular frontend and a Node.JS backend. The application needs to use the corporate Active Directory for authentication and authorization.

我正在构建一个由Angular前端和Node.JS后端组成的Intranet Web应用程序。应用程序需要使用企业Active Directory进行身份验证和授权。

I'm considering how to best implement this in a secure way. I am planning to use the Active Directory node module for actually communicating with the AD to authenticate when the user logs in, and to check security group membership for certain restricted actions, etc.

我正在考虑如何以安全的方式最好地实现这一点。我打算使用Active Directory节点模块实际与AD通信,以便在用户登录时进行身份验证,并检查某些受限操作的安全组成员身份等。

However, I am not quite sure what is the best way to authorize my backend endpoints. The AD module does not offer any token/ticket, even though I suppose Kerberos is used for the actual authentication process. In other authenticated apps I've developed I've generated a jsonwebtoken when the user logs in, and then passed and verified that token in each backend route, is that a good idea also when authenticating against AD?

但是,我不太确定授权后端端点的最佳方法是什么。 AD模块不提供任何令牌/票证,即使我认为Kerberos用于实际的身份验证过程。在我开发的其他经过身份验证的应用程序中,我在用户登录时生成了jsonwebtoken,然后在每个后端路由中传递并验证了该令牌,在对AD进行身份验证时也是个好主意吗?

EDIT: Second part of question spawned to separate thread: Best practices for server-side handling of JWT tokens

编辑:问题的第二部分产生于单独的线程:服务器端处理JWT令牌的最佳实践

Also, I have a more general concern, regarding what the best practice is for actually verifying tokens. Suppose that the "secret" used for JWT generation is compromised (in my scenario many people may have access to the source code of the system, but not to the system itself). Am I right in believing that a malicious user could then, with only this information, generate a token on behalf of any given user, and without ever authenticating with AD use that token in my API requests? A token is typically generated using jwt.sign(payload, secretOrPrivateKey, options). Alternatively, suppose a malicious user could get hold of an actual token (before it has expired). To me it seems like instead of having to know a user's username and password, the security is now reduced to having to know the username and the JWT secret. Is this a valid concern and what should I do to prevent this?

另外,关于实际验证令牌的最佳实践,我有一个更普遍的关注点。假设用于JWT生成的“秘密”受到损害(在我的场景中,许多人可能有权访问系统的源代码,但不能访问系统本身)。我是否正确地相信恶意用户可以仅使用此信息代表任何给定用户生成令牌,并且在没有使用AD进行身份验证的情况下在我的API请求中使用该令牌?通常使用jwt.sign(payload,secretOrPrivateKey,options)生成令牌。或者,假设恶意用户可以获得实际令牌(在它到期之前)。对我而言,似乎不必知道用户的用户名和密码,现在安全性已降低为必须知道用户名和JWT秘密。这是一个有效的问题,我该怎么做才能防止这种情况发生?

My best hope so far is using a server side session to store information about the current user after logging in, so that even if a token is maliciously generated and used when accessing backend endpoints, it would fail unless the user has actually gone through the login route, authenticated with AD and stored some information in the session as a result of this.

到目前为止,我最好的希望是在登录后使用服务器端会话来存储有关当前用户的信息,这样即使在访问后端端点时恶意生成和使用令牌,它也会失败,除非用户实际经历了登录路由,通过AD进行身份验证,并在会话中存储一些信息。

I also considered actually authenticating with AD in each API endpoint, but that would require the AD username/password to be sent in every request, which in turn would require that sensitive information would have to be stored in the client's sessionstorage or localstorage, which is most likely a bad idea.

我还考虑过在每个API端点中实际使用AD进行身份验证,但这需要在每个请求中发送AD用户名/密码,这反过来要求敏感信息必须存储在客户端的sessionstorage或localstorage中,这是很可能是一个坏主意。

So, questions:

1) Is it reasonable to combine AD authorization with JWT as bearer token or what is the preferred way to build a secure backend + frontend utilizing AD for authentication?

1)将AD授权与JWT结合作为承载令牌或使用AD进行身份验证构建安全后端+前端的首选方法是否合理?

2) If JWT is a good idea, what is the best practice for securing endpoints using JWT? Is using a server side session reasonable?

2)如果JWT是一个好主意,使用JWT保护端点的最佳做法是什么?使用服务器端会话合理吗?

Interestingly enough I have found tons of examples on how to best implement token based authentication (in general, or with NodeJS specifically), but many of them seem flawed in one way or another.

有趣的是,我已经找到了大量关于如何最好地实现基于令牌的身份验证的示例(通常,或者具体使用NodeJS),但是其中许多似乎都有某种方式存在缺陷。

1 个解决方案

#1


2  

1) Is it reasonable to combine AD authorization with JWT as bearer token or what is the preferred way to build a secure backend + frontend utilizing AD for authentication?

1)将AD授权与JWT结合作为承载令牌或使用AD进行身份验证构建安全后端+前端的首选方法是否合理?

It is reasonable, but if you are already using Kerberos and AD to initially authenticate the user, you might consider using s4u2proxy constrained delegation which allows the service to present the user's service ticket to the KDC and acquire (subject to authorisation checks) a ticket for a backend service (and repeat for as many services are necessary).

这是合理的,但是如果您已经使用Kerberos和AD来初始验证用户,您可以考虑使用s4u2proxy约束委派,该委托允许服务将用户的服务票证呈现给KDC并获取(受授权检查)票证后端服务(并且需要重复多次服务)。

If you have a lot of backend services that need to be contacted, a single JWT bearing all the authorization claims needed for all the services to enforce authorization policy may be a better option.

如果您需要联系许多后端服务,那么承载所有服务以执行授权策略所需的所有授权声明的单个JWT可能是更好的选择。

2) If JWT is a good idea, what is the best practice for securing endpoints using JWT? Is using a server side session reasonable?

2)如果JWT是一个好主意,使用JWT保护端点的最佳做法是什么?使用服务器端会话合理吗?

General key security practices apply:

一般关键安全实践适用:

  • Never store keys in the clear in non-volatile storage, anywhere.
  • 切勿在任何地方将密钥存放在非易失性存储器中。

  • Ideally do not store encrypted keys in attached storage on the server where, if the server is compromised, they would be subject to offline attack. Make them available to the host only at server startup.
  • 理想情况下,不要将加密密钥存储在服务器上的附加存储中,如果服务器受到攻击,它们将受到脱机攻击。仅在服务器启动时将它们提供给主机。

  • Ensure key material resides in secure memory so that it cannot be swapped to disk (and/or use encrypted swap).
  • 确保密钥材料位于安全内存中,以便它不能交换到磁盘(和/或使用加密交换)。

  • Use public key algorithms so that no secret key need exist on multiple hosts.
  • 使用公钥算法,以便多个主机上不需要密钥。

  • Consider using a hardware security module (HSM).
  • 考虑使用硬件安全模块(HSM)。

#1


2  

1) Is it reasonable to combine AD authorization with JWT as bearer token or what is the preferred way to build a secure backend + frontend utilizing AD for authentication?

1)将AD授权与JWT结合作为承载令牌或使用AD进行身份验证构建安全后端+前端的首选方法是否合理?

It is reasonable, but if you are already using Kerberos and AD to initially authenticate the user, you might consider using s4u2proxy constrained delegation which allows the service to present the user's service ticket to the KDC and acquire (subject to authorisation checks) a ticket for a backend service (and repeat for as many services are necessary).

这是合理的,但是如果您已经使用Kerberos和AD来初始验证用户,您可以考虑使用s4u2proxy约束委派,该委托允许服务将用户的服务票证呈现给KDC并获取(受授权检查)票证后端服务(并且需要重复多次服务)。

If you have a lot of backend services that need to be contacted, a single JWT bearing all the authorization claims needed for all the services to enforce authorization policy may be a better option.

如果您需要联系许多后端服务,那么承载所有服务以执行授权策略所需的所有授权声明的单个JWT可能是更好的选择。

2) If JWT is a good idea, what is the best practice for securing endpoints using JWT? Is using a server side session reasonable?

2)如果JWT是一个好主意,使用JWT保护端点的最佳做法是什么?使用服务器端会话合理吗?

General key security practices apply:

一般关键安全实践适用:

  • Never store keys in the clear in non-volatile storage, anywhere.
  • 切勿在任何地方将密钥存放在非易失性存储器中。

  • Ideally do not store encrypted keys in attached storage on the server where, if the server is compromised, they would be subject to offline attack. Make them available to the host only at server startup.
  • 理想情况下,不要将加密密钥存储在服务器上的附加存储中,如果服务器受到攻击,它们将受到脱机攻击。仅在服务器启动时将它们提供给主机。

  • Ensure key material resides in secure memory so that it cannot be swapped to disk (and/or use encrypted swap).
  • 确保密钥材料位于安全内存中,以便它不能交换到磁盘(和/或使用加密交换)。

  • Use public key algorithms so that no secret key need exist on multiple hosts.
  • 使用公钥算法,以便多个主机上不需要密钥。

  • Consider using a hardware security module (HSM).
  • 考虑使用硬件安全模块(HSM)。