Nginx使用Lua编写简易防火墙防止CC攻击

发布于 / 运维 / Comments Off on Nginx使用Lua编写简易防火墙防止CC攻击

前天,服务器突然异常高负荷运行

blob.png

查看日志,惊呆了,这样一个小站点居然产生了100M的日志?

blob.png

日志分析,一位来自内蒙古呼和浩特市的116.114.21.*的这位网友,对网站进行了锲而不舍的漏洞扫描。累计扫描次数可能有30万次?

服务器性能很菜,麻烦大哥扫描能不能加上点限制,比如每秒扫一次之类的。。。

估计这位仁兄可能看不到这篇文章,我们对服务器进行一些改造吧!搞一个CC防火墙~

首先保证你的Nginx的Lua模块正常安装,如果没有安装,请百度一下【Nginx安装lua-nginx-module】

接着,写一个配置文件:cc.conf

lua_shared_dict limit 10m;
lua_package_path "/nginx/waf/?.lua";
init_by_lua_file  /nginx/waf/cc.lib.lua;
access_by_lua_file /nginx/waf/cc.lua;

注意:/nginx/waf这个目录要替换成你保存防火墙程序的目录

接着,在这个目录下创建两个lua文件,文件名和内容分别是:

cc.lib.lua

function getRealIp()
  IP  = ngx.var.remote_addr 
  if ngx.var.HTTP_X_FORWARDED_FOR then    --如果用了CDN,判断真实IP
    IP = ngx.var.HTTP_X_FORWARDED_FOR
  end
  if IP == nil then
    IP  = "unknown"
  end
  return IP
end

function subString(str, k)    --截取字符串
  ts = string.reverse(str)
  _, i = string.find(ts, k)
  m = string.len(ts) - i + 1
  return string.sub(str, 1, m)
end

function getClientIp()
  IP  = ngx.var.remote_addr 
  if ngx.var.HTTP_X_FORWARDED_FOR then
    IP = ngx.var.HTTP_X_FORWARDED_FOR
  end
  if IP == nil then
    IP  = "unknown"
  end
  IP = subString(IP, "[.]") .. "0/24"
  return IP
end

function ban_ip(point)
  local token = getClientIp() .. "_WAF"
  local limit = ngx.shared.limit
  local req,_=limit:get(token)
  if req then
    limit:set(token,req+point,3600)  --发现一次,增加积分,1小时内有效
  else
    limit:set(token,point,3600)
  end
end

function get_ban_times()
  local token = getClientIp() .. "_WAF"
  local limit = ngx.shared.limit
  local req,_=limit:get(token)
  if req then
    return req
  else
    return 0
  end
end

function is_ban()
  local ban_times = get_ban_times()
  if ban_times >= 100 then        --超过100积分,ban
    ngx.header.content_type = "text/html;charset=UTF-8"
    ngx.status = ngx.HTTP_FORBIDDEN
    ngx.say("你访问的太快啦!请等几个小时再来吧")
    ngx.exit(ngx.status)
    return true
  else
    return false
  end
  return false
end

function denycc()
  CCcount = 100    --每60秒允许请求100次
  CCseconds = 60
  local token = getRealIp()
  local limit = ngx.shared.limit
  local req,_=limit:get(token)
  if req then
    if req > CCcount then
      limit:incr(token,1)
      ban_ip(1)  --CC攻击,罚分
      ngx.header.content_type = "text/html"
      ngx.status = ngx.HTTP_FORBIDDEN
      ngx.say("请稍安勿躁!慢点访问!")
      ngx.exit(ngx.status)
      return true
    else
      limit:incr(token,1)
    end
  else
    limit:set(token,1,CCseconds)
  end
  return false
end

cc.lua

is_ban()
denycc()

如果你想对一些host不生效,可以:

local hostname =  ngx.var.server_name 
if hostname ~= "white.example.com" then  --不想启用防火墙的host
  is_ban()
  denycc()
end

保存,重载Nginx,你的防火墙已经生效了

转载原创文章请注明,转载自: 斐斐のBlog » Nginx使用Lua编写简易防火墙防止CC攻击
评论已关闭