无令牌 REST API 安全问题

信息安全 Web应用程序 密码 php mysql 休息
2021-08-21 03:18:47

我正在 PHP/MySQL 中设计一个 API,根据其设计,它不会将用户的密码存储在数据库中,因此不会生成客户端持有的授权令牌。这样做的原因是为了防止在数据库受损的情况下获得任何敏感的、未加密的信息。

用户的敏感数据使用他们自己的密码进行加密,因此无法使用存储在(可能被泄露的)数据库中的任何内容来解密数据。我目前已经实现了一些安全功能:

  1. 如前所述,敏感数据使用 AES 加密,使用用户的 SHA-512 散列密码(密码作为表单数据随每个请求提供),加上一些额外的盐。
  2. HTTPS 是必需的,并且只允许 POST 请求。
  3. 用户帐户由电子邮件地址标识(在存储中经过修剪和小写),并且需要在使用前进行验证。
  4. 用户密码的长度必须至少为 8 个字符。
  5. 最终,第三方应用程序需要通过 Authorization 标头使用 API 令牌。第三方应用程序受到限制,因为它们无法创建、验证或删除帐户。

我的问题是,这就够了吗?我几乎不是安全专家,我最不想做的就是设计一些有重大监督的东西。我主要关心的是每个请求都会提供用户密码,即使它只能通过 SSL。

编辑:

澄清一下,用户将能够更改他们的密码,前提是他们仍然拥有当前密码。发出一个包含用户电子邮件地址、当前密码和新密码的请求。使用电子邮件地址和当前密码,像通常一样对请求进行身份验证。在继续之前,还要对新密码进行验证(强制最少 8 个字符)。

首先,正如用户希望检索他们的敏感信息时所做的那样,使用他们当前的密码对信息进行解密。在其解密状态下,然后使用新密码对信息进行加密,并在数据库中覆盖敏感数据。

此时,之前的密码没有存储记录,无法再使用。管理员无法更改密码,或者在任何情况下,如果没有先前用于加密信息的密码,则无法更改密码。如果密码丢失,则无能为力。

2个回答

在重新发明轮子并构建自己的会话管理器之前,请阅读OWASP 会话管理备忘单,这将帮助您避免常见错误。

问题是提议的身份验证令牌sha512(password)用于维护身份验证状态,它实际上是一个非常容易理解的会话令牌,原因有很多:

  1. 最糟糕的问题是这个提议的会话 id 的密钥空间非常小。攻击者猜测 sha512(password) 比猜测/dev/urandom.
  2. 加密!=身份验证。多个密钥可以作用于密文以产生一些结果,只有正确的密钥才能真正产生真正的纯文本。您仍然需要验证您是否收到了确切的密钥,而 AES-CBC 不会这样做。可以使用散列函数、CMAC 或 HMAC 验证此密钥的正确性。AES 在经过身份验证的操作模式下可以工作。
  3. CWE-613声明会话 ID 或“令牌”必须过期。通过使用密码哈希,实际上已经创建了sha512(password)一个不会过期的新密码,并且可以用于在不知道纯文本密码的情况下进行身份验证。一旦这个值被泄露,攻击者就可以访问该帐户。
  4. SHA512 是错误的密钥派生函数 (KDF),通常是存储密码的错误方法 ( CWE-916 )。bcrypt、pbkdf2、scrypt 都是不错的选择。
  5. 如果你是 RESTful,那么使用正确的 VERB对所有事情都使用 POST 是令人困惑的。强制执行 POST 不会使系统更安全,这些请求与 GET 一样容易受到 CSRF 或其他攻击等攻击。

你的想法不无道理。使用只有在用户在场时才能生成的密钥来加密用户的数据是一种合理的策略,并且实际上在许多高安全性环境中使用。如果操作正确,这可以提供显着的安全性。但我会介绍以下注意事项和修改:

  • 应避免无状态身份验证。它绝对比会话限制身份验证更糟糕。是的,总是。有多种原因,但其中之一是如果每次请求都发送密码,那么密码会缓存在某处理想情况下,用户应该登录,这会“解锁”数据存储并为用户提供一个限时会话密钥,该密钥只​​能用于在有限时间内访问“解锁”的数据存储。这使您可以使身份验证会话过期,并有助于防止许多潜在的攻击。请注意,这需要进行细微的设计更改,我将在下面详细说明。

  • 如果客户端的数据可以在客户端加密,那么就这样做。如果您所看到的用户数据只是一个加密的位块,那么您的服务器绝不会将该数据置于危险之中。

  • 您应该考虑使用两步加密链。与其使用密码派生密钥加密用户数据,不如使用完全随机密钥加密有价值的数据,然后使用用户密码派生密钥加密该完全随机密钥。这使您可以 (a) 轻松更改用户密码,(b) 引入更复杂的身份验证方案(例如双因素),以及 (c) 无需在每个请求中发送密码。只需使用从登录时提供给用户的随机会话令牌派生的临时密钥重新加密数据存储区密钥。您还应该绑定当前时间、用户的 IP 以及您想用来防止会话窃取的任何其他特定于会话的信息。

  • 使用合理的密钥推导公式。任何散列函数的单次传递都不足以防止攻击者在获取加密数据时暴力破解您的加密密钥。相反,请使用PBKDF2scrypt 等具有合理轮数的函数这大大增加了攻击者猜测用户密码所需的工作量。