这听起来很吓人,但是这些概念值得一学:这个知识点从过去20年开始使用,并且在未来很长时间都会使用。很多使用的安全策略都围绕哈希算法展开,这在web应用中随处可见。
好消息是我们需要知道关于哈希的内容,可以通过几张图表讲清楚,这也就是我们接下来要展示的。
我们会分两步来讲:第一步,什么是哈希算法;第二步,哈希算法是怎么和密码结合来产生信息验证码(MAC,即数字签名)。
在本节最后,你会掌握自己生成一个HS256的签名token,通过网上小工具和npm 包即可。
什么是哈希算法哈希算法是一种特殊的算法,它有几个特点。并且哈希算法有很多实用应用,比如数字签名。
下面我们将它的4个有趣的属性,以及他们是如何保证产生的签名是可验证的。
我们先来介绍 SHA-256
哈希特性:不可逆我们可以这样来比喻哈希:你可以通过牛排来得到汉堡包,但是你不可能通过汉堡包来用来做汉堡的牛排:
也就是说:这个算法是不可逆的。
这也意味着我们把头和载体经过哈希之后,没有谁可只通过输出的字符串看出我们的头和载体的元数据。
你可以在这个网站上试试SHA-256算法:哈希计算器,就像这样:
3f306b76e92c8a8fbae88a3ef1c0f9b0a81fe3a953fa9320d5d0281b059887c3但是这也意味着哈希不是加密:加密从定义上来说是可以还原,我们需要通过加密的信息获取原信息是什么。
哈希特性:可重复性另一个重要的属性是哈希是可重复的,也就是说无论我执行多少次哈希,得到的结果都是一样的。
我们可以这样认为,给定一系列输入和一个输出,我们可以很轻松的知道输出是否正确,因为我们可以通过输入计算出来对应的输出。当然,前提是我们知道所有的输入信息。
哈希特性:唯一性另一个特性是:对于不同的输入,我们总会得到不同的输出。
这意味着我们把载体和头经过哈希之后,我们都会得到同样的输出信息,而且不会有输入会得到相同的输出信息。
哈希特性:随机性最后一个特性是,我们不可能通过算法,可以从输出得到哈希之前的原值。
如果我们想通过输出来得到输入,通过猜想输入来比较输出的方式呢?是不是可以一个个字符来修改,当输出一致的时候,我们就知道了输入是什么了。
但是这里有一个问题:
通过哈希算法,这样是不可能的。
因为在哈希算法中,仅仅改变输入的一个字符,输出就会有大约50%的部分会发生改变,所以不可能通过比较的方式来得到输入。
那么知道了这些特性之后,我们可能会想:哈希算法是怎么得到数字签名的呢?
难道攻击者不能只获取头和载体,而忽略签名吗?
任何人都可以使用SHA-256算法来得到同样的输出,然后把签名放在JWT的签名中,是吗?
如何通过哈希算法得到数字签名上面那个问题是存在的,任何人都可以通过头和载体得到签名。
但是HS256并不仅仅是这样:除了头、载体之外,哈希的过程还增加了一个秘钥,加在一起进行哈希。
哈希出来的结果就是SHA-256 HMAC 或 Hash-based MAC。HS256签名使用的算法就是HMAC-SHA256算法。
所以只有拥有头、载体和特定的密码的人才可以生成token。
也就是说上面哈希的结果就是一个有效的数字签名。
这是因为只有生成载体并通过密码生成的签名是有效的,没有其他人可以生成同样的哈希串。
即哈希串作为一个证明载体是有效的数字证明而存在。
之后,哈希串被加载信息之中进行传递,让接受者去验证信息是没有被篡改的。
JWTs也是这样做的:JWT的最后一部分就是经过SHA-256对头和载体进行哈希之后,然后经过Base64Url编码的字符串。
怎么验证JWT签名接受者受到消息之后,接受者必须有同样的密码才能够对签名进行验证,用来确保载体是有效的。