之前做过第一版,后面再次实践时,发现有改进空间
与之前对比
第一版使用的思路是时间范围,这种方式产生激活码,只是限制了激活码的有效时长,却不能限制激活码的使用范围。所以第二版对比第一版,改进如下:
- 能与设备进行强绑定(需有渠道获取设备的唯一id码)
- 更优化的算法
- 在环境不变的情况下,激活码使用有效,与时间无关
- 根据需要可在激活码中加入授权结束时间,程序每次启动从激活码中读取该时间,并与当前时间进行比对,到期则提醒用户激活(本文未实现,可自行实现)
实现方法
再次说明下校验码的生效逻辑:
- 从设备获取一个能够标识设备的唯一id,用户可在软件上获取,并发给管理员
- 管理员利用该唯一id,通过一定的算法,生成一个激活码,并将该激活码发给客户
- 客户在激活界面输入激活码,用户端的软件,会获取同样的唯一id,使用同样的逻辑对唯一id进行加密,并将加密的结果与管理员给的激活码进行对比,一致则激活成功,否则激活失败
代码实现(typescript)
以下代码可以生成一个只包含数字和大小写字母的验证码,并且可以自行指定长度。哪怕只是改变其中一个字符,所生成的验证码也是截然不同的(这也是对比第一版进步的地方)
function getSrcHashCode(str: string, len: number) {
// 先判断待处理字符串的长度是否能被目标hash字符串的长度整除
const remainder = str.length % len; // 长度的余数
let newStr = str; // 保存拼接后的字符串
if (remainder != 0) {
const fillStr = new Array(len - remainder).fill(ascill2Word(str.length % 62)).join(""); //new一个字符串填充str
newStr = fillStr + str;
}
// 计算newStr的字符串ASCII码总和
let total: number = 0; // 保存字符串的ASCII总和
for (let i = newStr.length; i >0; i--) {
total += newStr.charCodeAt(i-1) * i;
}
const segmentLen = newStr.length / len; // 将字符数组分为HashCodeLen段,每段的长度
let result: string[] = new Array(len); // 装计算好的hashcode
for (let i = len; i >0; i--) {
let tmpSum = 0; // 记录每一段的和
let index = i * segmentLen; // 每一段字符的起点
for (let j = index; j < index + segmentLen; j++) {
// 每次循环segmentLen长度的字符
tmpSum += newStr.charCodeAt(j) * i;
}
result[i-1] = ascill2Word((total - tmpSum) % 62);
}
return result.join("");
}
// 针对数字和大小写字母的ASCII码转字符,数字加大小写字母共62个,所以ascill取余后的取值范围是[0,61],以下根据需要自行修改即可
function ascill2Word(ascill: number) {
// 数字加大小写字母共62个,排序为数字、大写字母、小写字母
if (ascill < 10) {
// 转化成数字
return String.fromCharCode(ascill + 48);
} else if (ascill >= 10 && ascill < 36) {
// 转化成大写字母
return String.fromCharCode(ascill + 55);
} else if (ascill >= 36 && ascill < 62) {
// 转化成小写字母
return String.fromCharCode(ascill + 61);
} else {
return "";
}
}
使用场景分析
- Windows等平台的离线app,这个就不用说了,就像操作系统那样,都是需要激活码的,当然人家的肯定更复杂。一样会被人破解,只要你的软件有破解的价值
- 手机上的离线程序,这个也是一样可以实现的,手机上的难点是获取有效的唯一id,这点很难,我研究了很久,依然无法保证正常使用下的唯一id。现在很多手机都做了限制,连OAID都不给获取。
针对第二点的浅谈
我发现我安装的某款软件真的可以唯一标识我的设备,卸载软件,清除缓存,更新OAID等可以想到的手段都无法避开这个标识,并且跟时间无关,并且,它没有额外获取任何权限,我把所有权限关了,他都还能标识我,我是真的很想知道怎么做到的,如有大佬知道,麻烦告知一声
我的想法
我思考了很久, 我只想到一种可能:它在某个不需要访问权限的文件夹里,自动生成了一个文件并保存了一个标识符,这个标识符可能是它自己生成的。并且这个文件不会被清除缓存,卸载软件等方法删除。
所以即使重装软件也没用,它一获取该文件就能重新标识用户。
只是,这样不需要权限且不会被清除的文件是存在的吗?