2013-03-02 21:52 3122人阅读 评论(0) 收藏 举报
对于一个中型或大型网站,有n个子项目在不同的服务器甚至不同的IDC部署和运行,SSO(单点登录)和无SESSION已经是必备的功能。在这种情况下用户登陆后的身份验证就会是一个问题。一种简单的解决办法就是登陆时将用户的身份写入cookie,为了安全再写入一个cookie的校验,防止cookie篡改。
1 <?php
2 $secretkey = '1234567890abcdefghi';
3 // …… 取出数据到 $data 的代码略去
4 if( md5( sha1( $password ) ) == $data['passowrd'] ) { // 登陆成功
5 $_COOKIE['uid'] = 1234;
6 $_COOKIE['nickname'] = 'soga';
7 $_COOKIE['token'] = md5( "uid:1234&nickname:soga&secretkey:1234567890abcdefghi" );
8 }
9 ?>
验证登陆合法性:
01 <?php
02 $secretkey = '1234567890abcdefghi';
03
04 if( $_COOKIE['token'] == md5( "uid:{$_COOKIE['uid']}&nickname:{$_COOKIE['nickname']}&secretkey:{$secretkey}" ) ) {
05 $login = true;
06 }
07 else {
08 $login = false;
09 }
10 ?>
这样实现有一些问题存在,密钥$secretkey会暴露在所有的程序内,存在安全隐患。所有产品的程序中都需要内置token校验的算法。
如果能在webserver层进行校验,直接告诉应用层校验结果,就可以避免上面的问题。找一种webserver上安全、稳定、高性能的实现,并且开发成本低的方案。我选择的是Nginx + ngx_lua。Nginx的稳定性、高性能搭配Lua的高性能、低成本开发,简直绝配。
Nginx+ngx_lua的编译安装就不在这里讲了。
Nginx 配置:
1 access_by_lua_file '/dir/test.lua';
test.lua 代码:
01 local secretkey='1234567890abcdefghi'
02 if ngx.var.cookie_uid == nil or ngx.var.cookie_nickname == nil or ngx.var.cookie_token== nil then
03 ngx.req.set_header("Check-Login", "NULL")
04 return
05 end
06
07 local ctoken = ngx.md5('uid:' .. ngx.var.cookie_uid .. '&nickname:' ..ngx.var.cookie_nickname .. '&secretkey:' .. secretkey)
08
09 if ctoken == ngx.var.cookie_token then
10 ngx.req.set_header("Check-Login", "Yes")
11 else
12 ngx.req.set_header("Check-Login", "No")
13 end
14
15 return
然后就可以测试一下了:
无cookie登陆测试
01 [root@localhost soft]# curl -v "http://yuenshui.com:88/test.php"
02 * About to connect() to yuenshui.com port 88
03 * Trying 122.0.66.162… connected
04 * Connected to yuenshui.com (122.0.66.162) port 88
05 > GET /test.php HTTP/1.1
06 > User-Agent: curl/7.15.5 (x86_64-redhat-linux-gnu) libcurl/7.15.5 OpenSSL/0.9.8b zlib/1.2.3 libidn/0.6.5
07 > Host: yuenshui.com:88
08 > Accept: */*
09 >
10 < HTTP/1.1 200 OK
11 < Server: nginx
12 < Date: Sun, 24 Jun 2012 10:38:09 GMT
13 < Content-Type: application/octet-stream
14 < Transfer-Encoding: chunked
15 < Connection: keep-alive
16 nil
17 <pre>$_SERVER:
18 Array
19 (
20 [TMP] => /tmp
21 [TMPDIR] => /tmp
22 [TEMP] => /tmp
23 [OSTYPE] =>
24 [MACHTYPE] =>
25 [MALLOC_CHECK_] => 2
26 [USER] => www
27 [HOME] => /home/www
28 [FCGI_ROLE] => RESPONDER
29 [SERVER_SOFTWARE] => nginx
30 [QUERY_STRING] =>
31 [REQUEST_METHOD] => GET
32 [CONTENT_TYPE] =>
33 [CONTENT_LENGTH] =>
34 [SCRIPT_NAME] => /test.php
35 [REQUEST_URI] => /test.php
36 [DOCUMENT_URI] => /test.php
37 [SERVER_PROTOCOL] => HTTP/1.1
38 [REMOTE_ADDR] => 114.93.76.130
39 [REMOTE_PORT] => 1037
40 [SERVER_ADDR] => 122.0.66.162
41 [SERVER_PORT] => 88
42 [SERVER_NAME] => yuenshui.com
43 [REDIRECT_STATUS] => 200
44 [HTTP_USER_AGENT] => curl/7.15.5 (x86_64-redhat-linux-gnu) libcurl/7.15.5OpenSSL/0.9.8b zlib/1.2.3 libidn/0.6.5
45 [HTTP_HOST] => yuenshui.com:88
46 [HTTP_ACCEPT] => */*
47 [HTTP_CHECK_LOGIN] => NULL
48 [PHP_SELF] => /test.php
49 [REQUEST_TIME] => 1340534289
50 [argv] => Array
51 (
52 )
53
54 [argc] => 0
55 )
56
57 $_COOKIE:
58 Array
59 (
60 )
token错误的测试:
01 [root@localhost soft]# curl -b "uid=12345;nickname=soga;token=aa6f21ec0fcf008aa5250904985a817b" "http://yuenshui.com:88/test.php"
02 <pre>$_SERVER:
03 Array
04 (
05 [TMP] => /tmp
06 [TMPDIR] => /tmp
07 [TEMP] => /tmp
08 [OSTYPE] =>
09 [MACHTYPE] =>
10 [MALLOC_CHECK_] => 2
11 [USER] => www
12 [HOME] => /home/www
13 [FCGI_ROLE] => RESPONDER
14 [SERVER_SOFTWARE] => nginx
15 [QUERY_STRING] =>
16 [REQUEST_METHOD] => GET
17 [CONTENT_TYPE] =>
18 [CONTENT_LENGTH] =>
19 [SCRIPT_NAME] => /test.php
20 [REQUEST_URI] => /test.php
21 [DOCUMENT_URI] => /test.php
22 [SERVER_PROTOCOL] => HTTP/1.1
23 [REMOTE_ADDR] => 114.93.76.130
24 [REMOTE_PORT] => 1059
25 [SERVER_ADDR] => 122.0.66.162
26 [SERVER_PORT] => 88
27 [SERVER_NAME] => yuenshui.com
28 [REDIRECT_STATUS] => 200
29 [HTTP_USER_AGENT] => curl/7.15.5 (x86_64-redhat-linux-gnu) libcurl/7.15.5OpenSSL/0.9.8b zlib/1.2.3 libidn/0.6.5
30 [HTTP_HOST] => yuenshui.com:88
31 [HTTP_ACCEPT] => */*
32 [HTTP_COOKIE] => uid=12345;nickname=soga;token=aa6f21ec0fcf008aa5250904985a817b
33 [HTTP_CHECK_LOGIN] => No
34 [PHP_SELF] => /test.php
35 [REQUEST_TIME] => 1340537366
36 [argv] => Array
37 (
38 )
39
40 [argc] => 0
41 )
42
43 $_COOKIE:
44 Array
45 (
46 [uid] => 12345
47 [nickname] => soga
48 [token] => aa6f21ec0fcf008aa5250904985a817b
49 )
token正确的测试:
01 [root@localhost soft]# curl -b "uid=1234;nickname=soga;token=aa6f21ec0fcf008aa5250904985a817b" "http://yuenshui.com:88/test.php"
02 <pre>$_SERVER:
03 Array
04 (
05 [TMP] => /tmp
06 [TMPDIR] => /tmp
07 [TEMP] => /tmp
08 [OSTYPE] =>
09 [MACHTYPE] =>
10 [MALLOC_CHECK_] => 2
11 [USER] => www
12 [HOME] => /home/www
13 [FCGI_ROLE] => RESPONDER
14 [SERVER_SOFTWARE] => nginx
15 [QUERY_STRING] =>
16 [REQUEST_METHOD] => GET
17 [CONTENT_TYPE] =>
18 [CONTENT_LENGTH] =>
19 [SCRIPT_NAME] => /test.php
20 [REQUEST_URI] => /test.php
21 [DOCUMENT_URI] => /test.php
22 [SERVER_PROTOCOL] => HTTP/1.1
23 [REMOTE_ADDR] => 114.93.76.130
24 [REMOTE_PORT] => 1059
25 [SERVER_ADDR] => 122.0.66.162
26 [SERVER_PORT] => 88
27 [SERVER_NAME] => yuenshui.com
28 [REDIRECT_STATUS] => 200
29 [HTTP_USER_AGENT] => curl/7.15.5 (x86_64-redhat-linux-gnu) libcurl/7.15.5OpenSSL/0.9.8b zlib/1.2.3 libidn/0.6.5
30 [HTTP_HOST] => yuenshui.com:88
31 [HTTP_ACCEPT] => */*
32 [HTTP_COOKIE] => uid=1234;nickname=soga;token=aa6f21ec0fcf008aa5250904985a817b
33 [HTTP_CHECK_LOGIN] => Yes
34 [PHP_SELF] => /test.php
35 [REQUEST_TIME] => 1340537463
36 [argv] => Array
37 (
38 )
39
40 [argc] => 0
41 )
42
43 $_COOKIE:
44 Array
45 (
46 [uid] => 12345
47 [nickname] => soga
48 [token] => aa6f21ec0fcf008aa5250904985a817b
49 )
http://yuenshui.com:88/test.php 打印信息的PHP代码:
01 <pre><?php
02 echo "\$_SERVER:\r\n";
03 unset($_SERVER['SCRIPT_FILENAME']);
04 unset($_SERVER['DOCUMENT_ROOT']);
05 unset($_SERVER['PATH']);
06 unset($_SERVER['HOSTNAME']);
07 unset($_SERVER['GATEWAY_INTERFACE']);
08 print_r($_SERVER);
09 echo "\r\n\$_COOKIE:\r\n";
10 print_r($_COOKIE);
11 ?>
上面是所有的测试程序。大家也可以通过curl进行测试http://yuenshui.com:88/test.php