网易将军令是一种动态的密码保护器,还有赛门铁克的vipAccess也是一种动态密码保护器。
它们的特点是可以离线动态生成,同时每过一分钟或者半分钟之后,密码都会变化一次,是一个六位数的密码。
这个密码的用途是在你输入你的账号加上固定密码之后,还需要额外输入一个动态密码。这个就是上面说的动态密码。其中网易将军令是用在网易游戏上的,赛门铁客的vipAccess是用在企业登录的二次验证的。
当初小时候我以为网易将军令是通过发短信啥的,现在看来其实并不是,是可以做到在离线情况下动态生成密码的。
微信支付和支付宝的付款码都是支持离线支付的,也就是你在没有网络的情况下,也可以使用付款码。
我把它们称为offline token(离线凭据)。
示例图片:
今天的文章主要是讲一下我自己对offline token实现的一种思路,供大家参考。当然我也不是这些企业的员工,也不清楚它们真正使用的技术细节。主要是如果让我来实现上面的功能,我会怎么做。
如果有不同的想法,欢迎评论和我探讨,谢谢。
接下来讲第一种离线token的实现方式:
第一种离线token需要服务器和客户端使用相同的加密算法和逻辑,以时间作为加密内容,实现动态密码
具体的实现逻辑就是,将军令使用内置的秘钥,根据当前的时间,当前时间可以是半分钟级别的,也可以是分钟级别的,使用加密算法和哈希算法生成一个6位数的动态密码。在验证的时候,服务器查找账户对应的将军令秘钥,使用同样的逻辑和算法得到一个6位数的动态密码,如果可以匹配则验证通过。需要服务器和将军令的时间误差要尽可能越小越好。
这里以AES加密算法为例,也可以用其它类型的加密算法。
将军令在出厂的时候,这个将军令的设备肯定是和你的游戏账户绑定的,将军令里面肯定内置了加密的秘钥的。
因此可以在数据库里记录将军令使用的秘钥和游戏账户,把这两个关联起来。
这里用python举个例子
下面是简单的aes算法:
# 补足字符串长度为16的倍数
def add_to_16(s):
while len(s) % 16 != 0:
s += '\0'
return str.encode(s) # 返回bytes
class Aes:
def __init__(self, key):
self.key = add_to_16(key)
self.aes = AES.new(str.encode(key), AES.MODE_ECB)
def encrypt(self, content):
return str(base64.encodebytes(self.aes.encrypt(add_to_16(content))), encoding='utf8').replace('\n', '') # 加密
def decrypt(self, content):
return str(
self.aes.decrypt(base64.decodebytes(bytes(content, encoding='utf8'))).rstrip(b'\0').decode("utf8")) # 解密
假设将军令出厂内置的秘钥是08408d58982111e9b729a0999b140833,用户的游戏id是iamdev,那么在出厂的时候,网易的游戏数据库就会记录下iamdev绑定了一个将军令设备,秘钥是08408d58982111e9b729a0999b140833
那么怎么形成一种每隔一分钟就会变化一次的效果呢?
可以使用当前unix的时间戳,然后精确到分钟即可,获取到秒级的时间戳之后,使用
t = t-t%60即可获取到一个分钟级别的时间戳,这样的话,将军令在
12点53分23秒加密的结果和12点53分45秒加密的效果是一样的,因为都会被精确到分钟级别,也就是12点53分00秒
if __name__ == '__main__':
t = int(time.time())
t = t - t % 60
print(t)
key = "08408d58982111e9b729a0999b140833"
print(str(key))
aes = Aes(str(key))
encrypt_text = aes.encrypt(str(t))
print('加密值:', encrypt_text)
print('解密值:', aes.decrypt(encrypt_text))
上述测试打印的结果是
1561560480
08408d58982111e9b729a0999b140833
加密值: BBJxBAUnVVucCALYRLyJ5A==
解密值: 1561560480
怎么获取到一个6位数的数字呢?
借助python的hash函数即可实现,因为python的hash函数可能会返回负数,所以取的区间是1:7。
print(str(hash(encrypt_text))[1:7])
#098182
在二次验证的时候,将显示的动态密码输入,发送到服务器。服务器通过在数据库里面查找这个账号对应的将军令的秘钥,然后使用相同的加密算法和哈希算法计算获取到数字,如果一样的话,那就是验证通过。
只要服务器上的时间和将军令设备的时间差不超过一分钟,都可以验证通过。
举个例子,如果将军令当前的时间为8点54分23秒,而服务器的时间是8点54分25秒,都是可以验证通过的。
即便有人记住了你的动态密码,但是他下次登录是没法使用的,因为每次生成的动态密码都是不一样的
下次登陆的时候的时间就不是那个时间了,而且时间差远大于一分钟。
除此之外,如果为了允许一定范围的时间误差,服务器是可以往前或者往后计算多一分钟都是可以的。
上面的逻辑其实也是对应VIP Access的。
我自己亲自测试过VIP access的客户端,如果把网络断开,然后来回kill掉,并重新打开客户端,发现这个6位数是一样的。因此明显是和当前时间是有关联的。
从安全角度来说,将军令出厂内置了秘钥,而且黑客是不知道你的秘钥的,所以是很安全的。而且黑客只能使用网络攻击,黑客和第三方是无法通过网络窃取你的将军令的秘钥的,而且这个设备也是在你身边,也是无法被窃取的。
其实扩展开来想的话,是可以思考清楚类似银行的动态密码保护器怎么做的?
usb u盾,用户在拿到的时候,是需要首次初始化,连接到电脑,然后从银行下载私钥的。
当然如果网易自己的服务器被黑了导致秘钥泄露的话,那其实也不是用户的问题。
未完待续,下一章节讲一下微信支付和支付宝支付的离线付款码的思路。