zoukankan      html  css  js  c++  java
  • 网站被攻击记录

    网站被攻击记录

    2019年4月22日21时许,有同学反映我们的网站出现了访问缓慢等异常现象。查询后台与CDN记录我们发现有人通过网站提供的接口进行了攻击。惊闻此事,组员们都感到十分震惊与不解,并积极开展了抢修工作。我们制订了如下抢修方案,先快速修复确保网站能尽快恢复使用,再给出一个完善的解决方案。网站于22时20分重新上线恢复访问,但是仍有访问不稳定的情况。经过进一步抢修,网站于23日凌晨0时5分恢复正常访问,此事件到此获得了较完美地解决。

    事件Timeline

    事件的timeline如下:

    timeline.png

    事件详细描述

    网站被攻击现象

    网站被攻击的主要现象是有人非法调用我们的注册接口,输入了大量无效的用户信息,导致网站运行缓慢。经过调查,共有至多4个IP在23日20时开始非法请求超过20万次,共新建无效用户约14万个,发送了超过14GiB的数据。

    流量.PNG

    来源.PNG

    网站漏洞

    我们的网站在设计之初考虑到用户主要是学校学生,因此在部分安全方面上有所缺失。本次被攻击的漏洞是注册用户接口没有一个有效的验证措施,没有过滤非法请求,只对邮箱进行了正则验证。

    解决方案

    网站被攻击引起了我们开发小组极大的重视。考虑到晚上9点正是网站用户量较多的时间段,我们制订了快速修复,妥善解决的解决方案。管理后端和网站部署的刘峻辰尝试快速修复,尽快使网站尽可能多的功能恢复正常使用。管理前端的肖萌威和PM罗奥升寻找一个妥善的解决方案并与快速修复同时开始正式修复,待夜深人静时再进行部署。

    事件影响

    事件造成了一定的损失。由于网站数据库回档到了先前的备份,导致8时至10时20分之间注册的用户账号,发表的评论丢失。这对于网站的宣传也有一定的负面影响。

    详细解决方案

    快速解决方案

    显然,网站下线时间越长越容易导致用户的流失。为此,我们决定尽快修复网站功能,快速上线。经过简单分析,我们认为当前问题主要可以分成两个部分:恢复数据库和阻止非法链接。

    恢复数据库

    我们在设计网站时考虑到了数据库的备份问题,采用crontab定时指令的方式进行备份。我们发现8点的备份数据尚未收到影响,因此决定回滚到8时的数据。尽管我们对于用户的大部分请求都做了日志记录,但是我们并没有保存请求的具体内容,因此无法通过这些信息进行进一步的精确回档。这也是我们下一个阶段要改进的内容。

    利用CloudFlare初步阻挡攻击

    我们的网站使用了CloudFlare CDN进行加速,但是并没有开启严格的攻击防护。在本事件发生后,我们临时将防护等级调整到了最高,对所有请求都进行了一个js challenge。该操作成功阻挡了大量非法请求,但是用户在使用网站时会先被定向到一个验证页面,影响了用户的体验。实践证实,尽管使用的是CloudFlare的免费套餐,但是其也成功阻挡了攻击并找出了发起的IP。

    威胁.PNG

    快速恢复访问

    在完成上面的工作以及简单调试后,我们快速的恢复了网站的访问,整个快速修复过程耗时约1小时,网站功能基本恢复正常。随后,我们投入了正式修复的工作。

    网站的正式修复

    尽管快速修复初步解决了问题,但是它也不是一个长久之计。为此,在进行快速修复的同时,其他成员也开始研究完善的修复方案。经过讨论,我们采取了腾讯防水墙作为验证模块。

    方案设计流程

    其实在Alpha开始的阶段,由于我们是个小网站,同时我们拿到的学长的代码也没有安全验证这一块,因此我们也没有考虑到安全验证这一块,但是在Alpha阶段的尾期想到了这一块,可能需要在注册的时候进行一定的验证来避免恶意的用户注册,于是在上周末已经进行了一部分的验证码的探究。

    但是在今天网站遭受了比较严重的攻击,我们将这一功能提前上线。

    验证码的选择

    验证码的选择有很多种,我们最终选择了拼图类的验证码,毕竟这种验证码比传统的字母验证码的安全性还是要强一点,即使通过脚本来通过验证也是很费时的。而据我的简单了解,极验(geetest)的验证码就做的不错,博客园登陆时所弹出来的验证就是使用的极验的接口。

    1555949867678.png

    极验的验证码能做到对用户进行区分,对可信用户能够免验证通过。但是在后续的了解中,发现极验的使用可能稍微有点麻烦,注册账号时也存在着24h的审核期,不能够马上投入使用,因此对于极验的了解没有过多的深入,尽管它的功能实现可能更好好。因此我去了解了腾讯的验证码平台,并最终选择了腾讯。

    腾讯验证码

    简介

    腾讯验证码平台也是一个提供验证码接口的网站,他提供了和极验类似的功能,同时使用起来也是比较的简单。

    1555954724506.png

    他也能够实现与极验类似的区分用户的功能。对于可信用户,可以直接通过验证,对于可疑用户需要采用拼图验证,对于恶意用户采用难度更高的立体图形验证。

    1555950142055.png

    对于恶意用户的验证码:

    1555951510912.png

    因此它十分方便于用户的使用。而它的安全性也是可以信任的,腾讯系的产品基本都是采用的腾讯验证码。

    1555950196897.png

    同时腾讯验证码免费提供每小时2000次验证,对于我们的小型网站来说绰绰有余,不需要考虑费用问题,注册也没有审核期,只需要手机、QQ号和网站地址即可轻松完成注册并立即开始使用。对于验证码的配置管理也十分简单,登陆后即可查看各种各样的数据,如每天的验证数据、拦截数据等等。进入配置中心后即可对验证码的外观、安全等属性进行配置,如开启可信用户免验证。因此我们最终就采取了腾讯的验证码。

    1555953877511.png

    1555955257840.png

    验证码的使用

    注册后将会获得一个验证码 APP ID和一串密钥 App Secret Key

    腾讯验证码首先在前端进行验证,通过验证后会生成一个票据和一个随机串,将票据随机串发送到后端后,由后端将票据随机串密钥发往腾讯服务器进行再次验证,因此只要密钥不被泄露,理论上是很难强行突破验证的。

    验证码的使用分为前端和后端。

    前端:

    前端功能很简单,就是添加对应的元素,能够弹出验证框,再将票据随机串和用户IP传回后端服务器即可。

    a、在Head的标签内最后加入以下代码引入验证JS文件(建议直接在html中引入)。

    <script src="https://ssl.captcha.qq.com/TCaptcha.js"></script>
    

    b、在你想要激活验证码的DOM元素(eg. button、div、span)内加入以下id及属性,data-appid的内容即为验证码 App ID

    <!--点击此元素会自动激活验证码-->
    <!--id : 元素的id(必须)-->
    <!--data-appid : AppID(必须)-->
    <!--data-cbfn : 回调函数名(必须)-->
    <!--data-biz-state : 业务自定义透传参数(可选)-->
    <button id="TencentCaptcha"
            data-appid="App ID"
            data-cbfn="callback"
    >验证</button>
    

    c、为验证码创建回调函数,注意函数名要与上面的data-cbfn相同,这里对于验证成功后的操作可以进行一定的修改。

    window.callback = function(res){
        console.log(res)
        // res(用户主动关闭验证码)= {ret: 2, ticket: null}
        // res(验证成功) = {ret: 0, ticket: "String", randstr: "String"}
        if(res.ret === 0){
            alert(res.ticket)   // 票据
        }
    }
    

    完成以上操作后,点击激活验证码的元素,即可弹出验证码。

    对于验证码进行操作时会生成一个res对象,用户直接关闭验证码时,其内容为{ret: 2, ticket: null},当验证成功时,其内容为{ret: 0, ticket: "String", randstr: "String"}ticket为票据,randstr为一串随机串。通过ret的值就能判断是否验证通过。验证通过后我们需要将这两项和用户IP传回后端,由后端进行二次验证。

    后端设计

    在完成快速修复任务后,后端开发也加入了正式修复流程。由于前端已经摸清了该验证模块的逻辑,找到了一份可以用来参考的python2 教程,后端的工作压力较小。再将py2样例移植到py3上后,经过简单调试就可以成功执行。唯一遇到的坑就是腾讯的接口文档和样例中都表明返回值是一个int,1表示认证成功,-1表示认证失败,然而实际上接口返回的是字符串'1'和'-1'。具体设计如下:

    在验证完成后,客户端收到获得一个验证票据(ticket)。将票据上传至服务器,并发送GET请求到下方接口可以校验验证码的票据,判断当次验证是否成功。

    URL: https://ssl.captcha.qq.com/ticket/verify

    字段名 描述
    aid (必填) APP ID
    AppSecretKey (必填) 密钥
    Ticket (必填) ticket
    Randstr (必填) randstr
    UserIP (必填) 用户IP

    返回值

    Json格式,eg:{response:1, evil_level:70, err_msg:""}

    字段名 描述
    response 1:验证成功,0:验证失败,100:AppSecretKey参数校验错误[required]
    evil_level [0,100],恶意等级[optional]
    err_msg 验证错误信息[optional],查看详细说明

    至此,验证码接入已完成,还可以进行更加复杂的接入。

    样例的Python2 代码如下,虽然问题很多但勉强能看,明显的错误已标出:

    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    import json, urllib
    from urllib import urlencode  # 注: py3里面这个库位置换了
    
    #----------------------------------
    # 腾讯验证码后台接入demo
    #----------------------------------
    
    #----------------------------------
     # 请求接口返回内容
     # @param  string appkey [验证密钥]
     # @param  string params [请求的参数]
     # @return  string
    #----------------------------------
    def txrequest(appkey, params={}, m="GET"): # 注: appkey和m实际没有用到
        url = "https://ssl.captcha.qq.com/ticket/verify"
        if m =="GET":
            f = urllib.urlopen("%s?%s" % (url, params))
        else:
            f = urllib.urlopen(url, params)
    
        content = f.read()
        res = json.loads(content)
        if res:
            error_code = res["response"]
            if error_code == 1:  # 注: 这里应该是字符串'1'
                print "验证成功"
            else:
                print "%s:%s" % (res["response"],res["err_msg"])
        else:
            print "请求失败"
    
    if __name__ == '__main__':
        AppSecretKey = "test"; # 注: 这个样例多了个分号
        appid = "test"
        Ticket = "test"
        Randstr = "test"
        UserIP = "127.0.0.1"
        params = {
            "aid" : appid,
            "AppSecretKey" : AppSecretKey,
            "Ticket" : Ticket,
            "Randstr" : Randstr,
            "UserIP" : UserIP
        }
        params = urlencode(params)
    
        txrequest(AppSecretKey, params)
    

    附:前后端调用时序图

    img

    正式恢复访问

    前后端代码与23日0:01编写完成并调试通过。随后我们将CloudFlare的防护等级降低到Medium,并部署了正式修正版本。用户体验恢复正常。

    结语

    本次网站被攻击事件给我们的网站带来了不小的影响,造成了数据库被迫回滚,网站临时下线,也丧失了部分潜在用户。此次事故让我们深刻的意识到网站安全的重要性,我们也决定在Beta阶段将网站安全建设作为一个重点关注的对象。面对恶意攻击,我们也尽力降低了被攻击的影响,采用多套方案尽快的解决了问题,没有将漏洞留到第二天。

  • 相关阅读:
    c语言求最大公约数和最小公倍数(转)
    git 提交去除每次输账号密码
    phpstorm使用zen coding 快速编辑补全html/css代码
    YII2.0使用ActiveForm表单(转)
    php面向对象之trait
    php操作redis(转)
    模块
    列表生成式 与生成器表达式
    三元表达式,递归,内置函数
    面向过程的编程思想
  • 原文地址:https://www.cnblogs.com/tbqjxjkwg/p/10755896.html
Copyright © 2011-2022 走看看