处理JWT令牌
(从这个线程衍生出来的,因为这实际上是它自己的问题,而不是特定于NodeJS等)
我正在使用身份验证实现REST API服务器,并且我已成功实现了JWT令牌处理,以便用户可以通过带有用户名/密码的/ login端点进行登录,然后从服务器密钥生成JWT令牌并返回到客户。 然后在每个经过验证的API请求中将令牌从客户端传递到服务器,服务器密钥用于验证令牌。
但是,我正在尝试了解令牌应该如何以及在多大程度上得到验证的最佳实践,以制定一个真正安全的系统。 究竟应该参与“验证”令牌? 使用服务器密钥验证签名是否足够,还是应该交叉检查令牌和/或令牌有效负载与存储在服务器中的某些数据?
基于令牌的认证系统只会像每个请求中传递用户名/密码一样安全,只要获取令牌的难度要高于获取用户的密码。 但是,在我见过的例子中,生成令牌所需的唯一信息是用户名和服务器端的秘密。 这是否意味着假设一个恶意用户获得关于服务器秘密的知识,他现在可以代表任何用户生成令牌,从而不仅可以访问给定的一个用户,而且如果密码是获得,但实际上所有用户帐户?
这给我带来了问题:
1)JWT令牌验证是否应限于验证令牌本身的签名,仅依赖服务器秘密的完整性,还是附带单独的验证机制?
在某些情况下,我已经看到了令牌和服务器会话的组合使用,在通过/ login端点成功登录后,会话已建立。 API请求验证令牌,并将令牌中发现的解码数据与会话中存储的一些数据进行比较。 但是,使用会话意味着使用cookie,并且在某种意义上它违背了使用基于令牌的方法的目的。 它也可能会给某些客户带来问题。
可以想象,服务器将所有令牌当前在memcache或类似目录中使用,以确保即使服务器机密受到攻击,攻击者可以生成“有效”令牌,但只能通过/ login端点生成的确切令牌将被接受。 这是合理的还是多余的/矫枉过正的?
2)如果JWT签名验证是验证令牌的唯一方法,这意味着服务器秘密的完整性是突破点,那么应如何管理服务器机密? 从环境变量中读取并在每个已部署的堆栈中创建(随机化?)一次? 重新定制或周期性地旋转(如果是这样,如何处理在旋转之前创建的现有有效令牌,但需要在旋转后进行验证,如果服务器在任何给定时间保持当前密钥和以前的密码,则可能已足够) ? 还有别的吗?
也许我只是在服务器机密被泄密的风险过于偏执,这当然是一个更加普遍的问题,需要在所有加密情况下解决......
我一直在为我的应用程序玩令牌。 尽管我不是专家,但我可以分享我在这件事上的一些经验和想法。
智威汤逊的重点基本上是完整的。 它为您的服务器提供了一种机制,用于验证提供给它的令牌是否是真实的,并且是由服务器提供的。 通过你的秘密产生的签名是为此提供的。 所以,是的,如果你的秘密以某种方式泄漏了,那么这个人可以产生你的服务器认为是它自己的令牌。 简单地说,由于签名验证,基于令牌的系统仍然比您的用户名/密码系统更安全。 在这种情况下,如果有人有你的秘密,你的系统还有其他安全问题需要处理,而不是有人伪造代币(即使这样,只要修改密码,就可以确保用旧秘密制作的代币现在无效)。
至于有效载荷,签名只会告诉您提供给您的令牌与您的服务器发送出去时的令牌完全相同。 验证有效载荷内容对您的应用程序有效或适当的显然取决于您。
对于你的问题:
1.)在我有限的经验中,使用第二个系统来验证令牌肯定更好。 仅仅验证签名就意味着令牌是用你的秘密生成的。 将任何创建的令牌存储在某种数据库(redis,memcache / sql / mongo或其他存储)中是确保您只接受服务器创建的令牌的绝佳方式。 在这种情况下,即使你的秘密泄露了,也不会有太多问题,因为任何生成的令牌都无效。 这是我使用我的系统所采用的方法 - 所有生成的令牌都存储在数据库(redis)中,并且在每个请求中,我都会在接受它之前验证令牌是否在我的数据库中。 这种方式令牌可以由于任何原因被撤销,比如以某种方式被释放到野外的令牌,用户注销,密码更改,秘密更改等。
2.)这是我没有太多经验的事情,而且我仍然在积极研究,因为我不是安全专业人员。 如果您发现任何资源,请随时在这里发布! 目前,我只是使用从磁盘加载的私钥,但很明显这远离最好的或最安全的解决方案。
在您的应用程序中实施JWT时,需要考虑以下事项:
保持JWT的生命周期相对较短,并在服务器上进行生命周期管理。 如果您没有,并且以后需要在JWT中需要更多信息,则必须支持2个版本,或者等到您的旧JWT过期后再执行更改。 如果只查看jwt中的iat
字段,并忽略exp
字段,则可以在服务器上轻松管理它。
考虑在你的JWT中包含请求的URL。 例如,如果您希望将JWT用于endpoint /my/test/path
,请在JWT中包含像'url':'/my/test/path'
这样的字段'url':'/my/test/path'
,以确保它仅用于此路径。 如果你不这样做,你可能会发现人们开始在其他终端使用你的JWT,甚至是那些没有被创建的JWT。 你也可以考虑包含一个md5(url),因为在JWT中有一个大网址会使得JWT变得更大,并且它们可以变得相当大。
如果JWT正在API中实施,那么每个用例都应配置JWT到期时间。 例如,如果针对JWT的10个不同用例包含10个端点,请确保您可以让每个端点接受在不同时间到期的JWT。 这允许您比其他端点锁定更多端点,例如,一个端点提供的数据非常敏感。
不要在一段时间后简单地过期JWT,而应考虑实施支持以下两者的JWT:
所有JWT身份验证失败应该生成一个“错误”响应头,说明JWT身份验证失败的原因。 例如“过期”,“不使用剩余”,“撤销”等。这有助于实施人员知道他们的智威汤逊失败的原因。
考虑忽略JWT的“标题”,因为它们会泄露信息并对黑客进行控制。 这主要是关于标题中的alg
字段 - 忽略这一点,只是假设标题是你想要支持的,因为这可以避免黑客试图使用None
算法,这会消除签名安全检查。
智威汤逊应包含一个标识符,详细说明哪个应用程序生成了令牌。 例如,如果您的JWT由2个不同的客户端,mychat和myclassifiedsapp创建,则每个应该在JWT的“iss”字段中包括项目名称或类似内容,例如“iss”:“mychat”
iat
(at)代替exp
(expiry)。 为什么? 由于iat
基本上意味着JWT创建的时间,因此您可以根据创建日期在JWT过期时调整服务器。 如果有人通过未来20年的exp
,智威汤逊基本上会永远活着! 请注意,如果他们的iat
将来会自动失效,但允许有一点摆动空间(例如10秒),以防客户端的时间与服务器时间略有不同步。 /mysite/userInfo?jwt=XXX
,并且该网址被缓存。 他们注销,几分钟后,一个普通用户登录到您的应用程序。 他们会得到缓存的内容 - 有关超级用户的信息! 这往往不会发生在客户端,而更多的发生在服务器上,特别是在您使用像Akamai这样的CDN的情况下,并且让一些文件活得更长。 这可以通过在URL中包含相关用户信息并在服务器上验证这一点来解决,即使是缓存请求,例如/mysite/userInfo?id=52&jwt=XXX
我不认为我是专家,但我想分享一些关于Jwt的经验。
1:正如Akshay所说,最好有第二个系统来验证你的令牌。
a .:我处理它的方式:我将生成的散列存储到会话存储器中,并显示expiricy时间。 验证令牌,它需要由服务器发布。
b.至少有一件事必须检查使用的签名方法。 例如:
header :
{
"alg": "none",
"typ": "JWT"
}
一些验证JWT的库会在不检查哈希的情况下接受这个库。 这意味着,如果不知道用来签署令牌的盐,黑客就可以授予自己一些权利。 始终确保这不会发生。 https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/
c .:通过会话ID使用cookie不会有助于验证令牌。 如果有人想劫持一个lambda用户的会话,他只需要使用一个嗅探器(例如:wireshark)。 这个黑客将同时拥有两个信息。
我处理它的方式与点1.a相关。 :我有一个秘密与一个随机变量混合在一起。 这个秘密对每个令牌都是独一无二的
但是,我正在尝试了解令牌应该如何以及在多大程度上得到验证的最佳实践,以制定一个真正安全的系统。
如果你想要最好的安全性,你不应该盲目地遵循最佳实践。 最好的方法是理解你在做什么(我认为没关系,当我看到你的问题时),然后评估你所需要的安全性。 如果摩萨德想访问您的机密数据,他们总会找到一种方法。 (我喜欢这篇博文:https://www.schneier.com/blog/archives/2015/08/mickens_on_secu.html)
链接地址: http://www.djcxy.com/p/22021.html