IP黑白名单

DDOS攻击

DDOS又称为分布式拒绝服务,全称是Distributed Denial of Service。DDOS本是利用合理的请求造成资源过载,导致服务不可用。
比如一个停车场总共有100个车位,当100个车位都停满车后,再有车想要停进来,就必须等已有的车先出去才行。如果已有的车一直不出去,那么停车场的入口就会排起长队,停车场的负荷过载,不能正常工作了,这种情况就是“拒绝服务”。我们的系统就好比是停车场,系统中的资源就是车位。资源是有限的,而服务必须一直提供下去。如果资源都已经被占用了,那么服务也将过载,导致系统停止新的响应。
分布式拒绝服务攻击,将正常请求放大了若干倍,通过若干个网络节点同时发起攻击,以达成规模效应。这些网络节点往往是黑客们所控制的“肉鸡”,数量达到一定规模后,就形成了一个“僵尸网络”。大型的僵尸网络,甚至达到了数万、数十万台的规模。如此规模的僵尸网络发起的DDOS攻击,几乎是不可阻挡的。
常见的DDOS攻击有SYN flood、UDP flood、ICMP flood等。其中SYN flood是一种最为经典的DDOS攻击,其发现于1996年,但至今仍然保持着非常强大的生命力。SYN flood如此猖獗是因为它利用了TCP协议设计中的缺陷,而TCP/IP协议是整个互联网的基础,牵一发而动全身,如今想要修复这样的缺陷几乎成为不可能的事情。

Syn_Flood攻击原理:

攻击者首先伪造地址对服务器发起SYN请求(我可以建立连接吗?),服务器就会回应一个ACK+SYN(可以+请确认)。而真实的IP会认为,我没有发送请求,不作回应。服务器没有收到回应,会重试3-5次并且等待一个SYNTime(一般30秒-2分钟)后,丢弃这个连接。
如果攻击者大量发送这种伪造源地址的SYN请求,服务器端将会消耗非常多的资源来处理这种半连接,保存遍历会消耗非常多的CPU时间和内存,何况还要不断对这个列表中的IP进行SYN+ACK的重试。TCP是可靠协议,这时就会重传报文,默认重试次数为5次,重试的间隔时间从1s开始每次都番倍,分别为1s+ 2s + 4s + 8s +16s = 31s,第5次发出后还要等32s才知道第5次也超时了,所以一共是31 + 32 = 63s。
也就是说一个假的syn报文,会占用TCP准备队列63s之久,也就是说在没有任何防护的情况下,频繁发送伪造的伪造syn包,就会耗尽连接资源,从而使真正的连接无法建立,无法响应正常请求。 最后的结果是服务器无暇理睬正常的连接请求—拒绝服务。

Syn_Flood防御

cookie源认证:
原理是syn报文首先由DDOS防护系统来响应syn_ack。带上特定的sequence number (记为cookie)。真实的客户端会返回一个ack 并且Ack number为cookie+1。 而伪造的客户端,将不会作出响应。这样我们就可以知道那些IP对应的客户端是真实的,将真实客户端IP加入白名单。下次访问直接通过,而其他伪造的syn报文就被拦截。
reset认证:
Reset认证利用的是TCP协议的可靠性,也是首先由DDOS防护系统来响应syn。防护设备收到syn后响应syn_ack,将Ack number (确认号)设为特定值(记为cookie)。当真实客户端收到这个报文时,发现确认号不正确,将发送reset报文,并且sequence number 为cookie + 1。 而伪造的源,将不会有任何回应。这样我们就可以将真实的客户端IP加入白名单。
在很多对抗DDOS的产品中,一般会综合使用各种算法,结合一些DDOS攻击的特征,对流量进行清洗。对抗DDOS的网络设备可以串联或者并联在网络出口处。但DDOS仍然是业界的一个难题,当攻击流量超过了网络设备,甚至带宽的最大负荷时,网络仍将瘫痪。一般来说,大型网站之所以看起来比较能“抗”DDOS攻击,是因为大型网站的带宽比较充足,集群内服务器的数量也比较多。但一个集群的资源毕竟是有限的,在实际的攻击中,DDOS的流量甚至可以达到数G到几十G,遇到这种情况,只能与网络运营商合作,共同完成DDOS攻击的响应。
DDOS的攻击与防御是一个复杂的课题,因此对网络层的DDOS攻防在此不做深入讨论。

CC攻击

CC攻击是DDOS攻击的一种方式,可以理解为是应用层的DDOS攻击。
攻击者借助代理服务器生成指向受害主机的合法请求,实现DDOS和伪装就叫:CC(Challenge Collapsar)。
CC攻击的原理非常简单,就是对一些消耗资源较大的应用页面不断发起正常的请求,以达到消耗服务端资源的目的。在Web应用中,查询数据库、读/写硬盘文件等操作,相对都会消耗比较多的资源。一个很典型的例子:

String sql = " select * from post where targid=${targid} 
order by postid desc limit ${start},30";

当post表数据庞大,翻页频繁,{start}数字急剧增加时,查询结果集={start}+30;该查询效率呈明显下降趋势,而多并发频发调用,因查询无法立即完成,资源无法立即释放,会导致数据库请求连接过多,数据库阻塞,网站无法正常打开。
CC就是充分利用了这个特点,模拟多个用户不停的进行访问那些高计算、高IO的数据。为什么要使用代理呢?因为代理可以有效地隐藏自己的身份,也可以绕开所有的防火墙,因为基本上所有的防火墙都会检测并发的TCP/IP连接数目,超过一定数目一定频率就会被认为是Connection-Flood。
在互联网中充斥着各种搜索引擎、信息收集等系统的爬虫(spider),爬虫把小网站直接爬死的情况时有发生,这与应用层DDOS攻击的结果很像。
应用层DDOS攻击还可以通过以下方式完成:在黑客入侵了一个流量很大的网站后,通过篡改页面,将巨大的用户流量分流到目标网站。

<!--那么访问该页面的用户,都将对target发起一个get请求,这可能直接导致 target拒绝服务--> 
<iframe src="http://target" height="0" width="0"> 
</iframe>

应用层DDOS攻击是针对服务器性能的一种攻击,那么许多优化服务器性能的方法,都或多或少地能缓解此种攻击。比如将使用频率高的数据放在memcache中,相对于查询数据库所消耗的资源来说,查询memcache所消耗的资源可以忽略不计。
但很多性能优化的方案并非是为了对抗应用层DDOS攻击而设计的,因此攻击者想要找到一个资源消耗大的页面并不困难。比如当memcache查询没有命中时,服务器必然会查询数据库,从而增大服务器资源的消耗,攻击者只需要找到这样的页面即可。
同时攻击者除了触发“读”数据操作外,还可以触发“写”数据操作,“写”数据的行为一般都会导致服务器操作数据库。

CC防护

应用层DDOS攻击并非一个无法解决的难题,一般来说,我们可以从以下几个方面着手。
首先,应用代码要做好性能优化。 合理地使cache就是一个很好的优化方案,将数据库的压力尽可能转移到内存中。此外还需要及时地释放资源,比如及时关闭数据库连接,减少空连接等消耗。
其次,在网络架构上做好优化。 善于利用负载均衡分流,避免用户流量集中在单台服务器上。同时可以充分利用好CDN和镜像站点的分流作用,缓解主站的压力。
再有,使用页面静态化技术,利用客户端浏览器的缓存功能或者服务端的缓存服务,以及CDN节点的缓冲服务,均可以降低服务器端的数据检索和计算压力,快速响应结果并释放连接进程。
最后,也是最重要的一点,实现一些对抗手段,比如限制每个IP地址的请求频率,超出限制策略后动态加入黑名单
(1)验证码
比如下是一个用户提交评论的页面,嵌入验证码能够有效防止资源滥用,因为通常脚本无法自动识别出验证码。但验证码也分三六九等,有的验证码容易识别,有的则较难识别。验证码发明的初衷,是为了识别人与机器。但验证码如果设计得过于复杂,那么人也很难辨识出来,所以验证码是一把双刃剑。
(2)Detecting system abuse
Yahoo为我们提供了一个解决思路。如果发起应用层DDOS攻击的IP地址都是真实的,所以在实际情况中,攻击者的IP地址其实也不可能无限制增长。假设攻击者有1000个IP地址发起攻击,如果请求了10000次,则平均每个IP地址请求同一页面达到10次,攻击如果持续下去,单个IP地址的请求也将变多,但无论如何变,都是在这1000个IP地址的范围内做轮询。
为此Yahoo实现了一套算法,根据IP地址和Cookie等信息,可以计算客户端的请求频率并进行拦截。Yahoo设计的这套系统也是为Web Server开发的一个模块,但在整体架构上会有一台master服务器集中计算所有IP地址的请求频率,并同步策略到每台Webserver上。
Yahoo为此申请了一个专利(Detecting system abuse ),因此我们可以查阅此专利的公开信息,以了解更多的详细信息。
Yahoo设计的这套防御体系,经过实践检验,可以有效对抗应用层DDOS攻击和一些类似的资源滥用攻击。但Yahoo并未将其开源,因此对于一些研发能力较强的互联网公司来说,可以根据专利中的描述,实现一套类似的系统。
专利页面:

https://xueshu.baidu.com/usercenter/paper/show?paperid=3945f7b5a9fbc6f3ebbe4c246899eece&site=xueshu_se

IP黑白名单方式

阿里云安全产品:


image.png

Web 应用防火墙 - IP黑白名单配置
CDN - 配置IP黑白名单
DDoS防护 - 配置黑白名单
开发IP黑白名单功能
(1)OpenResty
OpenResty是一个基于 Nginx的可伸缩的 Web 平台,由中国人章亦春发起,提供了很多高质量的第三方模块。OpenResty 是一个强大的 Web 应用服务器,Web 开发人员可以使用 Lua 脚本语言调动 Nginx 支持的各种 C 以及 Lua模块,更主要的是在性能方面,OpenResty可以快速构造出足以胜任 10K 以上并发连接响应的超高性能 Web 应用系统。360,UPYUN,阿里云,新浪,腾讯网,去哪儿网,酷狗音乐等都是 OpenResty 的深度用户。
(2)Lua
Lua 是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。Lua 是巴西里约热内卢天主教大学里的一个研究小组于 1993 年开发的。
通过Lua编写限流、权限认证、黑白名单等功能
设计目的:
其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能
Lua 特性:
轻量级: 它用标准C语言编写并以源代码形式开放,编译后仅仅一百余K,可以很方便的嵌入别的程序里。
可扩展: Lua提供了非常易于使用的扩展接口和机制:由宿主语言(通常是C 或C++)提供这些功能,Lua可以使用它们,就像是本来就内置的功能一样。

动态黑名单实现

(1)安装OpenResty

# 下载 
wget https://openresty.org/download/ngx_openresty- 1.9.7.1.tar.gz 
# 解压 
tar xzvf ngx_openresty-1.9.7.1.tar.gz 
cd ngx_openresty-1.9.7.1/ 
# 配置 
./configure 
# 编译 
make 
# 安装
make install 
# 配置 nginx profile PATH 
PATH=/usr/local/openresty/nginx/sbin:$PATH export PATH 
# 指定配置 
nginx -c /usr/local/openresty/nginx/conf/nginx.conf

(2)配置
用OpenResty以及下面的 redis 组件,配置redis数据库信息及黑名单策略

set $redis_service "127.0.0.1"; 
set $redis_port 6380; 
set $redis_db 0; 
# 1 second 50 query 
set $black_count 50; 
set $black_rule_unit_time 1; 
set $black_ttl 3600; 
set $auto_blacklist_key blackkey;

redis_service: redis 服务器 ip 地址
redis_port: redis 服务器端口
redis_db:所使用的redis db
black_count:拉黑限制的最大访问次数
black_rule_unit_time:拉黑限制次数的保存时间,即保存访问次数的 kv 的ttl
black_ttl:黑名单的存活时间
auto_blacklist_key: kv 的部分 key
重点控制好 black_count 和 black_rule_unit_time
(3)lua 脚本
ip_blacklist.lua,从ip及token(访问凭证)入手来控制

local redis_service = ngx.var.redis_service 
local redis_port = tonumber(ngx.var.redis_port) 
local redis_db = tonumber(ngx.var.redis_db) 
local black_count = tonumber(ngx.var.black_count) 
local black_rule_unit_time = tonumber(ngx.var.black_rule_unit_time) 
local cache_ttl = tonumber(ngx.var.black_ttl) 
local remote_ip = ngx.var.remote_addr 

-- 计数 
function my_count(redis, status_key, count_key) 
    local key = status_key 
    local key_connect_count = count_key 
    local Status = redis:get(key) 
    local count = redis:get(key_connect_count) 
    
    if Status ~= ngx.null then 
        -- 状态为connect 且 count不为空 且 count <= 拉黑次数 
        if (Status == "Connect" and count ~= ngx.null and tonumber(count) <= black_count) then 
            -- 再读一次 
            count = redis:incr(key_connect_count) 
            ngx.log(ngx.ERR, "count:", count) 
            if count ~= ngx.null then 
                if tonumber(count) > black_count then
                    redis:del(key_connect_count) 
                    redis:set(key,"Black") 
                    -- 永久封禁 
                    -- Redis:expire(key,cache_ttl) 
                else 
    redis:expire(key_connect_count,black_rule_unit_time) 
                end 
            end 
        else
            ngx.log(ngx.ERR,"The visit is blocked by the blacklist because it is too frequent. Please visit later.") 
            return ngx.exit(ngx.HTTP_FORBIDDEN) 
        end 
    else
        local count = redis:get(key) 
        if count == ngx.null then 
            redis:del(key_connect_count) 
        end 
        redis:set(key,"Connect") 
        redis:set(key_connect_count,1) 
        redis:expire(key,black_rule_unit_time) 
        redis:expire(key_connect_count,black_rule_unit_time) 
    end 
end 
-- 读取token 
local token 
local header = ngx.req.get_headers()["Authorization"] 
if header ~= nil then 
    token = string.match(header, 'token (%x+)') 
end 

local redis_connect_timeout = 60 
local redis = require "resty.redis" 
local Redis = redis:new() 
local auto_blacklist_key = ngx.var.auto_blacklist_key 

Redis:set_timeout(redis_connect_timeout) 

local RedisConnectOk,ReidsConnectErr = Redis:connect(redis_service,redis_port) 
local res = Redis:auth("password");

if not RedisConnectOk then 
    ngx.log(ngx.ERR,"ip_blacklist connect Redis Error :" .. ReidsConnectErr) 
else
    -- 连接成功 
    Redis:select(redis_db) 
    
    local key = auto_blacklist_key..":"..remote_ip 
    local key_connect_count = auto_blacklist_key..":key_connect_count:"..remote_ip 
    
    my_count(Redis, key, key_connect_count) 
    
    if token ~= nil then 
        local token_key, token_key_connect_count 
        token_key = auto_blacklist_key..":"..token t
        oken_key_connect_count = auto_blacklist_key..":key_connect_count:"..token 
        my_count(Redis, token_key, token_key_connect_count) 
    end 
end

至于对于添加到黑名单的 ip 及 token,需要怎么做下一步的处理,这边就给服务器下的具体应用来处理,在这里不阐述。
(4)配置到 nginx 的 conf

server { 
    listen 80; 
    server_name edu.lagou.com; 
    root /~/public; 
    # 加载配置文件 
    include /etc/nginx/conf.d/blacklist_params; 
    # 指定请求中需要执行的 lua 脚本 
    access_by_lua_file /etc/nginx/conf.d/ip_blacklist.lua; 
    location / { 
    }
    error_log /etc/nginx/conf.d/log/error.log; 
    access_log /etc/nginx/conf.d/log/access.log; 
}

配置就完成了,在 console 中重启下 nginx nginx -s reload ,就可以实现动态添加黑名单的需要了。至于对于添加到黑名单的 ip 及 token,需要怎么做下一步的处理,这边就给服务器下的具体应用来处理,在这里不阐述。
API 网关Kong,基于OpenResty,开源与2015年,核心价值在于其高性能和跨站性。从全球500强的组织统计数据来看,Kong现在是维护的、在生产环境使用最广泛的网关。Plugin IP Restriction通过设置IP白名单和黑名单,根据客户端IP来对一些请求进行拦截和防护。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,539评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,911评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,337评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,723评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,795评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,762评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,742评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,508评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,954评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,247评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,404评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,104评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,736评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,352评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,557评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,371评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,292评论 2 352

推荐阅读更多精彩内容