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