客户端内嵌WebView与浏览器访问页面的安全机制

近期新增代理商系统,游戏内加入webview以及从浏览器登录系统两种方式。作为服务端开发,与主管讨论之后,不同已有基于netty开发的多个服务器,服务端新增基于Spring-boot开发的服务器提供微服务。本文介绍安全机制设计与实现。

客户端内嵌WebView与服务器通信的加密方案

安全验证采用token做密钥,摘要算法保证内容正确。摘要算法采用最常见的MD5即可。
加密过程是服务端生成token,并把这个token发给客户端,客户端(这里包括WebView内页面)每次请求都附带stime以及token, 对这个字符串做计算形成摘要(sign)。
客户端调用WebView之前,通过protobuffer协议获取token。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//请求访问代理页面的token
message CGGetAgtTokenREQ
{
}
message GCGetAgtTokenRES
{
required int32 result = 1;
required string token = 2;
}
<Protocol P_CG_GET_AGT_TOKEN_REQ = "请求访问代理页面的token"
PROTOCOL_CLASS="com.kodgames.message.proto.game.GameProtoBuf.CGGetAgtTokenREQ" />
<Protocol P_GC_GET_AGT_TOKEN_RES = "响应token"
PROTOCOL_CLASS="com.kodgames.message.proto.game.GameProtoBuf.GCGetAgtTokenRES" >
<String name="GC_GET_AGT_TOKEN_SUCCESS" isSuccess="true">请求成功</String>
<String name="GC_GET_AGT_TOKEN_FAILED">请求失败</String>
</Protocol>

此时客户端得到的token格式是:

1
"GAME-"+随机字符串

随机字符串生成规则采用:

1
UUID.randomUUID().toString().replaceAll("-", "").substring(0,16).toUpperCase();

客户端第一次拉起WebView,发送格式如下。页面直接将请求参数转发到服务端,服务端拿到完整url,在拦截器中用同样的算法做身份验证:

1
2
3
4
5
6
7
http://172.16.2.172:8091/agent/is_agent?id=5006872&stime=1497680416778&sign=35454B055CC325EA1AF2126E27707052
其中
token = "GAME-XXXXXXXXX"
path = "/agent/is_agent"
queryString = "id=5006872&stime=1497680416778"
sign = md5(queryString + "&token=" + token)

queryString是未加密之前的请求字符串,stime是客户端当前时间戳,服务端设置请求有效时间为一分钟,防止重放攻击。由于token只在第一次由服务端下发给客户端,后续无传输,所以在不泄露token的前提下,可有效保证客户端提交数据合法。

token发放机制,采用双token隔离安全性:

1
2
3
4
5
6
7
8
9
客户端初次请求服务端获取token,此时token="GAME-"+随机字符串。
客户端拉起webview访问页面,页面第一次向服务端提交请求,控制器判断token的类型,如果token类型是"GAME-"+随机字符串,则控制器重新发放页面内专用的token。此时token="AGENT-"+随机字符串。
webtoken是通过cookie的机制发送:
Cookie cookie = new Cookie("token",token);
httpServletResponse.addCookie(cookie);
后续页面内请求均采用此token。退出页面时,把cookie置空,以免token泄露。

每次客户端访问时,会重新向服务端请求token,服务端更新token后发送给客户端。

浏览器网页登录与服务器通信的加密方案

浏览器访问的用户认证不采用传统的sessionId,沿袭内嵌WebView与服务器通信的token认证,通过访问路径区分三种安全机制:

  • 用户登录及修改密码采用临时token策略,用户进入页面即获取临时token及uuid,登录请求时携带uuid。服务端验证通过后,将临时token写入到用户正式表中,临时token表删除token。出现到一个问题,就是只有认证成功的用户,临时token才会被删除,其他情况不会被删除,导致临时token表即会越来越大,采用定时任务删除临时表token,即临时token表每天凌晨四点清理一次。涉及到密码相关的传输,密码本身要先加密一次。

  • 用户登录后的安全保障同内嵌WebView与服务器通信的安全机制相同。

  • 发送验证码、初次进入页面、用户确认等无安全威胁的请求,不走安全验证,服务端无需过滤。

举例说明,初次访问页面及登录请求格式如下:

1
2
3
http://172.16.2.163:8091/no_filter/first_come
http://172.16.2.163:8091/agent/community_login?id=10003&name=10001&pwd=20CC88D2E204FFA768509D33FA882492&type=1&uuid=2f52ef92b73b43659045567ba29881c4&stime=1498728038692&sign=ECD622B701C2B90E33319E7E08A422A9