用Nginx+Lua实现高性能、高可靠、安全的登陆验证

对于一个中型或大型网站,有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 ( x 86 _ 64 - redhat - linux - gnu) libcurl / 7 . 15 . 5 OpenSSL / 0 . 9 . 8 b 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 ( x 86 _ 64 - redhat - linux - gnu) libcurl / 7 . 15 . 5 OpenSSL / 0 . 9 . 8 b 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 = aa 6 f 21 ec 0 fcf 008 aa 5250904985 a 817b
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 ( x 86 _ 64 - redhat - linux - gnu) libcurl / 7 . 15 . 5 OpenSSL / 0 . 9 . 8 b 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 = aa 6 f 21 ec 0 fcf 008 aa 5250904985 a 817b
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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值