标签:style blog class code c java
对于现在 POST 技术满天飞的时代,防机器人确实是很头疼的一件事情,类似流量精灵这样的东西,他可以做到 100%
的真实信息,大批量的访问。
当然今天不谈这些,只是分析下 天涯论坛 回复时的验证策略。
昨天谈到 packer 压缩,今天我们来看个实例吧。
http://bbs.tianya.cn/m/reply.jsp?item=funinfo&id=4339425
这个是天涯论坛手机端的回复帖子页面,里面有一个关于回复验证的js,就是用的
packer压缩。
http://static.tianyaui.com/global/ty/util/TY.util.userAction.js?v=201404111018
真心不知道他们是怎么想的,1秒还原大法。。。
jQuery(function() { function i(B) { var D, l, n, C = document.cookie.substr(document.cookie.indexOf("&id=") + "&id=".length); C = C.substr(0, C.indexOf("&")), C = "" == C ? 8980291 : C, D = jQuery(B.target), l = (new Date).getTime(), n = "focusout" == B.type ? "blur" : "focusin" == B.type ? "focus" : B.type, n = n.replace("key", "").substring(0, 1), 0 == c && (c = l), d >= f && (d = 2), a["c" == n ? 1 : "f" == n ? 0 : d++] = n + e+++"." + ("c" == n ? B.pageX + ":" + B.pageY : "b" == n ? d : "f" == n ? c : B.which) + "." + (l - ("c" == n || "f" == n ? c : b)), b = l, ("b" == n || 17 == B.which) && (v = a.join(",") + "|" + k(a.join(",") + a[0] + C) + "|" + k(D.val() + a[0]) + "|" + navigator.userAgent + "|v2", 0 == jQuery("#" + h).length ? jQuery(‘<input type="hidden" id="‘ + h + ‘" name="action" value="‘ + v + ‘" />‘).insertAfter(D) : jQuery("#" + h).val(v)) } function k(l) { return o(m(p(l))) } function m(l) { return s(t(r(l), 8 * l.length)) } function o(D) { var l, n, B, C; try {} catch (E) { j = 0 } for (l = j ? "0123456789ABCDEF" : "0123456789abcdef", n = "", C = 0; C < D.length; C++) { B = D.charCodeAt(C), n += l.charAt(15 & B >>> 4) + l.charAt(15 & B) } return n } function p(C) { for (var n, B, D = "", l = -1; ++l < C.length;) { n = C.charCodeAt(l), B = l + 1 < C.length ? C.charCodeAt(l + 1) : 0, n >= 55296 && 56319 >= n && B >= 56320 && 57343 >= B && (n = 65536 + ((1023 & n) << 10) + (1023 & B), l++), 127 >= n ? D += String.fromCharCode(n) : 2047 >= n ? D += String.fromCharCode(192 | 31 & n >>> 6, 128 | 63 & n) : 65535 >= n ? D += String.fromCharCode(224 | 15 & n >>> 12, 128 | 63 & n >>> 6, 128 | 63 & n) : 2097151 >= n && (D += String.fromCharCode(240 | 7 & n >>> 18, 128 | 63 & n >>> 12, 128 | 63 & n >>> 6, 128 | 63 & n)) } return D } function r(n) { var l, B = Array(n.length >> 2); for (l = 0; l < B.length; l++) { B[l] = 0 } for (l = 0; l < 8 * n.length; l += 8) { B[l >> 5] |= (255 & n.charCodeAt(l / 8)) << l % 32 } return B } function s(n) { var l, B = ""; for (l = 0; l < 32 * n.length; l += 8) { B += String.fromCharCode(255 & n[l >> 5] >>> l % 32) } return B } function t(E, F) { var G, H, I, J, l, n, B, C, D; for (E[F >> 5] |= 128 << F % 32, E[(F + 64 >>> 9 << 4) + 14] = F, G = 1732584193, H = -271733879, I = -1732584194, J = 271733878, l = 0; l < E.length; l += 16) { n = G, B = H, C = I, D = J, G = w(G, H, I, J, E[l + 0], 7, -680876936), J = w(J, G, H, I, E[l + 1], 12, -389564586), I = w(I, J, G, H, E[l + 2], 17, 606105819), H = w(H, I, J, G, E[l + 3], 22, -1044525330), G = w(G, H, I, J, E[l + 4], 7, -176418897), J = w(J, G, H, I, E[l + 5], 12, 1200080426), I = w(I, J, G, H, E[l + 6], 17, -1473231341), H = w(H, I, J, G, E[l + 7], 22, -45705983), G = w(G, H, I, J, E[l + 8], 7, 1770035416), J = w(J, G, H, I, E[l + 9], 12, -1958414417), I = w(I, J, G, H, E[l + 10], 17, -42063), H = w(H, I, J, G, E[l + 11], 22, -1990404162), G = w(G, H, I, J, E[l + 12], 7, 1804603682), J = w(J, G, H, I, E[l + 13], 12, -40341101), I = w(I, J, G, H, E[l + 14], 17, -1502002290), H = w(H, I, J, G, E[l + 15], 22, 1236535329), G = x(G, H, I, J, E[l + 1], 5, -165796510), J = x(J, G, H, I, E[l + 6], 9, -1069501632), I = x(I, J, G, H, E[l + 11], 14, 643717713), H = x(H, I, J, G, E[l + 0], 20, -373897302), G = x(G, H, I, J, E[l + 5], 5, -701558691), J = x(J, G, H, I, E[l + 10], 9, 38016083), I = x(I, J, G, H, E[l + 15], 14, -660478335), H = x(H, I, J, G, E[l + 4], 20, -405537848), G = x(G, H, I, J, E[l + 9], 5, 568446438), J = x(J, G, H, I, E[l + 14], 9, -1019803690), I = x(I, J, G, H, E[l + 3], 14, -187363961), H = x(H, I, J, G, E[l + 8], 20, 1163531501), G = x(G, H, I, J, E[l + 13], 5, -1444681467), J = x(J, G, H, I, E[l + 2], 9, -51403784), I = x(I, J, G, H, E[l + 7], 14, 1735328473), H = x(H, I, J, G, E[l + 12], 20, -1926607734), G = y(G, H, I, J, E[l + 5], 4, -378558), J = y(J, G, H, I, E[l + 8], 11, -2022574463), I = y(I, J, G, H, E[l + 11], 16, 1839030562), H = y(H, I, J, G, E[l + 14], 23, -35309556), G = y(G, H, I, J, E[l + 1], 4, -1530992060), J = y(J, G, H, I, E[l + 4], 11, 1272893353), I = y(I, J, G, H, E[l + 7], 16, -155497632), H = y(H, I, J, G, E[l + 10], 23, -1094730640), G = y(G, H, I, J, E[l + 13], 4, 681279174), J = y(J, G, H, I, E[l + 0], 11, -358537222), I = y(I, J, G, H, E[l + 3], 16, -722521979), H = y(H, I, J, G, E[l + 6], 23, 76029189), G = y(G, H, I, J, E[l + 9], 4, -640364487), J = y(J, G, H, I, E[l + 12], 11, -421815835), I = y(I, J, G, H, E[l + 15], 16, 530742520), H = y(H, I, J, G, E[l + 2], 23, -995338651), G = z(G, H, I, J, E[l + 0], 6, -198630844), J = z(J, G, H, I, E[l + 7], 10, 1126891415), I = z(I, J, G, H, E[l + 14], 15, -1416354905), H = z(H, I, J, G, E[l + 5], 21, -57434055), G = z(G, H, I, J, E[l + 12], 6, 1700485571), J = z(J, G, H, I, E[l + 3], 10, -1894986606), I = z(I, J, G, H, E[l + 10], 15, -1051523), H = z(H, I, J, G, E[l + 1], 21, -2054922799), G = z(G, H, I, J, E[l + 8], 6, 1873313359), J = z(J, G, H, I, E[l + 15], 10, -30611744), I = z(I, J, G, H, E[l + 6], 15, -1560198380), H = z(H, I, J, G, E[l + 13], 21, 1309151649), G = z(G, H, I, J, E[l + 4], 6, -145523070), J = z(J, G, H, I, E[l + 11], 10, -1120210379), I = z(I, J, G, H, E[l + 2], 15, 718787259), H = z(H, I, J, G, E[l + 9], 21, -343485551), G = A(G, n), H = A(H, B), I = A(I, C), J = A(J, D) } return Array(G, H, I, J) } function u(D, E, l, n, B, C) { return A(q(A(A(E, D), A(n, C)), B), l) } function w(C, D, E, F, l, n, B) { return u(D & E | ~D & F, C, D, l, n, B) } function x(C, D, E, F, l, n, B) { return u(D & F | E & ~F, C, D, l, n, B) } function y(C, D, E, F, l, n, B) { return u(D ^ E ^ F, C, D, l, n, B) } function z(C, D, E, F, l, n, B) { return u(E ^ (D | ~F), C, D, l, n, B) } function A(B, C) { var l = (65535 & B) + (65535 & C), n = (B >> 16) + (C >> 16) + (l >> 16); return n << 16 | 65535 & l } function q(l, n) { return l << n | l >>> 32 - n } var j, a = [], b = 0, c = 0, d = 2, e = 0, f = 20, g = "#textAreaContainer,#sendMsg_content,#msg_textarea", h = "user_action"; jQuery(document).delegate(g, "blur", i).delegate(g, "keydown", i).delegate(g, "keypress", i).delegate(g, "keyup", i).delegate(g, "focus", i), j = 0 });
中间的加密算法可以忽略,可能是md5之类的算法,直接看这部分即可:
var j, a = [], b = 0, c = 0, d = 2, e = 0, f = 20, // 以上是一些初始化 g = "#textAreaContainer,#sendMsg_content,#msg_textarea", // 输入区域 h = "user_action"; // 最终验证值放在ID为 user_action 的元素里 jQuery(document).delegate(g, "blur", i).delegate(g, "keydown", i).delegate(g, "keypress", i).delegate(g, "keyup", i).delegate(g, "focus", i), j = 0; // 监听 g 变量里的元素,当 聚焦,失去焦点,键盘按下,抬起,按键 都会触发 i 函数。那详细的分析下 i 都做了些什么吧。 function i(B) { var D, l, n, C = document.cookie.substr(document.cookie.indexOf("&id=") + "&id=".length); C = C.substr(0, C.indexOf("&")), C = "" == C ? 8980291 : C, D = jQuery(B.target), l = (new Date).getTime(), n = "focusout" == B.type ? "blur" : "focusin" == B.type ? "focus" : B.type, n = n.replace("key", "").substring(0, 1), 0 == c && (c = l), d >= f && (d = 2), a["c" == n ? 1 : "f" == n ? 0 : d++] = n + e+++"." + ("c" == n ? B.pageX + ":" + B.pageY : "b" == n ? d : "f" == n ? c : B.which) + "." + (l - ("c" == n || "f" == n ? c : b)), b = l, ("b" == n || 17 == B.which) && (v = a.join(",") + "|" + k(a.join(",") + a[0] + C) + "|" + k(D.val() + a[0]) + "|" + navigator.userAgent + "|v2", 0 == jQuery("#" + h).length ? jQuery(‘<input type="hidden" id="‘ + h + ‘" name="action" value="‘ + v + ‘" />‘).insertAfter(D) : jQuery("#" + h).val(v)) }
这部分被编译过了,结构上被优化的比较变态,所以很难直接阅读,经过整理:
function i(B) { var D, l, n, C = document.cookie.substr(document.cookie.indexOf("&id=") + "&id=".length); // 为了取 cookies id 部分。。 C = C.substr(0, C.indexOf("&")), // 取ID值 C = "" == C ? 8980291 : C, // 如果没有,就用 8980291 // 看他取个ID都这么纠结,应该是个新手写的。。。 D = jQuery(B.target), // 当前元素 l = (new Date).getTime(), // 当前时间戳,用于计算每步操作时间差 n = "focusout" == B.type ? "blur" : "focusin" == B.type ? "focus" : B.type, // 修正事件名 n = n.replace("key", "").substring(0, 1), // 取事件名第一个字符 f, b, d, p, u 分别对应 focus, blur, keydown, keypress, keyup 0 == c && (c = l), // 上一次操作的时间戳,如果第一次操作,就用变量l的值。 d >= f && (d = 2), // d 是数组下标,范围是 2-20。下标 0, 1 固定值特殊处理 a["c" == n ? 1 : "f" == n ? 0 : d++] = n + e+++"." + ("c" == n ? B.pageX + ":" + B.pageY : "b" == n ? d : "f" == n ? c : B.which) + "." + (l - ("c" == n || "f" == n ? c : b)), // 这一行代码就验证重点,一个长度为 20 的数组,保存着获得焦点的时间戳和每个按键的记录 // a[0] 格式固定:"f" + 操作次数 + "." + 当前操作时间戳 + 与上次操作的时间间隔 // a[0] 的数据类似这样:f2.1400154199651.2678 // a[1] 忽略,直接空着即可,我也不知道 c 是什么事件,反正这个用不到。 // a[2] - a[19] 格式类似,前缀不同。d, p, u 为一组占用3个元素, // 例如:[d8.97.167, p8.97.1, u8.97.75] 表示第 8 次操作,按键码是97,d 是 keydown与上次按下间隔167ms,p 是 keypress操作与按下间隔97ms,u 是 keyup与keypress间隔75ms // 这样循环填充数组,比如大于20,会重新从2开始,3个值一组的往后填充 // 最后一个格式固定:"b" + 操作次数 + "." + 数组循环到几(2-20之间的值) + "." + 与上次操作间隔。 // 最后一个的数据类似这样:b12.14.862 b = l, // 保存本次操作的时间戳 if ("b" == n || 17 == B.which) { // 如果是失去焦点或者按了 ctrl(电脑上17是ctrl,手机端不知道是不是这个健) v = a.join(",") + "|" + k(a.join(",") + a[0] + C) + "|" + k(D.val() + a[0]) + "|" + navigator.userAgent + "|v2", // a 数组以 "," 拼接字符串 // k 应该是 md5 之类的,没具体测试 // 相当于 a数组 + "|" + md5(a数组 + 数组第一个元素 + 用户ID) + "|" + md5(用户输入的内容 + 数组第一个元素) + "|" + 浏览器信息 + "|v2" if (0 == jQuery("#" + h).length) { // 如果不存在 id="user_action" 的元素,就创建并插入到输入框后面 jQuery(‘<input type="hidden" id="‘ + h + ‘" name="action" value="‘ + v + ‘" />‘).insertAfter(D) } else { // 如果操作就直接更新内容 jQuery("#" + h).val(v) } } }
总体来说,代码并不是很难,可能光看代码比较难理解,我是动态调试着看的,不然会很费时间。
他生成的数据大概是这样:
f8.1400154504548.1565,,d8.97.167,p8.97.1,u8.97.75,d9.117.143,p9.117.4,u9.117.22,b10.8.2283,p4.114.3,u4.114.53,d5.116.122,p5.116.3,u5.116.2,d6.122.136,p6.122.5,u6.122.98,d7.105.49,p7.105.4,u7.105.79|094175120fb2ae4d5977afbe3fc04447|9de7848b9e445ba83c030b90651347fc|Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.131 Safari/537.36|v2
第一个和最后一个格式固定,中间的内容,3个为一组循环填充。
当然 最后一个 不是指数组的最后一个元素,因为他的数据是 2-19
循环填充的,可能最后一个重新轮到 2 或者是 4 所以这个是不固定的。
最重要的数据是:数组第一个值,用户输入内容 和
浏览器信息
因为他最终生成的验证值是:a数组 + "|" +
md5(a数组 + 数组第一个元素 + 用户ID) + "|" + md5(用户输入的内容 + 数组第一个元素) + "|" + 浏览器信息 +
"|v2"
这样的格式,所以其他数据也许可以随便乱填,我没具体测试,只是按照他的格式生成的,提交测试通过。
post 成功。
细心的朋友可能会发现怎么是
2014-05-09,
其实这个是之前人家花钱找我写的一个东西,我不好意思把我写的代码直接发出来,毕竟人家花钱的东西,我免费到处乱发也不是回事。
所以只给个思路,有兴趣的朋友可以和我深入探讨。
天涯的这个验证思路还是不错的,记录每次操作的时间,按键,操作间隔,然后把这个按键记录+用户ID md5一下,又把 用户输入的数据+第一个元素 md5
一下。
后台进行数据效验,这样能过滤掉一大批机器人 POST 信息,因为不是每个会 POST 的都是高手,不然也不会花钱找我写这个东西了。
把这方案加到自己项目里,应该也是个不错的选择。
今天分享完毕,明天见。
标签:style blog class code c java
原文地址:http://www.cnblogs.com/52cik/p/js-reply-verify.html