实现一个客户端通过给与的指定激活码,激活仅限当前机器使用具体软件的功能。客户端可能处于能连接互联网和无法连接互联网两种情况。同时均要实现在指定时间使权限过期的功能,激活码在使用时才开始计时。
这个就非常简单了,使用最简单的哈希加盐就可以实现了,与正常 REST 接口的哈希加盐验证只有,验证服务器端需要预先存好设置的激活码这一步。
激活码有效期就通过一个取巧的方法,将有效期的秒数转换成16进制,埋藏在序列号的指定段上。
在将当前时间和过期时间一起加盐,实现用户无法通过修改或锁定系统时间破解我们的系统。
当然,激活后,也要每隔一段时间验证一下是否过期,并且同时更新验证的时间戳,防止用户修改或锁定系统时间。
可以将鉴权放在请求前检验登录情况的装饰器里,每次更新只更新到flush里,在其他操作commit的时候再更新到数据库,防止一个请求里多个commit会导致数据无法回滚。
比较有风险的一点就是,用户可能会抓包服务端发到客户端的鉴权结果请求,然后伪造成功信息实现越过真实的鉴权结果,所以我们要设置一些比较特殊的字符串成功信息的字符串。或者可以实现类似银行电子狗,客户端-服务端均会随时间产生的相同动态加密校验码,与成功或失败信息加密后,再返回给客户端,保证中间过程即时被抓包,也无法破解。以下伪代码不考虑此过程
# 激活部分client伪代码
def online_active():
# 前端传递激活码
serial_number = form.serial_number.data
# 获取本机硬件信息
device_info = get_device_info()
# 盐
secret = config.secret
# 记录激活码过期时间
expire_time = int(serial_number[6:], 16) * (60 * 60 * 24)
expire_timestamp = now_timestamp + expire_time
# 硬件信息加盐生成的指纹
signature = md5(device_info, expire_timestamp, now_timestamp, secret)
# 向激活服务器发起验证请求
if verify_license(serial_number, device_info, expire_timestamp, now_timestamp, signature):
# 写入数据库
insert_active()
return True
else:
return False
# 激活部分server伪代码
def verify_license(serial_number, device_info, expire_timestamp, now_timestamp, signature):
# 验证是否存在对应的激活码
if serial_number in db:
# 与客户端一致,只要验证指纹是否一致就行了
if signature == md5(device_info, expire_timestamp, now_timestamp, secret):
return True
return False
# 客户端检测权限是否仍然有效
def is_active():
# 验证激活设备是否改变,同时验证了激活时间是否被篡改
timestamp_or_false = is_active_equipment()
if not expire_timestamp_or_false:
return False
# 获取下面每次鉴权写入数据库的时间last_timestamp,防止用户篡改系统时间,躲避过期机制
expire_timestamp, last_timestamp = expire_timestamp_or_false
# 是否因为超过过期时间而过期
if now_time > expire_timestamp:
return False
# now_time 为当前系统时间
# 防止用户锁定时间
if last_timestamp >= now_time:
return False
# 更新数据库中的now_timestamp并重新生成指纹
now_timestamp = now_time
signature = md5(something)
# 写入数据库
insert_active()
return True
# 客户端检测是否设备是否改变
def is_active_equipment():
# 其实就是重复哈希加盐鉴权的过程,只不过是将验证客户端指纹、验证服务器指纹改为了,
# 客户端指纹、客户端数据库指纹鉴权了
db_signature, serial_number, expire_timestamp, now_timestamp = get_db_signature()
# 获取本机硬件信息
device_info = get_device_info()
# 盐
secret = config.secret
# 硬件信息加盐生成的指纹
signature = md5(device_info, expire_timestamp, now_timestamp, secret)
if signature == db_signature:
return expire_timestamp, now_timestamp
return False
这里逻辑就比较恶心,但是还是类似上面在线激活的思想。只不过从客户端-激活服务器
改为了客户端-手机-激活服务器
。
客户端-手机
这一部分通过扫描二维码,自动跳转网址,给激活服务器发起请求实现。
具体流程(非常绕!)就是,在客户端输入激活码
,客户端生成一个携带设备等校验信息的二维码
和一个用于校验的校验码
,返回给前端的只有二维码
,用户扫描二维码
向激活服务器发起校验,如果校验成功,则生成一个和客户端一样的校验码
返回到用户手机上,用户将该校验码
再次输到客户端里。客户端自己生成的校验码
和用户输入的校验码
一致,则激活成功。如果校验失败,那向用户手机直接发送失败信息。
需要保证每次不同终端客户端-手机-服务端
、服务端-手机-客户端
生成的校验码
和签名
均是计算出来的,而不能存起来。
过期部分还是同在线激活方式相同,以下伪代码不做赘述。
与在线激活方式遇到的
中间人攻击
类似,这种方式最好在客户端-手机
、手机-服务器
这两个过程中加密信息,但是这篇文章讨论的是两种激活模式的业务逻辑实现,不涉及具体实现。
# 客户端输入激活码,使用请求地址和参数生成二维码
def generate_qr_code():
# 前端传递激活码
serial_number = form.serial_number.data
# 获取本机硬件信息
device_info = get_device_info()
# 盐
secret = config.secret
# 记录激活码过期时间
expire_time = int(serial_number[6:], 16) * (60 * 60 * 24)
expire_timestamp = now_timestamp + expire_time
# 硬件信息加盐生成的指纹
signature = md5(device_info, expire_timestamp, now_timestamp, secret)
# 生成校验码
pin_code = someting_Encrypt()
# 激活服务器的激活接口
request_url = "aaa.com/bbbb"
return request_url, 上面的相关信息
# 用户手机向验证服务器发起请求,返回pin_code
def offline_active():
# 鉴权,与在线激活同样
verify_license()
# 生成校验码
pin_code = someting_Encrypt()
return pin_code
# 客户端验证pin_code
def verify_pin():
# 获取前端发送过来的pin_code
pin_code = form.pin_code.data
# 生成校验码
if pin_code == someting_Encrypt():
return True
return False
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。