服务器是公网 IP,单机所以没有用反向代理 是不是这种情况下,$remote_addr 就会始终是真实 IP 呢?
我额外设置了
fastcgi_param HTTP_X_FORWARDED_FOR $remote_addr;
这样就能保证$remote_addr 始终是用户的真实 IP 呢?
我在这样的配置下,参考下面的文章 配置了 redis 和 lua https://blog.linuxeye.cn/453.html
然后修改了其中的 IP 部分为
function getClientIp()
IP = ngx.var.remote_addr
return IP
end
然后检测 redis,发现可以正确生成黑白名单数据。但是,检查 php 的 log。发现依然会出现部分 Ip 的高频访问,这些 IP 没有被加入黑名单。比如下面这个 ip,几个小时内访问了 60W 次,基本上每秒 100 次请求。而没有被加入黑名单
61.151.186.217 - - [14/Jun/2017:03:27:49 +0800] "GET /index.php HTTP/1.1" 302 154 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.81 Safari/537.36" "-"
61.151.186.217 - - [14/Jun/2017:03:27:49 +0800] "GET /index.php HTTP/1.1" 302 154 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.81 Safari/537.36" "-"
61.151.186.217 - - [14/Jun/2017:03:27:49 +0800] "GET /index.php HTTP/1.1" 302 154 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.81 Safari/537.36" "-"
61.151.186.217 - - [14/Jun/2017:03:27:49 +0800] "GET /index.php HTTP/1.1" 302 154 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.81 Safari/537.36" "-"
61.151.186.217 - - [14/Jun/2017:03:27:49 +0800] "GET /index.php HTTP/1.1" 302 154 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.81 Safari/537.36" "-"
有没有大神帮忙分析下是哪里配置有错误呢
1
Phant0m 2017-06-14 22:00:11 +08:00
```
local function getClientIp() local headers = ngx.req.get_headers() if not headers['x-forwarded-for'] then realIp = ngx.var.remote_addr or '127.0.0.1' return realIp end if type(headers['x-forwarded-for']) == "table" then realIp = headers['x-forwarded-for'][1] else realIp = headers['x-forwarded-for'] end return realIp end ``` |
2
blackjar 2017-06-14 23:40:46 +08:00
服务器设置 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
之后取 X-Forwarded-For 的第一个段值 可以拿到真实 ip |
3
ladyv2 OP |
4
ladyv2 OP 今天看 log,又出现了
61.151.186.154 - - [15/Jun/2017:01:30:00 +0800] "GET / HTTP/1.1" 302 154 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.81 Safari/537.36" "-" 61.151.186.154 - - [15/Jun/2017:01:30:00 +0800] "GET / HTTP/1.1" 302 154 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.81 Safari/537.36" "-" 访问次数 61.151.186.154 次 但是看 redis,完全没有记录。。 redis /tmp/redis.sock> keys 61.151.186 (empty list or set) 非常奇怪 |
6
ladyv2 OP @Phant0m 代码如下
local get_headers = ngx.req.get_headers local ua = ngx.var.http_user_agent local uri = ngx.var.request_uri local url = ngx.var.host .. uri local redis = require 'redis' local red = redis.new() local CCcount = 100 local CCseconds = 30 local blackseconds = 7200 if ua == nil then ua = "unknown" end local redis = require "resty.redis" local red = redis:new() red:set_timeout(1000) -- 1 sec local ok, err = red:connect("localhost") if not ok then ngx.say("failed to connect: ", err) return end local res, err = red:auth("password1") if not res then ngx.say("failed to authenticate: ", err) return end if ok then function getClientIp() IP = ngx.var.remote_addr --[[ IP = ngx.req.get_headers()["X-Real-IP"] if IP == nil then IP = ngx.req.get_headers()["x_forwarded_for"] end if IP == nil then IP = ngx.var.remote_addr end if IP == nil then IP = "unknown" end --]] return IP end local token = getClientIp() .. "." .. ngx.md5(url .. ua) local req = red:exists(token) if req == 0 then red:incr(token) red:expire(token,CCseconds) else local times = tonumber(red:get(token)) if times >= CCcount then local blackReq = red:exists("black." .. token) if (blackReq == 0) then red:set("black." .. token,1) red:expire("black." .. token,blackseconds) red:expire(token,blackseconds) ngx.exit(503) else ngx.exit(503) end return else red:incr(token) end end return end -- put it into the connection pool of size 100, -- with 10 seconds max idle time local ok, err = red:set_keepalive(10000, 1000) if not ok then return end |
7
Phant0m 2017-07-12 15:35:58 +08:00
@ladyv2 你代码里 存入 redis 的 key 不是 IP 啊,key 是 token = getClientIp() .. "." .. ngx.md5(url .. ua) ,直接取 IP 当然是空
|
8
Phant0m 2017-07-12 15:42:22 +08:00
还有最好把 IP 作为 key,如果按照你代码写的用 token,那么攻击者可以不停的更换 url 来达到攻击的目的
|
9
ladyv2 OP @Phant0m 不是啊。查看是不是屏蔽也是查看的这个 token 啊。查看 redis 也是有被屏蔽的
1) "black.202.141.176.9.7c879b2da20d1694c748b1a70b8d9281" 2) "black.1.180.215.60.9a394cf0c48fba4606c9757d3d8527c5" 采用这个 token 也是经过考虑的。如果单纯用 IP,很容易把一些通过代理或者共用 IP 的地址封掉。所以只能采用 IP+URL+浏览器来计算 |
10
Phant0m 2017-07-13 00:13:22 +08:00
@ladyv2 你 27 天前的那个回复取的是 IP。。。 计数器可以用 ngx_lua 的内存字典,然后再放入 redis
|
11
ladyv2 OP @Phant0m 其实是一样的啊,利用 token 来屏蔽 IP
现在的问题就是像我主楼发的一样,有的 IP 大量访问同样的 URL (几十万次),居然没被屏蔽。这就是我没搞明白的问题。。。 |
15
chinaglwo 2017-12-01 21:55:29 +08:00
fastcgi_param HTTP_X_FORWARDED_FOR $remote_addr;
这个配置是不是很多余? |