什么是HTTP Basic Authentication?
在wiki上有详细的解释: http://en.wikipedia.org/wiki/Basic_authentication_scheme
HTTP Basic Authentication是一个定义在HTTP/1.1规范中的验证机制。这种机制是以用户名和密码为基础的。一个web server要求一个web client去验证一个用户。作为request的一部分,web server 传递被称之为realm的字符串,用户就是在它里面被验证的。注意:Basic Authentication机制的realm字符串不一定反映任何一种安全方针域。Web client得到这些用户名和密码,然后把它传递给web server。Web server然后在一个特定的领域验证这些用户。
由于密码是使用一种64位的编码来传递,而且目的server没有验证,所以Basic Authentication不是一种安全的验证协议。
在访问一个需要 HTTP Basic Authentication 的URL的时候,如果你没有提供用户名和密码,服务器就会返回401,
如果你直接在浏览器中打开,浏览器会提示你输入用户名和密码。
你可以尝试点击这个url看看效果:http://api.minicloud.com.cn/statuses/friends_timeline.xml
如果想要在发送请求的时候添加 HTTP Basic Authentication 认证信息到请求中,有两种方法:
一是在请求头中添加Authorization:
Authorization: "Basic 用户名和密码的base64加密字符串"
二是在url中添加用户名和密码:
http://userName:password@api.minicloud.com.cn/statuses/friends_timeline.xml
//需要Base64见:http://www.webtoolkit.info/javascript-base64.html
function make_base_auth(user, password) {
var tok = user + ':' + pass;
var hash = Base64.encode(tok);
return "Basic " + hash;
}
var auth = make_basic_auth('QLeelulu','mypassword');
var url = 'http://example.com';
// 原始JavaScript
xml = new XMLHttpRequest();
xml.setRequestHeader('Authorization', auth);
xml.open('GET',url)
// ExtJS
Ext.Ajax.request({
url : url,
method : 'GET',
headers : { Authorization : auth }
});
// jQuery
$.ajax({
url : url,
method : 'GET',
beforeSend : function(req) {
req.setRequestHeader('Authorization', auth);
}
});
HTTP基本认证(HTTP Basic Athorization)过程分析
在HTTP协议进行通信的过程中,HTTP协议定义了基本认证过程以允许HTTP服务器对WEB浏览器进行用户身份证的方法,当一个客户端向HTTP服务 器进行数据请求时,如果客户端未被认证,则HTTP服务器将通过基本认证过程对客户端的用户名及密码进行验证,以决定用户是否合法。
客户端在接收到HTTP服务器的身份认证要求后,会提示用户输入用户名及密码,然后将用户名及密码以BASE64加密,加密后的密文将附加于请求信息中, 如当用户名为anjuta,密码为:123456时,客户端将用户名和密码用“:”合并,并将合并后的字符串用BASE64加密为密文,并于每次请求数据 时,将密文附加于请求头(Request Header)中。
HTTP服务器在每次收到请求包后,根据协议取得客户端附加的用户信息(BASE64加密的用户名和密码),解开请求包,对用户名及密码进行验证,如果用 户名及密码正确,则根据客户端请求,返回客户端所需要的数据;否则,返回错误代码或重新要求客户端提供用户名及密码。
整个交互过程如下(模拟个登录GOOGLE首页的过程,并假设登录GOOGLE需要认证):
1,客户端向服务器请求数据,请求的内容可能是一个网页或者是一个其它的MIME类型,此时,假设客户端尚未被验证,则客户端提供如下请求至服务器:
Get /index.html HTTP/1.0
Host:www.google.com
这段信息表明,客户端向主机www.google.com请求其位于根目录下的index.html网页,使用http1.0协议。
2,服务器向客户端发送验证请求代码401,服务器返回的数据大抵如下:
HTTP/1.0 401 Unauthorised
Server: SokEvo/1.0
WWW-Authenticate: Basic realm="google.com"
Content-Type: text/html
Content-Length: xxx
<HTML>
<HEAD>
<TITLE>Error</TITLE>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=ISO-8859-1">
</HEAD>
<BODY><H1>401 Unauthorised.</H1></BODY>
</HTML>
3,当符合http1.0或1.1规范的客户端(如IE,FIREFOX)收到401返回值时,将自动弹出一个登录窗口,要求用户输入用户名和密码。
4,用户输入用户名和密码后,将用户名及密码以BASE64加密方式加密,并将密文放入前一条请求信息中,则客户端发送的第一条请求信息则变成如下内容:
Get /index.html HTTP/1.0
Host:www.google.com
Authorization: Basic xxxxxxxxxxxxxxxxxxxxxxxxxxxx
注:xxxx....表示加密后的用户名及密码。
5,服务器收到上述请求信息后,将Authorization字段后的用户信息取出、解密,将解密后的用户名及密码与用户数据库进行比较验证,如用户名及密码正确,服务器则根据请求,将所请求资源发送给客户端:
HTTP/1.0 200 OK
Server: www.google.com/http1.0
Content-Type: text/html
Content-Length: xxxx
<html>
网页内容
</html>
如用户名及密码不正确,请返回第2步,重新向客户端发送用户验证请求。
6,在以后的整个通信会话中,客户端均会在请求包中附加入加密后的用户信息。
HTTP基本认证的目标是提供简单的用户验证功能,其认证过程简单明了,适合于对安全性要求不高的系统或设备中,如大家所用路由器的配置页面的认证,几乎 都采取了这种方式。其缺点是没有灵活可靠的认证策略,如无法提供域(domain或realm)认证功能,另外,BASE64的加密强度非常低,可以说仅 能防止sohu的搜索把它搜到了。当然,HTTP基本认证系统也可以与SSL或者Kerberos结合,实现安全性能较高(相对)的认证系统。
想起用basic验证的服务器端的设置:
方式一:在web.xml中配置,可以参考CATALINA_HOME/server/manager/WEB-INF/web.xml
方式二:在程序中coding,参考如下:
if(request.getHeader("Authorization")==null){
response.setStatus(401);
response.setHeader("WWW-authenticate","Basic realm=\"请输入管理员密码\"");
}else if( !(request.getHeader("Authorization").equals(pass))){
response.setStatus(401);
response.setHeader("WWW-authenticate","Basic realm=\"用户名或者密码错误\"");
out.print("对不起你没有权限!!");
return;
}
GET /manager HTTP/1.0
Content-Type: application/x-www-form-urlencoded
Authorization: Basic <base64encode(user:pass)>
方法一:直接使用new sun.misc.BASE64Encoder().encode(byte[])构造HTTP头
方法二: Authenticator.setDefault(new AuthImpl()); 然后使用HttpURLConnection连接即可,这种方式更灵活
class AuthImpl extends Authenticator {
protected PasswordAuthentication getPasswordAuthentication() {
String user = "admin";
char pass[] = "admin".toCharArray();
nginx配置
虽然resin的配置也可以达到效果,但是毕竟是配置到了工程文件中,以后定期更换用户名与密码,都得更新项目描述符;而且有个更要命的问题,如果一个resin上有多个项目的话,一次更新就需要修改所有相关项目的web.xml文件,太麻烦了。在nginx上也可以配置basic认证,而且更简单。
nginx的http basic认证密码是用crypt(3)加密的,可以试用apache的htpasswd生成密码文件。首先进入apache的安装目录,进入apache/bin/目录下,可以看到htpasswd,输入如下命令生成密码文件。
htpasswd -c -d pass_file user_name
其中-c表示生成文件,-d表示是以crypt加密,pass_file是密码文件名,user_name表示basic认证的用户名,回车后会提示输入密码,然后再次输入确认,生成密码文件完成。
然后就是配置nginx,nginx的认证需要配置到location下,如下所示。
location ~ /admin/manage {
auth_basic "Auth";
auth_basic_user_file pass_file;
}
其中Auth可以随意设置,它只不过是当需要认证时弹出窗口的服务显示名称而已,pass_file就是我们之前生成的密码文件,这里要注意nginx 0.6.7开始,auth_basic_user_file的相对目录是nginx_home/conf,以前版本的相对目录是nginx_home,现在只要访问包含/admin/manage路径的资源都会弹出认证框,而且对于一个nginx代理了n个web服务的情况,需要更换用户名与密码时,只需要将密码文件替换一次即可,比第一种方式方便可靠了很多。