从0开始,开发WAF+(一)

先说一下设计思路,看图

OpenStar

通过设计的流程图,我的处理流程就是按照这个执行的

今天说 STOP 0

当用户请求到了,我首先需要获取用户真实IP。

1:连接IP就是用户真实IP

2:走CDN时,用户IP在指定的http头中

所以这里我们就需要有配置文件来配置取用户真实IP是怎么取的,我先设计了一个json

{
    "id.game.com": {
        "ips": [
            "111.206.199.57"
        ],
        "realipset": "CDN-R-IP"
    },
    "101.200.122.200": {
        "ips": [
            "101.254.241.149",
            "106.37.236.170"
        ],
        "realipset": "x-for-f"
    },
    "game.game.com": {
        "ips": "*",
        "realipset": "x-forword-for"
    }
}

解释一下,host是id.game.com的请求,直连IP为:111.206.199.57的,用户真实IP在http头CDN-R-IP中。ips就是我们的CDN节点服务器列表了,目前仅支持IP列表的写法,还没有增加使用IP段这种写法。另外2个也同样这么理解即可。

在开启看取用户IP的代码:

local remoteIp = ngx.var.remote_addr
local headers = ngx.req.get_headers()
local host = ngx.req.get_headers()["Host"] or "unknownhost"
local method = ngx.var.request_method
local url = ngx.unescape_uri(ngx.var.uri)
local referer = headers["referer"] or "unknownreferer"
local agent = headers["user_agent"] or "unknownagent"	
--local request_url = ngx.unescape_uri(ngx.var.request_uri)

local config_dict = ngx.shared.config_dict
local limit_ip_dict = ngx.shared.limit_ip_dict
local ip_dict = ngx.shared.ip_dict

local cjson_safe = require "cjson.safe"
local config_base = cjson_safe.decode(config_dict:get("base")) or {}

--- 判断config_dict中模块开关是否开启
local function config_is_on(config_arg)
	if config_base[config_arg] == "on" then
		return true
	end
end

--- 取config_dict中的json数据
local function getDict_Config(Config_jsonName)
	local re = cjson_safe.decode(config_dict:get(Config_jsonName)) or {}
	return re
end

-- 传入 (host  连接IP  http头)
local function loc_getRealIp(host,remoteIP,headers)
	if config_is_on("realIpFrom_Mod") then
		local realipfrom = getDict_Config("realIpFrom_Mod")
		local ipfromset = realipfrom[host]		
		if type(ipfromset) ~= "table" then return remoteIP end
		if ipfromset.ips == "*" then
			local ip = headers[ipfromset.realipset]
			if ip then
				if type(ip) == "table" then ip = ip[1] end  --- http头中又多个取第一个
			else
				ip = remoteIP
			end
			return ip
		else
			for i,v in ipairs(ipfromset.ips) do
				if v == remoteIP then
					local ip = headers[ipfromset.realipset]
					if ip then
						if type(ip) == "table" then ip = ip[1] end  --- http头中又多个取第一个
					else
						ip = remoteIP
					end
					return ip
				end
			end
			return remoteIP
		end
	else
		return remoteIP
	end
end

这里用了几个API,参考NGINX API for Lua

取连接ip,headers,host;host是从headers这个table中取出来的。还有一些其他需要用到的如method,url(已经url转码后),referer,useragnet等,

config_is_on 函数,是判断是否开启了模块,从http头中获取用户真实IP。

PS:下一篇我说一下,程序的初始化阶段

config_base 是从dict中取的总配置数据,并转化成json的。"on" 表示开启,区分大小写的,代码中使用字符串直接进行判断的。

loc_getRealIp 函数,是取用户真实IP的主函数,首先判断模块"realIpFrom_Mod"是否开启从http头取用户IP;其次读取"realIpFrom_Mod"配置列表(json转化后),就是通过函数getDict_Config来取的;接下来就是通过请求的host从列表中取自己对应的配置,如果没有就直接返回连接IP作为用户真实ip,如果取到了先判断ips是不是 *,ips=* 表示所有ip来的都从http头取用户真实ip,否则就循环匹配ips中所有ip和当前ip是否相等,没有相等的就返回连接ip作为用户真实ip,剩下就是从http头中去用户真实ip了,如果多个只取第一个。

文字解释的比较繁琐,大家直接阅读代码吧。

 

写在前面:

代码写的比较水,功能上是没啥问题,性能测试了也还行,就是不规范、不优雅。

 

 

转载于:https://my.oschina.net/u/1458760/blog/687549

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值