http协议并没有定义相关的安全认证方面的标准,所以就有了Basic and Digest Access Authentication的定义来补充,它的目的就是补充一套基于http服务端的认证机制,保护相关的资源避免被非法用户访问,如果你要访问被保护的资源,则必需要提供合法的用户名和密码。
basic & digest auth 和 https 没有任何关系。前者是为用户认证机制,后者是信息通道加密措施。
digest是basic的升级版,更加安全。因为basic是明文传输密码信息,而digest是加密后传输。
首先,这个世界上没有绝对的东西。digest默认用MD5(其它算法也可以)对密码进行加密,虽然相比basic认证的明文传输更安全,但是加密算法本身的安全性也值得怀疑(md5是可以反推出原文的)。再者,digest只是对认证信息的加密,后续的内容传输安全性得不到保障。所以https机制的作用就显现出来。
通过上面的相关信息,我们可以得到一个清晰的结论:如果你想加强自己的认证信息的保护,有两种选择,一是基于digest认证;别一种是在https通道上进行basic认证。
1,客户端请求受保护的资源
2,服务器检测到没有授权,则生成一个challenge返回给客户端
3,客户端根据challenge和相关信息计算出digest
4,附带3计算出的信息再次请求1中的资源
5,服务端根据已知的用户密码信息计算出digest并与4中请求的digest比较验证
6,服务端验证通过后返回资源给合法用户
Basic和Digest的认证都是按照上面的流程来,唯一不同的是3和5中计算digest的算法不同:Basic是将密码直接base64编码(明文),而Digest是用MD5进行加密后传输。
下面假设我们现在要请求:http://localhost:8080/index.html 这个路径,而它需要认证后才能访问。
Basic的流程如下:
Digest的流程和上面一样,只是challenge和digest的生成算法不同
这里我们只是讨论流程,具体的challenge和digest的生成算法请参考:RFC2617
HttpHost targetHost = new HttpHost("localhost", 8080);
DefaultHttpClient client = new DefaultHttpClient();
HttpContext context = new BasicHttpContext();
context.setAttribute(ClientContext.CREDS_PROVIDER, new BasicCredentialsProvider());
CredentialsProvider provider = (CredentialsProvider)context.getAttribute(ClientContext.CREDS_PROVIDER);
provider.setCredentials(
new AuthScope(targetHost.getHostName(), targetHost.getPort()),
new UsernamePasswordCredentials("tomcat", "admin"));
HttpGet get = new HttpGet("http://localhost:8080/web/Hello");
HttpResponse response = client.execute(get,context);
System.out.println(response.getStatusLine());
HttpEntity entity = response.getEntity();
String s = EntityUtils.toString(entity);
System.out.println(s);