当前位置: > Linux服务器 > nginx >

结合Nginx+Lua实现安全高并发的登录验证

时间:2015-01-21 23:33来源:linux.it.net.cn 作者:IT

对于一个中型或大型网站,有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.5 OpenSSL/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.5 OpenSSL/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.5 OpenSSL/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 ?>

(责任编辑:IT)
------分隔线----------------------------
栏目列表
推荐内容