让我将所有内容分开并单独解决每个问题:
验证
对于身份验证,baseauth 的优点是它是协议级别的成熟解决方案。这意味着很多“以后可能会出现”问题已经为您解决了。例如,使用 BaseAuth,用户代理知道密码是密码,因此他们不会缓存它。
验证服务器负载
如果您向用户分配令牌而不是在服务器上缓存身份验证,那么您仍然在做同样的事情:缓存身份验证信息。唯一的区别是您将缓存的责任转移给了用户。对于用户来说,这似乎是不必要的劳动,没有任何收益,因此我建议按照您的建议在服务器上透明地处理此问题。
传输安全
如果可以使用 SSL 连接,就足够了,连接是安全的*。为了防止意外多次执行,您可以过滤多个 url 或要求用户在 URL 中包含随机部分(“nonce”)。
url = username:[email protected]/api/call/nonce
如果这是不可能的,并且传输的信息不是秘密的,我建议使用哈希来保护请求,正如您在令牌方法中所建议的那样。由于哈希提供了安全性,因此您可以指示用户提供哈希作为基本身份验证密码。为了提高鲁棒性,我建议使用随机字符串而不是时间戳作为“随机数”,以防止重放攻击(同一秒内可以发出两个合法请求)。您可以简单地使用 api 密钥作为共享密钥,然后使用不会更改的盐来防止彩虹表攻击,而不是提供单独的“共享密钥”和“api 密钥”字段。用户名字段似乎也是放置随机数的好地方,因为它是身份验证的一部分。所以现在你有一个像这样的干净的调用:
nonce = generate_secure_password(length: 16);
one_time_key = nonce + '-' + sha1(nonce+salt+shared_key);
url = username:[email protected]/api/call
确实,这有点费力。这是因为您没有使用协议级解决方案(例如 SSL)。因此,向用户提供某种 SDK 可能是一个好主意,这样至少他们就不必亲自使用它。如果您需要这样做,我认为安全级别合适(just-right-kill)。
安全秘密存储
这取决于你想阻止谁。如果您阻止有权访问用户手机的人以用户的名义使用您的 REST 服务,那么最好在目标操作系统上找到某种密钥环 API 并让 SDK(或实现者)存储钥匙在那里。如果这是不可能的,您至少可以通过对其进行加密并将加密数据和加密密钥存储在不同的位置来使获取秘密变得更加困难。
如果您试图阻止其他软件供应商获取您的 API 密钥以阻止备用客户端的开发,则只能使用单独加密和存储的方法almost作品。这是白盒加密,迄今为止,没有人针对此类问题提出真正安全的解决方案。您至少可以做的是为每个用户颁发一个密钥,这样您就可以禁止滥用密钥。
(*) 编辑: SSL 连接不应再被认为是安全的没有采取额外步骤进行验证 them.