Ruby on rails JWT令牌解码,即使签名的最后一个字符已更改
我只是在rails应用程序上试用JWT令牌,使用这个JWT库: 返回以下令牌: eyJhbGciOiJIUzI1NiJ9.Eyjzc3Mioiiizmifq.CwX_ztyhVpyx_G27u938SceilsVc5AB5Akwqlo2HA 然后我用上面的标记解码Ruby on rails JWT令牌解码,即使签名的最后一个字符已更改,ruby-on-rails,jwt,base64,digital-signature,Ruby On Rails,Jwt,Base64,Digital Signature,我只是在rails应用程序上试用JWT令牌,使用这个JWT库: 返回以下令牌: eyJhbGciOiJIUzI1NiJ9.Eyjzc3Mioiiizmifq.CwX_ztyhVpyx_G27u938SceilsVc5AB5Akwqlo2HA 然后我用上面的标记解码 JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJzc3MiOiIzMzMifQ.CwX_1FztYHVpyx_G27u938SceilsVc5AB5Akwqlo2HA", 'SECRET_KEY') 正确返
JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJzc3MiOiIzMzMifQ.CwX_1FztYHVpyx_G27u938SceilsVc5AB5Akwqlo2HA", 'SECRET_KEY')
正确返回以下响应:
[{“sss”=>“333”},{“alg”=>“HS256”}]
但是,如果我尝试将标记的最后一个字母改为B,而不是当前的A,它仍然返回相同的响应,这很奇怪
JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJzc3MiOiIzMzMifQ.CwX_1FztYHVpyx_G27u938SceilsVc5AB5Akwqlo2HB", 'SECRET_KEY')
即使我提供的令牌错误,也会得到此响应:
[{“sss”=>“333”},{“alg”=>“HS256”}]
事实上,我在“D”之前的所有角色都得到了相同的响应
如果我使用F
和上面的其他方法,则其显示错误与预期一致:
JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJzc3MiOiIzMzMifQ.CwX_1FztYHVpyx_G27u938SceilsVc5AB5Akwqlo2HF", 'SECRET_KEY')
JWT::VerificationError(引发签名验证)
来自(irb):34
这可能是什么原因?这是预期的行为还是我做错了什么?原因是base64url编码。JWT的三个部分都是base64url编码的。将输入数据转换为映射到一组64个ASCII字符的6位表示形式。如果有3个字节的源数据(24位),base64编码的结果是4个字符长,每个字符代表一个6位的值,因此4*6位=24位。如果需要编码的比特数不能被6除而没有余数,那么会有一个字符包含2或4个不重要的比特 在您的例子中,编码签名有43个字符,这意味着43*6=258位。 因此,理论上可以对258位进行编码,但签名只有256位(32字节)长,这意味着末尾有2个无关紧要的位 查看显示,“A”到“D”表示6位值0(000000)到4(000011),因此前四位(仍然有效)都是相同的,只有最后两个不重要的位在变化。但字符“E”代表5(000100),将更改256位值的最后一位 下表说明了这一点。它显示签名的最后4个base64字符,包括最后一个字符(A-D)的可能更改以及原始数据的位和字节数: 该范围内最后一个字符的更改只会导致最后两位(浅灰色)的更改,但不会更改原始数据,因为更改的位超出了原始数据的最后一位
如果你真的很关心最后的2位,你可以考虑把签名算法改成HS34.< 然后是一个384位(=48字节)的散列,用64个Base64字符表示。384可以被8除,被6除,不带余数,因此末尾没有不重要的位,最后一个字符的任何更改都将导致验证失败
HS512会有与HS256相同的“问题”,最后甚至会有4个不重要的位,但尽管如此,较长的哈希(512位对384位对256位)被认为更安全结论:一切都很好,这里没有问题。签名的验证基于其二进制值,而二进制值不受编码特性的影响。如果您担心的话,您可以更改算法,但我认为这不是真的必要,算法的选择不应该基于此。谢谢您的解释。我以为那是一只虫子。
JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJzc3MiOiIzMzMifQ.CwX_1FztYHVpyx_G27u938SceilsVc5AB5Akwqlo2HF", 'SECRET_KEY')