在WIFI的应用场景中,有个很典型的应用,叫做Captive Portal,也叫Captive Web Portal(CWP)。
大致流程是:
1. 用户的移动设备(例如手机)接入WIFI。
2. 打开任意网页。
3. 得到一个类似Login的页面,需要用户填写一些信息,然后提交。
4. 认证通过后,允许自由访问网络,否则无法上网。
电信、移动等运营商经常会推出一些市区里的WIFI,很多用的就是这种方式。还有像机场等地。有个典型的应用,就是杭州的ihangzhou
iOS,还有Mac OS,都有个功能,当接入无线网络后,会自动检测网络是否通。如果不通,则会自动弹出一个页面,让用户去登录。
Apple把这种功能叫做Captive Network Assistant(CNA)。
其原理如下:
1. 发送一个HTTP/1.0的请求到 www.apple/library/test/success.html 
2. 接收一个回应,如果回应跟它预计的结果一致,那么认为网络是通的,就不会自动弹出页面。同时,状态栏的WIFI图标出现。流程结束。否则,进入下一步。
3. 如果收到的回应不是它想要的那个,它就认为有CWP存在。
4. 如果有CWP存在,iOS就会自动打开一个页面,在这个页面中再请求一次www.apple/library/test/success.html,这一次,使用的是HTTP/1.1。
5. 然后就可以打开Login页面了。
在第2步中,如果有CWP存在,收到的回应通常是一个Login页面,这个和第5步收到的结果应该是一样的。
如果网络能,则可以收到下面的回应。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN"><HTML><HEAD><TITLE>Success</TITLE></HEAD><BODY>Success</BODY></HTML>
只是第2步中,iOS是如何判断的,不得而知。不过只要保证收到上面的响应,则一定能通。
那么,第2步中如果没有收到响应,或是收到了非HTTP 200的响应又会如何呢?
根据我的测试,如果没收到响应,依然会弹出一个窗口。不过,这不是一种正常的CWP状态。
非HTTP 200的情况,我只试了HTTP 302重定向。在这种情况下,iOS不会自动弹出Login页面。
在上面的5步中,得到了一个Login页面,然后又会发生什么呢?
用户拿到Login页面后,应该填写一些信息,并且提交。iOS会在用户提交后,立即发一边第1步中的请求,再次检测网络。如果此时网络还是不通,iOS会自动断开当前的SSID。不过这个行为好像有点不稳定,具体就不细说了。
网络通了后,在iOS上基本有2个现象。一是右上角的“取消”按钮变成”完成“,或是自动关闭这个窗口,行为似乎不太一致。最关键的是顶端状态栏WIFI图标的出现。
从现象上看,只要WIFI图标不出来,iOS就不允许有流外出(部分特殊的除外)。
********** 副作用 **********
iOS的这种行为,其实没给用户多少方便,却会带来不少麻烦。我记得在iOS 4时,还可以选择是否启用auto-login。不过iOS 6已经没有这个选项了。
理论上讲,这个功能最麻烦的就是要保证你所在的网络可以访问www.apple/library/test/success.html。如果仅仅是在公司内部网络,不允许访问外网,那么iOS就无法连接了。
【题外话】在iOS 5以前,只有open的SSID才会发test请求。(open的SSID指的是没有802.1X或PSK认证的)。而从iOS 6开始,连上非open的网络也会发这个test了。
所以,在这种内网的情况下,需要防火墙开放www.apple的访问,或是WIFI AP可以支持避开CNA的检测。
我一直没在网上到关于CNA的判断标准,不知道Apple搞这么个东西干吗。
********** 测试结果 **********
写完此文,心里一直痒痒的,想知道第2步究竟是怎么判断的。于是立即动手测试。
我发现,只要响应页面中,<TITLE>的值是Success,大小写敏感,就可以欺骗iOS了。
网页自动关闭
测了iOS 6.0和Mac OS 10.7,结果都一样。这下我心里释怀了。不知道新版本会不会有变化。该死的苹果。