网站被攻击记录

网站被攻击记录

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

事件Timeline

事件的timeline以下:html

timeline.png

事件详细描述

网站被攻击现象

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

流量.PNG

来源.PNG

网站漏洞

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

解决方案

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

事件影响

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

详细解决方案

快速解决方案

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

恢复数据库

咱们在设计网站时考虑到了数据库的备份问题,采用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阶段将网站安全建设做为一个重点关注的对象。面对恶意攻击,咱们也尽力下降了被攻击的影响,采用多套方案尽快的解决了问题,没有将漏洞留到次日。

相关文章
相关标签/搜索