关闭

在线投票系统公平性探讨

1011人阅读 评论(0) 收藏 举报

一、前言:

  国庆节黄金周居然要加班,真是郁闷啊,朋友给了一个网址:http://games.sina.com.cn/z/mm/ ,说是好多网络游戏MM在里面,据称里面还真有特别漂亮的,呵呵。我实在经不起诱惑,打开一看,原来是sina搞的一个活动,活动名称就叫“中国第一届游戏MM风采秀”,随便看了几个MM的视频,还真是漂亮哈。不过,作为一个喜欢找系统空子的人,我很快就盯上了其中的投票系统,嘿嘿。sina为这次活动举办了一次网友投票,来评选最受欢迎的网络MM,每个MM都有那么一个得票数,最后据说要选出5个得票最多的MM参加总决赛。

 

二、初步实验及简单投票器设计:

  随便找了一个MM做实验,004016号的纳兰如意MM,准备瞧瞧sina的在线投票系统是不是有缺陷。

  实验一,首先我在本机投了一票之后,又找了一台内网的机器再测试,还可以继续投,说明sina并没有限制每个IP的投票次数。在仔细地看了这个投票系统之后,发现实质上投票只不过是提交一个连接,就拿004016号MM来说,其实只要提交http://stat.sina.com.cn/cgi-bin/survey/mms2003/vote.pl?usernum=004016&title=纳兰如意,就可以增加一票。

  实验二,打开一个新的IE窗口,提交上面的连接,返回的内容是“感谢您的参与!纳兰如意 的票数为 000xxxx 票”,这次投票成功,继续,用这个IE窗口第二次提交上面的连接,发现返回的内容是“请不要重复提交信息!”。看来sina还是设置了一次连接的投票次数限制,不过,总觉得有点问题,继续做下面的实验。

  实验三,打开两个IE窗口,同时提交上面的连接,发现增加了两票,这一点说明sina也没有限制两次投票的间隔时间。怪了,刚才一个IE窗口提交两次连接怎么不成功。

  啃了一个苹果后,突然恍然大悟,哈哈,原来sina是这样设置的,一次tcp连接只能投票一次,当检测到本次连接已经投过票之后,就会返回“请不要重复提交信息!”。而关掉这个已经投过票的IE时,这次连接就失效了。重新再打开IE提交投票连接时,就可以继续投票了。呵呵,sina的投票系统果然有很大的缺陷。下面就可以轻松地写出自动投票程序了,主要的代码如下:

void vote()
{
  char url[200] = "http://stat.sina.com.cn/cgi-bin/survey/mms2003/vote.pl?usernum=004016&title=纳兰如意";
  //可以改成任意MM的投票连接

  HINTERNET hinternet=0;
  hinternet=InternetOpen("Microsoft Internet Explorer",INTERNET_OPEN_TYPE_PRECONFIG,NULL,NULL,0);
  if(hinternet==0)
  {
  return;
  }
  HINTERNET hInternetFile;
  hInternetFile = InternetOpenUrl(hinternet,url, NULL, 0, INTERNET_FLAG_TRANSFER_BINARY | INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE, 0);
  if (!hInternetFile)
  {
  return;
  }

  char buffer[2*1024] = "0";
  DWORD dwBytesRead = 0;
  InternetReadFile(hInternetFile,buffer,sizeof(buffer),&dwBytesRead);
  printf("%s/n/n",buffer);

  InternetCloseHandle(hinternet);
  return;
}

  上面这个vote()函数实现的功能就是提交一次投票连接,可以增加一票。由于限制了每次tcp连接的投票次数,所以,仅仅不停地调用这个函数是无法连续投票的,但是,呵呵,你可以绕一下,把这个函数编译成exe文件,然后用另外一个程序去不停地CreateProcess这个exe文件,假设上面的代码编译连接成toupiao.exe,你就可以用下面的代码来调用:

void main()
{
  printf("code by xiaobai/n/n");

  int num = 0;
  printf("请输入投票次数: ");
  scanf("%d", &num);

  int i = 0;
  while(i<num)
  {
  STARTUPINFO startinfo;
  GetStartupInfo(&startinfo);
  startinfo.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
  startinfo.wShowWindow = SW_HIDE;
  PROCESS_INFORMATION processinfo;
  if(CreateProcess(NULL, "toupiao.exe", NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &startinfo, &processinfo) == 0)
  {
  printf("Create process error!/n");
  return;
  }
  CloseHandle(processinfo.hProcess);
  Sleep(1000);
  printf("%d ", i);
  i++;
  }
  return;
}

  这样一来,你就可以不停地投票了。为了程序的稳定性,我设置了每投一次票就sleep一秒钟,现在,你一个小时就可以投3600票,呵呵,是不是有点过分了,嘿嘿。

 

三、突破IP限制的隐蔽式投票器设计

  前面我们已经设计了一个简单的投票器,虽然简单,不过,投票效率可是够高的,呵呵。但是,总觉得好象疏忽了点什么,感觉上不太对劲。哦,原来是IP的问题,我们刚才运行投票器后,总是自己本机一个IP地址在投票,如果对方记录了IP地址,那么,显示的票都是从这一个IP地址来的,那岂不是弄巧成拙。虽然现在看来sina好象并没有过滤一个IP地址的重复票的问题,但是,作为我们这种爱走“旁门左道”的人来说,我们总不能碰到问题就放手吧,嘿嘿。现在我们就来设计一个隐蔽性比较好的投票器,即使对方设置了IP地址的重复投票过滤,也可以成功地进行批量投票。

  我们这个隐蔽式投票器的设计思想就是利用HTTP代理服务器。在网络上,我们可以很轻松地得到很多的http proxy,现在就利用代理来隐藏自己的IP,让http proxy代替我们来提交投票的请求,这样,显示在投票系统服务器上的IP地址就是http proxy的IP地址,就成功地隐蔽了自己的IP。所以,只要你有足够的http proxy,就可以投很多的票。


//----------------------
socktp.cpp
code by xiaobai
//----------------------
#include <Winsock2.h>
#include <winsock.h>

#pragma comment(lib,"WS2_32.lib")

void main(int argc,char* argv[])
{
  WSADATA wsadata;
  char lpbuffer[MAX_PATH*2+50]="0";
  sockaddr_in addrin;
  SOCKET sock;

  if (WSAStartup(MAKEWORD( 2, 2 ),&wsadata)!=0)
  return;
  sock=socket(AF_INET,SOCK_STREAM,0);

  addrin.sin_addr.s_addr = inet_addr(argv[1]);
  addrin.sin_port =htons(atoi(argv[2]));
  addrin.sin_family=AF_INET;

  int rtn = connect(sock,(sockaddr*) &addrin,sizeof(addrin));

  lstrcpy(lpbuffer,"GET http://stat.sina.com.cn/cgi-bin/survey/mms2003/vote.pl?usernum=004016&title=纳兰如意");
  //可以修改成任何一个MM
  send(sock,lpbuffer,lstrlen(lpbuffer),0);

  closesocket(sock);
  return;
}

  上面就是投票器的主要实现代码,通过参数传递进去http proxy的IP地址和端口,就可以让代理去提交投票的连接,这样的话,显示在服务器上的IP就是http proxy的IP。这段代码可以利用你给的http proxy投一次票。编译连接成toupiao.exe文件后,把你所有的http proxy地址和端口按照一定格式保存为一个txt文件。跟上面的简单投票器一样,再利用另外一段程序,读取每个http proxy,读取后利用CreateProcess传递给toupiao.exe文件,就可以不停地投票了。

  通过上面的代码,我们就成功地实现了具有隐蔽功能的投票器,即使投票服务器限制了IP地址的票数,也不怕了,因为http proxy在网络上简直是无限的。所以,只要你找到足够多的http proxy,你就可以投票足够多次,也不会出现大多数票都来自一个IP的情况了,呵呵。

 

四、解决对策与探讨

  上面我们设计了可以突破IP限制的隐蔽式投票器,不过说到底,我们希望得到的是一个公平的竞争环境,我们都不喜欢作弊者。所以,我们要对在线投票系统的公平性要做些努力。

  首先,对于sina的这次活动,给我的印象是sina不负责任。对于如此的投票缺陷,sina竟然无动于衷。在刚投票开始的时候,我就想把相关的缺陷情况反映给sina,可是,活动相关的信箱,自投票以来这几天,始终提示信箱已满,无法投递mail。论坛中无数人都在询问关于刷票的问题,始终没有人给一个负责的解释。
 
  不过,话说回来,这其实也就是一个商业活动,对于投票的结果,sina不关注,赞助商也不会关注,他们关注的是最后达到的广告效应和即得的经济利益。

  呵呵,话扯远了,还是回到技术的层面。为了防止在线投票系统作弊,应该做到下面几个步骤:

  1、首先,设置投票IP限制,或者要求每个IP只能投一票,这样,可以有效地防止作弊。但是,现在由于IP地址并不充足,所以,有很多都是代理或者NAT来上网,所以,有可能很多人使用的是一个IP地址。所以,限制IP并不是一个很好的办法,有可能让很多人都没有投票的机会,这样本身就造成了不公平。

  2、设置每个IP地址的投票延时,碰到1那种不合适的情况,就可以采用这个办法,每个IP地址在投票之后,要经过一段时间的延时才可以第二次投票。这样也是一种防止单个IP地址刷票的办法。

  3、其实上面的方法对于我们设计的突破IP限制的隐蔽式投票器来说,都是没有任何意义的,那该怎么办呢?还是就以sina为对象来说,设置成为只有sina的会员投票,并且每个会员的投票次数都是有限制的,这样,对于防止所有类型的投票器都是很有效的,并且,为了加强效果,可以设置成每次投票都要输入一个随即产生的校验码。这样,再配合前面两种方法,就可以大大降低作弊的可能性。


  其实,并不是我们想钻空子,我们只是想让这个网络对所有人都有一个公平的竞争环境。
 
 

10月10日晚7点补充:

  昨天sina的投票就已经结束了,今天再看的时候就已经开始第二轮投票了,这次的投票方法改变了一下,不会让你很容易地发现投票提交的信息了,呵呵,看来安全了一些。就拿冰风传奇MM投票页来看吧,具体的连接是http://games.sina.com.cn/z/mm/vote_jz.shtml,要求投票者分配手中的30个点数,然后最后点击提交按钮来投票。由于不象以前那种可以直接得到投票的提交信息了,所以,表面上看起来好象作弊的难度大了。
 
  但是,嘿嘿,还是有办法的。这就要请出我们的Sniffer来了,截获你在点击提交按钮时与sina服务器的交互过程,不就可以得到投票提交连接了么,呵呵。说做就做,打开Iris,监视80端口的信息。在冰风传奇MM投票页上,给1号填上2分,2号填上3分,19号填上4分,最后的姓名填上xiaobai,电话填上1234567,OK!,提交吧。哈哈,想要的东西来了,看下面截获的内容:
 
  第一个数据包:
  POST /cgi-bin/survey/games/mms2003/vote.cgi HTTP/1.1..Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-powerpoint, application/vnd.ms-excel, application/msword, */*..Referer: http://games.sina.com.cn/z/mm/vote_jz.shtml..Accept-Language: zh-cn..Content-Type: application/x-www-form-urlencoded..Accept-Encoding: gzip, deflate..User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)..Host: stat.sina.com.cn..Content-Length: 500..Connection: Keep-Alive..Cache-Control: no-cache..Cookie: regplace=China...........X...6..
 
  第二个数据包:
  MMS_Game=%B1%F9%B7%E7%B4%AB%C6%E6&MMS_Result1=2&MMS_Result2=3&MMS_Result3=0%B7%D6&MMS_Result4=0%B7%D6&MMS_Result5=0%B7%D6&MMS_Result6=0%B7%D6&MMS_Result7=0%B7%D6&MMS_Result8=0%B7%D6&MMS_Result9=0%B7%D6&MMS_Result10=0%B7%D6&MMS_Result11=0%B7%D6&MMS_Result12=0%B7%D6&MMS_Result13=0%B7%D6&MMS_Result14=0%B7%D6&MMS_Result15=0%B7%D6&MMS_Result16=0%B7%D6&MMS_Result17=0%B7%D6&MMS_Result18=0%B7%D6&MMS_Result19=4&MMS_Result20=0%B7%D6&User_Name=xiaobai&User_Phone=1234567&User_Code=&User_Address=&User_Email=l=...
 
  上面就是sniffer得到的东西,我只保留了http的部分。呵呵,看到了吧,用POST来提交/cgi-bin/survey/games/mms2003/vote.cgi,而内容则是后面第二个数据包的内容。第二个数据包的内容很容易理解,看里面1号选手对应的MMS_Result1=2,2号选手对应的MMS_Result2=3,19号选手对应的MMS_Result19=4,其他的都是0,还有后面的User_Name=xiaobai,User_Phone=1234567,呵呵,是不是我们刚才输入的内容。
 
  既然提交的内容都得到了,那就来组合一下,就有了如下的内容:
  http://stat.sina.com.cn/cgi-bin/survey/games/mms2003/vote.cgi?MMS_Game=%B1%F9%B7%E7%B4%AB%C6%E6&MMS_Result1=2&MMS_Result2=3&MMS_Result3=0%B7%D6&MMS_Result4=0%B7%D6&MMS_Result5=0%B7%D6&MMS_Result6=0%B7%D6&MMS_Result7=0%B7%D6&MMS_Result8=0%B7%D6&MMS_Result9=0%B7%D6&MMS_Result10=0%B7%D6&MMS_Result11=0%B7%D6&MMS_Result12=0%B7%D6&MMS_Result13=0%B7%D6&MMS_Result14=0%B7%D6&MMS_Result15=0%B7%D6&MMS_Result16=0%B7%D6&MMS_Result17=0%B7%D6&MMS_Result18=0%B7%D6&MMS_Result19=4&MMS_Result20=0%B7%D6&User_Name=xiaobai&User_Phone=1234567&User_Code=&User_Address=&User_Email=l=...
 
  现在,只要打开IE,提交上面格式的请求,就可以很容易地增加票数了。你只需要把你想投票的MM找到对应的MMS_Result,后面加上你要投的票数,由于sina做了限制,每次只能最大是30。然后,改一下后面的User_Name和User_Phone,提交,呵呵,就投票成功了。我们想得到的已经得到了,投票器也可以轻松地写出来了。不过这次投票器的设计有一点点麻烦,每投一次票,都要随机再产生一个User_Name和User_Phone,呵呵。

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:7429次
    • 积分:89
    • 等级:
    • 排名:千里之外
    • 原创:0篇
    • 转载:5篇
    • 译文:0篇
    • 评论:0条
    文章存档