Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/53.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/file/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails JWT令牌解码,即使签名的最后一个字符已更改_Ruby On Rails_Jwt_Base64_Digital Signature - Fatal编程技术网

Ruby on rails JWT令牌解码,即使签名的最后一个字符已更改

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') 正确返

我只是在rails应用程序上试用JWT令牌,使用这个JWT库:

返回以下令牌:

eyJhbGciOiJIUzI1NiJ9.Eyjzc3Mioiiizmifq.CwX_ztyhVpyx_G27u938SceilsVc5AB5Akwqlo2HA

然后我用上面的标记解码

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')