我们都知道有些web资源只有具有特定权限的人才能获取,所以web服务器必须弄清楚到底是谁在访问它。但是HTTP协议又具有无状态的特性,就拿登录举例子来说,比如这次登陆了,下次发请求的时候它不知道你是否是登陆的状态。也就是说web服务器它不知道不是否就是有这个“特定权限”的人。所以为了达到这个目标,必不可少的就是认证。
基于表单的认证(Session+Cookie)
这种认证方式需要Session和Cookie配合。服务器端保存Session对象(一个Session对象与一个Session ID关联,两者之间存在映射关系),客户端以Cookie的形式保存Session ID这个值。
这个Cookie的名字叫JSESSIONID,值就是Session ID。在客户端第一次访问服务器的时候,服务器会为客户端分配一个Session ID。这时Tomcat服务器会生成这个名字为JSESSIONID,值为Session ID的这个Cookie,并发送给客户端,客户端拿到的这个存储Session ID的Cookie在本次会话中均是有效的,在接下来的每次请求中都会将这个Cookie传给服务器,服务器根据JSESSIONID这个名字会检索到Session ID。这个时候服务器并没有创建Session对象,只是生成了Session ID。当服务器调用getSession()方法时,服务器会获取到这个客户端的Session ID值,然后去自己的容器中查看这个Session ID有没有与之对应的Session对象,如果没有则创建。而这个Session对象本身就相当于一个大大的Map,可以用于存储客户端的状态信息。
举个例子来说:
- 客户端在登录页面输入账号和密码进行登录。本次将账号和密码封装在请求正文中发送给服务器。
- 服务器端拿到账号密码去后台比对。账号密码合法则发送相应的资源,并且生成一个Session对象,将这个Session对象保存在服务器端。在这个Session对象里可以存储标记该用户是否登录。
- 然后客户端下一次请求时,又会传递这个Session ID,服务器根据这个Session ID获取到Session,就能获取到第二步中标识的用户状态,然后就知道了用户的“身份”,再根据这个“身份”判断该用户有没有权限。
这种方式也是很有优点的,因为客户端每次发送的是这个Session ID,比较高效;而且对于这个账号和密码他只明文发送过一次,比较安全。
Basic认证(基本认证)
这个是最基本的认证方式,但是这个不常用。先看一张图:
- 假如客户端现在想要访问一个“权限资源”index.html,客户端会给服务器发请求: GET /index.html HTTP/1.1
- 服务器返回401(表示你还没有登录授权,你需要先接受验证)。外加响应头WWW-Authenticate:Basic realm="xxxxx.com"
- 客户端收到401响应,知道了他需要完成Basic认证。然后提示用户输入账号密码验证信息。输入完毕之后浏览器会将账号密码以Base64方式编码,发送给服务器。注意传输给服务器的是一串你看不懂的乱码
- 服务器收到这团乱码去效验你的账号密码,如果通过验证则给你发放资源。
注意:认证完之后,客户端接下来的每次请求中都带上这串乱码。
虽然他是经过Basic64编码后的,但是这种编码很容易被**,如果别人窃听到你这团乱码,很轻而易举就能**出你的账号密码,所以这种认证方式几乎是明文。而且一旦认证完成之后,接下来的每次请求中都会携带这串乱码,被窃听到的几率大大增加。就算窃听者不**密码,如果他拿到你这团乱码去认证,服务器也会将其视为合法用户。而且你每次都是同一个乱码,没有其他附加信息,就那样一个编码,只要我得到,就可以随便去请求你所拥有的资源。
我查阅资料,这种叫重放攻击。
重放攻击的基本原理就是把以前窃听到的数据原封不动地重新发送给接收方。很多时候,网络上传输的数据是加密过的,此时窃听者无法得到数据的准确意义。但如果他知道这些数据的作用,就可以在不知道数据内容的情况下通过再次发送这些数据达到愚弄接收端的目的。例如,有的系统会将鉴别信息进行简单加密后进行传输,这时攻击者虽然无法窃听密码,但他们却可以首先截取加密后的口令然后将其重放,从而利用这种方式进行有效的攻击。再比如,假设网上存款系统中,一条消息表示用户支取了一笔存款,攻击者完全可以多次发送这条消息而偷窃存款。
所以,Basic这种方式是很不安全的。
Gigest认证(摘要认证)
为了改进Basic认证中存在的缺陷,HTTP1.1中引入了这种认证方式。这种方式同样使用质询/响应的方式,但不会像Basic认证那样直接发送明文密码。
上面图中也表明清楚了。服务器返回的质询码中会包含一个唯一的字符串nonce。这是服务端向客户端发送质询时附带的一个随机字符串,这个数会经常发生变化。客户端用该字符串和用户密码以及一些附加信息通过MD5算法(Hash算法的一种)计算出一团乱码,将这团“乱码”传输给服务器。所以这团“乱码”每次都不一致。这样就有效防止了重放攻击。因为这次窃听到的乱码,你只能在这次使用,你下次就用不了了,因为下次计算出来的又是一个不一样的新的值。