`
tang9140
  • 浏览: 35124 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

关于12306第三方软件检测研究

 
阅读更多

转载请注明出处:http://blog.csdn.net/tang9140/article/details/42869269


首先申明下,本文章纯作为个人喜好的技术性研究,请不要用于非法操作盈取不正当利益,你懂的。

问题引出

大概在2014年12月的17、18号,大量针对12306的刷票软件出现了非法请求或‘使用第三方购票软件’提示,并且验证码识别出错。后面得知12306为了对恶意抢票软件、插件进行遏制与防控,通过手段能识别出抢票软件和用户购票的行为差别。

那么问题来了。。。,我就很好奇,他们通过什么手段做到的呢。

补充下,我之前是有做过JAVA版的抢票软件,仅做学习用途,没其它目的。在12306加了第三方软件检测后,我的刷票软件同样出现了‘非法请求’提示,连登录都进不去。于是引发了我的思考。

抢票软件本质是什么?

我个人认为抢票软件无非是用机器人(实际上所谓的机器人就是一个软件,这里只是形象表述)代替实体人去购买车票。大家都知道机器反应快,因此在同时开抢的前提下,肯定是机器比实体人快,这也是为什么黄牛党能买到车票,而你买不到车票的原因。继续往下思考,为什么机器人能够代替实体人去进行买票的一系列操作?这就引出了下一个问题。

用户在浏览器上购买车票的一系列操作,从技术角度看,本质上发生了什么?

大家都知道,12306网站提供的是基于B/S架构的WEB服务,是建立在http协议之上的服务。http协议是典型的请求-应答模式的协议,是无状态的协议。实际上用户在浏览器上的所有操作,最终都是依托浏览器发送请求到服务端,服务端接收到请求后进行相应的业务处理并将响应结果返回到浏览器端,浏览器再显示给用户。更具体点说,浏览器接收用户的各种事件(例如鼠标单击事件,键盘输入事件)后,然后在后台发送http请求到服务端,同时浏览器后台会接收到服务端的响应内容并展示为HTML页面。

更一般化,对于服务器来说,只要收到的请求是符合HTTP协议的就会进行处理,它不关心请求是通过浏览器发送过来的还是刷票软件发送过来的(浏览器本身也是一个软件,一般操作系统都自带浏览器)。从上面分析可以看出,只要第三方软件去完全模拟浏览器发送符合规范的HTTP请求,WEB服务器就会当作合法的请求并进行处理。那么问题又来了,为什么刷票软件会出现“非法请求”提示呢,这不跟你刚才的分析有矛盾吗?这个嘛,其实不矛盾。请注意我刚才说的是“完全模拟浏览器”,之前作为学习版的抢票软件并没有严格按照浏览器方式去发送HTTP请求,这也就导致12306能通过一些技术手段检测出非法的请求。那么,引出了我们的终极问题

12306怎么进行技术检测的,怎么区别正常请求跟非法请求?

在回答这个问题前,大家先要了解下HTTP协议。HTTP请求消息分为四部分:请求行、请求头、空行、可选的请求消息体;共有八种请求方法,最常用的就两种:GET请求和POST请求。GET请求将参数带在URL后面(没有消息体),而POST请求将参数带在消息体中。请求头中可能包含Cookie信息等。回到正题,12306对于非法请求检测无非对三方面进行检查,即请求头、Cookie、请求参数。

12306检测三方面:

1、请求头

在模拟HTTP请求时,需要注意请求头的顺序。经过本人测试,如果登录请求的‘Cookie请求头’放置在‘Connection请求头’后面时,会提示‘非法请求’

2、Cookie

Cookie请求头同样要注意顺序,先是JSESSIONID(中间其它cookie)最后是BIGipServerotn,current_captcha_type

3、请求参数

还是顺序的问题,请严格参照浏览器发送请求参数的顺序进行发送。除此之外,12306在登录和提交订单时还增加了动态key验证。你需要先获取到动态js文件的url地址,然后访问该js文件内容,提取出其中的key值,并用该js文件中的加密算法对key加密后形相应的value值。

通过上述三方面的检测,就能够发现一些非法请求。当然有第三方软件检测,也就有反检测。在12306推出这一系列第三方软件检测、监控及更换验证码(我相信有三套不同的验证码)后的数小时,一些刷票软件就进行了破解。其实本人觉得所谓的第三方软件检测完全是治标不治本,就好像游戏中的反外挂检测一样,在强大的外挂研发人员看来,完全不堪一击。不管你加了多少次验证,不管你怎么更换验证规则,都会很快的被破解。我倒觉得,与其把时间花在怎么反外挂上,还不如内部提供外挂,借鉴游戏的做法,12306倒不如内部提供一键抢票功能,不需要经过选车次,选乘客,提交下单验证码,再次确认等复杂过程。直接按照用户事先设定好的规则一键抢票(需要保证用内部一键抢票功能比外部刷票软件抢到票的概率要高),这样还来得实在些,你怎么看呢。支持的赞个

码字不易,源头来自http://blog.csdn.net/tang9140。

另附上关于KEY加密算法的JAVA版实现代码,感兴趣的同学可以看下

public class DynamicJsUtil {
    
    private static String keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
    
    static class Base32 {
        
        private static int delta = 0x9E3779B8;
        
        public static String longArrayToString(int[] data, boolean includeLength) {
            int length = data.length;
            int n = (length - 1) << 2;
            if (includeLength) {
                int m = data[length - 1];
                if ((m < n - 3) || (m > n))
                    return null;
                n = m;
            }
            
            StringBuilder sb = new StringBuilder("");
            for (int i = 0; i < length; i++) {
                int i0 = data[i] & 0xff;
                int i8 = data[i] >>> 8 & 0xff;
                int i16 = data[i] >>> 16 & 0xff;
                int i24 = data[i] >>> 24 & 0xff;
                if (i0 != 0)
                    sb.append((char)i0);
                if (i8 != 0)
                    sb.append((char)i8);
                if (i16 != 0)
                    sb.append((char)i16);
                if (i24 != 0)
                    sb.append((char)i24);
            }
            
            String result;
            if (includeLength) {
                result = sb.substring(0, n);
            }
            else
                result = sb.toString();
            return result;
        }
        
        public static int[] stringToLongArray(String str, boolean includeLength) {
            int length = str.length();
            int arrsize = length % 4 == 0 ? length / 4 : length / 4 + 1;
            int[] result = new int[arrsize];
            for (int i = 0; i < length; i += 4) {
                if (i + 4 > length) {
                    int char8 = i + 1 >= length ? 0 : str.charAt(i + 1) << 8;
                    int char16 = i + 2 >= length ? 0 : str.charAt(i + 1) << 16;
                    int char24 = i + 3 >= length ? 0 : str.charAt(i + 1) << 24;
                    result[i >> 2] = str.charAt(i) | char8 | char16 | char24;
                }
                else
                    result[i >> 2] =
                        str.charAt(i) | str.charAt(i + 1) << 8 | str.charAt(i + 2) << 16 | str.charAt(i + 3) << 24;
            }
            if (includeLength) {
                int[] newArr = new int[arrsize + 1];
                System.arraycopy(result, 0, newArr, 0, arrsize);
                newArr[arrsize] = length;
                result = newArr;
            }
            return result;
        }
        
        public static String encrypt(String str, String key) {
            if (str == "") {
                return "";
            }
            int[] v = stringToLongArray(str, true);
            int[] k = stringToLongArray(key, false);
            if (k.length < 4) {
                int[] newArr = new int[4];
                System.arraycopy(k, 0, newArr, 0, k.length);
                k = newArr;
            }
            int n = v.length - 1;
            int z = v[n], y = v[0];
            int mx, e, p, sum = 0;
            int q = 6 + 52 / (n + 1);
            while (0 < q--) {
                sum = sum + delta & 0xffffffff;
                e = sum >>> 2 & 3;
                for (p = 0; p < n; p++) {
                    y = v[p + 1];
                    mx = (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
                    z = v[p] = v[p] + mx & 0xffffffff;
                }
                y = v[0];
                mx = (z >>> 5 ^ y << 2) + (y >>> 3 ^ z << 4) ^ (sum ^ y) + (k[p & 3 ^ e] ^ z);
                z = v[n] = v[n] + mx & 0xffffffff;
            }
            return longArrayToString(v, false);
        };
    }
    
    public static String encode32(String input) {
        input = escape(input);
        StringBuilder output = new StringBuilder();
        int length = input.length();
        int chr1, chr2, chr3;
        int enc1, enc2, enc3, enc4;
        int i = 0;
        do {
            chr1 = input.charAt(i++);
            enc1 = chr1 >> 2;
            output.append(keyStr.charAt(enc1));
            
            if (i < length) {
                chr2 = input.charAt(i++);
                enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
                output.append(keyStr.charAt(enc2));
                
                if (i < length) {
                    chr3 = input.charAt(i++);
                    enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
                    enc4 = chr3 & 63;
                    output.append(keyStr.charAt(enc3)).append(keyStr.charAt(enc4));
                }
                else {
                    enc3 = ((chr2 & 15) << 2) | (0 >> 6);
                    output.append(keyStr.charAt(enc3)).append(keyStr.charAt(64));
                }
            }
            else {
                enc2 = ((chr1 & 3) << 4) | (0 >> 4);
                output.append(keyStr.charAt(enc2)).append(keyStr.charAt(64)).append(keyStr.charAt(64));
            }
        } while (i < length);
        return output.toString();
    }
    
    static String bin216(String s) {
        s += "";
        String output = "";
        int l = s.length();
        for (int i = 0; i < l; i++) {
            char c = s.charAt(i);
            String temp = Integer.toString(c, 16);
            output += temp.length() < 2 ? "0" + temp : temp;
        }
        return output;
    }
    
    public static String escape(String src) {
        char j;
        StringBuffer tmp = new StringBuffer(src.length() * 2);
        for (int i = 0; i < src.length(); i++) {
            j = src.charAt(i);
            if (Character.isDigit(j) || Character.isLowerCase(j) || Character.isUpperCase(j))
                tmp.append(j);
            else if (j < 256) {
                if (j == '*' || j == '@' || j == '-' || j == '_' || j == '+' || j == '.' || j == '/') {
                    tmp.append(j);
                }
                else {
                    tmp.append("%");
                    if (j < 16)
                        tmp.append("0");
                    tmp.append(Integer.toString(j, 16).toUpperCase());
                }
            }
            else {
                tmp.append("%u");
                tmp.append(Integer.toString(j, 16));
            }
        }
        return tmp.toString();
    }
    
    /**
     * 获取动态加密value值
     * @param key
     * @return
     */
    public static String getRandomParamValue(String key) {
        return encode32(DynamicJsUtil.bin216(Base32.encrypt("1111", key)));
    }
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

分享到:
评论

相关推荐

    12306 火车票 抢票 软件

    此外,使用第三方软件可能涉及隐私泄露风险,用户在使用时需谨慎,选择信誉良好、安全可靠的软件。 综上所述,12306火车票抢票软件凭借其快速抢票能力和全面的功能设计,成为许多旅客在节假日出行时的重要助手。...

    12306辅助登录软件

    12306辅助软件,测试过了能登录上去,输入12306的用户名和密码就可以登录了。

    12306极速抢票软件

    一是隐私安全,任何第三方软件的使用都需要谨慎对待个人账户信息,确保软件来源可靠,避免个人信息泄露。二是遵循12306官网的规定,不违反其使用条款,防止因使用抢票软件被封号。三是网络环境,抢票过程需要稳定的...

    12306订票助手软件版 (测试版)

    同时,下载并安装任何第三方软件时,用户都应谨慎对待,注意防范潜在的安全风险,比如病毒、恶意软件等。 综上所述,12306订票助手软件版虽然在某些方面能提高购票效率,但其测试版的不完善和稳定性问题提示我们,...

    12306抢火车票软件

    此外,中国铁路总公司官方并不支持或推荐使用第三方抢票软件,因为它们可能会对系统的稳定性和公平性造成影响。因此,用户在使用这类软件时应保持警惕,确保来源可靠,同时遵循12306官网的相关规定,避免违规操作。

    12306铁路抢票软件

    这款软件的开发者深入研究了12306官网的购票接口,通过编程技术实现了自动监控余票、快速提交订单等功能,旨在解决春节期间回家难的问题。本文将探讨该软件的部分实现细节,包括所使用的编程语言、框架以及核心算法...

    全自动订票软件(12306)

    【全自动订票软件(12306)】是一款针对中国铁路客户服务中心12306网站设计的辅助购票工具,特别适用于2013年的购票环境。此软件旨在简化购票流程,通过自动化操作帮助用户在繁忙的购票季节快速、高效地完成火车票...

    C#编写12306登录小软件

    C#可以使用AForge.NET或Emgu CV等第三方库来处理图像,识别验证码中的文字。识别过程可能包括预处理(如灰度化、二值化)、特征提取和模式匹配等步骤。 五、UI设计 为了构建用户友好的登录界面,我们可以使用C#的...

    12306火车票自动抢票软件

    在具体实现上,自动抢票软件可能采用不同的编程语言,如Python、JavaScript、Java等,同时可能借助各种第三方库和框架,如Selenium用于网页自动化操作,requests库用于网络请求,BeautifulSoup或Scrapy用于网页解析...

    12306的抢票软件

    然而,值得注意的是,使用这类软件可能存在法律风险,因为12306网站有明确的规定禁止使用任何插件或第三方软件进行抢票,以免影响系统的正常运行和公平购票。因此,在使用此类工具时,用户应确保了解并遵守相关规定...

    抢票软件的12306java实现

    抢票软件的12306java实现,抢票软件的12306java实现,抢票软件的12306java实现,抢票软件的12306java实现,抢票软件的12306java实现,抢票软件的12306java实现,

    12306购票软件

    然而,值得注意的是,虽然12306购票软件提供了丰富的功能,但在使用过程中应遵循公平购票的原则,避免使用非法插件或第三方抢票软件,以免违反相关规定。同时,用户在使用一键抢票时需确保账户安全,防止个人信息...

    12306在线订票软件模拟(模拟自动登录)

    这个软件的目的是完全模拟人工在线订票,通过软件去实现12306的自动登录,有时间计划做成完全的12306人工在线订票模拟软件,解决人工在12306在线订票的种种痛苦。目前所有相关技术问题已经解决,唯一的问题是验证码...

    12306分流抢票软件

    《12306分流抢票软件:技术解析与安全考量》 12306分流抢票软件,作为一款针对中国铁路客户服务中心12306官网的辅助工具,其核心功能在于帮助用户在高峰期顺利购票。这款名为"12306Bypass_1.10.70.zip"的压缩包,...

    12306铁路买票辅助软件

    《12306铁路买票辅助软件:轻松购票指南》 在当今信息化时代,铁路购票已经离不开网络,12306官网作为中国铁路官方购票平台,为大众提供了便捷的购票服务。然而,对于非专业人员来说,尤其是在高峰期抢购火车票时,...

    12306自动登录软件

    《12306自动登录软件详解》 在日常生活中,我们经常需要使用12306官网购买火车票,而频繁的手动输入账号和密码无疑增加了许多不便。为了解决这一问题,出现了12306自动登录软件,它能够帮助用户实现自动登录,大大...

    模仿12306软件

    自己做的一款模仿12306的软件,需要的同学可以下载看看

    12306火车票抢购软件Bypass

    《12306火车票抢购软件Bypass:深入解析技术原理与应用》 在当今社会,每逢节假日,火车票的抢购成为了一场没有硝烟的战争。12306作为中国铁路官方购票平台,其系统稳定性和购票效率备受关注。然而,由于购票需求的...

    12306火车票订票软件 (windows版本)

    这是出于个人爱好开发的一个订票软件。 与12306官网订票流程是一致的,用VC++开发的,在winXP上测试通过,目前版本最新支持到2016年7月,因为订票协议有可 能变更,所以不确定能支持到什么时候,后续有需求也会...

    12306自动抢票软件

    12306自动抢票软件

Global site tag (gtag.js) - Google Analytics