如何设计具有2因子认证(2FA)的无状态REST登录?

问题描述:

我正在为如何设计具有多因素身份验证的无状态RESTful身份验证API的概念而苦苦挣扎.

I'm struggling with the concept of how to design a stateless RESTful authentication API with multi-factor authentication.

几乎根据定义,需要2FA时需要多个状态.使用用户名/密码登录,然后提交代码"(TOTP,SMS代码,验证问题的答案等).这进一步暗示了某种有限状态机(FSM).

Almost by definition, the need of a 2FA requires multiple states; logging in with a username/password, then submitting a "code" (either a TOTP, SMS-code, answer to a verification question, etc). This further implies a finite-state-machine (FSM) of some sort.

据我所知,为了维持无状态机制而存在的唯一选择是:

As far as I can tell, the only options which exist in order to maintain a stateless mechanism are:

  1. 在提交数据以转换到下一个状态时,客户端必须传输一些状态信息(例如:当前FSM状态)
  2. 状态必须在服务器端保持不变
  3. 客户端必须在每次请求时传输所有数据,以使其达到当前状态

显然,传输所有数据是没有意义的.因此,这意味着要么在请求中传输状态信息(不透明或其他),要么在服务器上保持状态.

Obviously transmitting ALL data is nonsensical. So this would imply either transmitting state information (opaque or otherwise) in the request or maintaining state on the server.

还是我缺少其他技巧?

我正在添加我想出的解决方案,以防将来对其他人有好处.请注意,在这种情况下,PVQ代表个人验证问题"(即:基于知识的身份验证).

I'm adding the solution I came up with in case it is beneficial for someone else in the future. Please note that in this case, PVQ stands for "Personal Validation Question" (ie: Knowledge-Based-Authentication).

最后,我设计了登录端点,要求:

At the end, I designed my login endpoint to require:

  • 授权标头(这是2FA令牌):Authorization: authType=PVQ token=<tokenid>
  • 用户名
  • 密码
  • Authorization header (which is a 2FA token) : Authorization: authType="PVQ" token="<tokenid>"
  • username
  • password

如果缺少Authorization标头,则端点返回401并设置WWW-Authenticate标头,指示需要2FA令牌(即:Authorization标头)进行登录.参数可以是PVQ,SMS,TOTP等(基于用户的配置)

If the Authorization header is missing, the endpoint returns a 401 and sets a WWW-Authenticate header, indicating that a 2FA token (ie: Authorization header) is required to login. param could be PVQ, SMS, TOTP, etc (based on the user's configuration)

WWW-Authenticate : authType="PVQ"

如果客户端收到401/WWW-Authenticate响应,则它有责任呼叫2FA端点:

If the client receives a 401/WWW-Authenticate response, it is its responsibility to call the 2FA endpoints:

  • 挑战/获取(接收挑战令牌)

  • challenge/get (receive a challenge token)

  • 客户端:发送用户名/密码
  • 服务器:以ID响应,并以
    • 问题(PVQ)
    • 或仅通过第三方短信提供商发送发送短信代码
    • Client: sends username/password
    • Server: Responds with an ID, and either
      • a question (PVQ),
      • or just sends sends an SMS code via 3rd party SMS provider

      挑战/验证(接收Authorization标头所需的2FA令牌)

      challenge/verify (receive the 2FA Token needed for the Authorization header)

      • 客户:发送
          challenge/get
      • 中收到的
      • ID
      • 用户名/密码
      • 应对挑战(即:对PVQ,SMS代码或TOTP代码的文字答复)
      • Client: sends
        • ID received in the challenge/get
        • username/password
        • response to the challenge (ie: text answer to a PVQ, or SMS code, or TOTP code)
        • 2FA令牌值

        客户端现在可以使用所需的用户名/密码/身份验证令牌来调用登录端点.

        The client can now call the login endpoint with the required: username/password/Authentication token.

        最后,没有说客户端返回服务器的状态",但是为此权衡的是,必须将用户名/密码组合发送给2FA子系统的每个请求.

        In the end, there is not "state" per say that the client returns to the server, but the tradeoff for this, is that the username/password combination must be sent to every request for the 2FA subsystem.

        在服务器端,在发送给用户的SMS代码或PVQ问题的上下文中,在数据库中存储了一些状态信息,以及一个临时身份验证2FA令牌(单次使用和固定的TTL)

        On the server side, there is some state information stored in the DB in the context of the SMS code or PVQ question that was sent to the user, as well as an ephemeral Authentication 2FA token (single use, and fixed TTL).