123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- local redis = require "redis"
- local regex = require "rex_pcre"
- local mime = require "mime"
- local cipher = require "openssl.cipher"
- local redis_conn = nil
- function scw()
- -- local start_time = ngx.now()
- local has_redis = false
- local ignore = os.getenv("SCW_IGNORE")
- local uri = ngx.var.uri
- local req_uri = ngx.var.request_uri
- ngx.log(ngx.INFO, "req_uri: " .. req_uri)
- if ignore ~= nil and regex.match(uri, ignore) then
- return -- do norhing if configured to ignore
- end
- -- --------------------------------------------------------------------------
- -- Does the user have an encrypted scw cookie that proves he is human?
- --
- local cookie_name = "cookie_" .. tostring(os.getenv("SCW_COOKIE"))
- if cookie_name == "cookie_" then
- ngx.log(ngx.ERR, "SCW_COOKIE is not set!")
- return
- end
- local scw_key = os.getenv("SCW_KEY")
- if scw_key == nil or scw_key == "" then
- ngx.log(ngx.ERR, "SCW_KEY is not set!")
- return
- end
- local cookie_key = ngx.decode_base64(scw_key)
- local human_cookie = ngx.var[cookie_name]
- local xff = tostring(ngx.var["http_x_forwarded_for"])
- local rip = tostring(ngx.var["http_x_real_ip"])
- if human_cookie then
- human_cookie = ngx.decode_base64(ngx.unescape_uri(human_cookie))
- end
- local is_human = false
- if human_cookie ~= nil and cookie_key:len() == 32 then
- local cookie_data = _decrypt(human_cookie, cookie_key)
- local cookie_ip = string.gsub(cookie_data, "scw|(.-)|(%d+)$", "%1")
- local cookie_expiry = string.gsub(cookie_data, "scw|(.-)|(%d+)$", "%2")
- is_human = cookie_ip ~= "" and (cookie_ip == ngx.var.remote_addr or cookie_ip == xff or cookie_ip == rip) and ngx.now() <= tonumber(cookie_expiry)
- if is_human then
- return
- end
- end
- -- --------------------------------------------------------------------------
- -- check for blacklist status
- --
- if pcall(function() redis_conn:ping() end) then
- has_redis = true
- else
- -- io.stderr:write("reconnecting to redis\n")
- local redis_host = os.getenv("SCW_REDIS_HOST")
- local redis_port = os.getenv("SCW_REDIS_PORT")
- if redis_host == nil or redis_host == "" then
- ngx.log(ngx.ERR, "SCW_REDIS_HOST is not set!")
- return
- end
- if redis_port == nil or redis_port == "" then
- ngx.log(ngx.ERR, "SCW_REDIS_PORT is not set!")
- return
- end
- if pcall(function() redis_conn = redis.connect(redis_host, 6379) end) then
- has_redis = true
- end
- end
- local captcha_url = os.getenv("SCW_CAPTCHA_URL")
- if captcha_url == nil or captcha_url == "" then
- ngx.log(ngx.ERR, "SCW_CAPTCHA_URL is not set!")
- return
- end
- if has_redis and captcha_url ~= "" then
- -- the client ip
- local v = redis_conn:get("bl:" .. ngx.var.remote_addr)
- -- the X-Forwarded-For IP
- if v == nil then
- v = redis_conn:get("bl:" .. xff)
- end
- -- the X-Real-IP IP
- if v == nil then
- v = redis_conn:get("bl:" .. rip)
- end
- if v ~= nil then -- and h == nil then
- local rprotocol = "http"
- if ngx.var.scheme == "https" or ngx.var["http_x_forwarded_proto"] == "https" then
- rprotocol = "https"
- end
- ngx.log(ngx.INFO, "port: " .. ngx.var.server_port)
- local rport = ""
- if (rprotocol == "https" and ngx.var.server_port ~= 443) or (rprotocol == "http" and ngx.var.server_port ~= 80) then
- rport = string.format(":%d", ngx.var.server_port)
- end
- local referer = string.format("%s://%s%s%s", rprotocol, ngx.var.host, rport, ngx.var.uri)
- return ngx.redirect(string.format(captcha_url, ngx.var.remote_addr, ngx.escape_uri(referer)))
- end
- end
- end
- function _decrypt(message_and_iv, key)
- if message_and_iv:len() < 32 then
- return ""
- end
- iv, _ = message_and_iv:sub(1, 16)
- message, _ = message_and_iv:sub(17, -1)
- local c = cipher.new("aes-256-cbc")
- c:decrypt(key, iv)
- cleartext, err = c:final(message)
- if err ~= nil then
- return ""
- end
- return cleartext
- end
- scw()
|