现在但凡商家或者一些媒体、公司有什么活动都会在比赛竞选阶段设置投票环节,一方面可能是认为这样让公众参与更有公平感、另一方面可能是想让更多人知道了解活动背后的商业目的和价值,提升品牌的公众知名度等。
这不,就连所谓的程序员大赛也设置了投票环节,而且这个环节还是前置于评委专家。本文不想对此评论过多,只是在刷票分析后的吐槽一下。下面就来简单分析下这个『第二届全球程序员节解放号杯程序员大赛』是如何来刷票的。
其实后来看了微信开发者wiki后才知道现在好多都是用的静默授权认证。相关wiki可以看这里https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842
当微信打开链接http://1024.jfh.com/mvote/detail?proId=1453 时会先向微信接口发起oauth验证,获取code。链接如下
https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx7e3e7526c38cebb5&redirect_uri=https%3A%2F%2Fwww.jfh.com%2Fjfm%2Fwx%2Fmenu%2Fgame%2Fv1%2FauthOpenid%3Fbackurl%3Dhttp%3A%2F%2F1024.jfh.com%2Fmvote%2Fmobile%2Fdetail%3FproId%3D1453%26from%3Dtimeline&response_type=code&scope=snsapi_base&state=MESG
其中传的appid好理解,scope=snsapi_base其实就是静默授权,即微信上不会提示获取用户基本信息,所以可以知道他调这个接口就只是想取到open id。还有回调地址redirect_uri,这个拿到code后会在解放号的服务端做各种处理,首先肯定是调用接口拿code换access_token,其实在返回值里已经拿到open id。存数据库或者session、redis等等。
接口格式如 https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code 。
这一点是在服务端进行的,我们没法抓包。
再来说下我在明白上面这些前,尝试写的刷票的测试代码。
#!encoding=utf-8
import random
import requests
import string
def getRandomString(id_length):
charSeq = string.ascii_letters + string.digits
randString = 'RvimHs'
for i in range(id_length):
randString += random.choice(charSeq)
return randString
sess = requests.session()
user_agent = 'Mozilla/5.0 (iPhone; CPU iPhone OS 7_1_2 like Mac OS X) > AppleWebKit/537.51.2 (KHTML, like Gecko) Mobile/11D257 > MicroMessenger/6.0.1 NetType/WIFI'
vote_url = 'http://1024.jfh.com/mvote/doVote'
refer_url = 'http://1024.jfh.com/mvote/mobile/detail?proId=1446'
init_url = 'http://1024.jfh.com/mvote/mobile/detail?proId=1446&from=timeline'
# resp = sess.get('https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx7e3e7526c38cebb5&redirect_uri=https%3A%2F%2Fwww.jfh.com%2Fjfm%2Fwx%2Fmenu%2Fgame%2Fv1%2FauthOpenid%3Fbackurl%3Dhttp%3A%2F%2F1024.jfh.com%2Fmvote%2Fmobile%2Fdetail%3FproId%3D725%26from%3Dtimeline&response_type=code&scope=snsapi_base&state=MESG&connect_redirect=1',
# headers={
# 'User-Agent': user_agent
# })
#
# print sess.cookies
resp = sess.get(init_url, headers={
'User-Agent': user_agent
})
# print resp.status_code, resp.content
# exit(0)
open_id = getRandomString(22)
print(open_id)
sess.cookies.set('voteWeixinOpenId', open_id, path='/', domain='1024.jfh.com')
print sess.cookies
# exit(0)
# resp = sess.get('http://1024.jfh.com/showImg?url=http://obs.myhwclouds.com/jf-bucket-app/1024/v2/6/photo/null/1537451727520.jpg',
# headers={
# 'User-Agent': user_agent
# })
# print sess.cookies
# resp = sess.get('http://www.jfh.com/jfm/wx/menu/hotreq/jsapisign?url=http%3A%2F%2F1024.jfh.com%2Fmvote%2Fmobile%2Fdetail%3FproId%3D1453%26openId%3DGkOWbH6iA5DK3LO0TYFLaV7BpxHRBZ4N0HV4EZdD0b8%253D')
# print resp.status_code, resp.content
# exit(0)
# print sess.cookies
# exit(0)
resp2 = sess.post(vote_url, data={'proId': 1446}, headers={
'Refer': refer_url,
'User-Agent': user_agent
# 'Cookie': 'voteWeixinOpenId=o6MNU1WwnuGNRLFx4amHsRvH2k7k'
})
# print sess.cookies
print resp2.status_code, resp2.content
反正看起来很乱,就是先尝试发的请求。开始想简单了,伪造个open id发到服务端,提示投票次数已用完!其实按上面说的校验方式。解放号服务端在通过微信网页授权后拿到的存储openid与你发的请求中携带的open id做了比对。显然是不可能的,即使暴力破解计算量是非常大的。当然可以使用暴力方式伪造无数个open id尝试,前提是这些open id已经授权过了,但是... 还是算了,搞死服务器就是大事情了。
现在看来伪造open id来实现机刷是不可能的了。
另外也想到一种办法就是搞个网页,里面嵌套iframe,生成二维码或链接各种伪装来诱使别人打开,实现点击一次就可刷票。但据说iframe方式微信授权是禁止的,这个有待研究,另外这种方式弊端会在服务端留下痕迹,即Refer,容易让人找到刷票嫌疑。
最后,又得回到人工刷票上。打听下市场,0.1元一个号, 其实就是0.1元可以拿到10票,10000票才100块钱。看看这排名前三的,都是某航的,要说人缘可能比咱宅男强,一天一万多票... 用没用水军我不知道,实际上人工刷票你也不好查。再来吐槽下,程序员大赛不来点实际上,上来就是投票,80个作品点进去就只能看个人的简介和作品简介,参赛阶段也不说明最后投票都是展示什么,投票时看不到作品是啥,你说投票是看脸和封面截图么。