现在很多网站考虑安全,会做人机验证,可以有效的防刷,防爬虫,防止暴力破解。 你是否遇到过这个 这个 还有这个前言
如何实现人机验证,又不用和前端耦合在一起,类似waf,在第一层做验证,不通过就直接拦截。nginx支持调用lua脚本,于是可以使用nginx_lua_module来实现。 我们先看看Nginx指令处理阶段: 访问某个需要人机验证的页面时,在content_by_lua做处理,如果没经过人机验证,我们返回人机验证页面,浏览器人机验证后,做缓存和cookies,我定了12个小时。也就是12小时内任何页面不需要再做人机验证。 大概的流程如下:如何实现?
实现人机验证步骤
1、申请谷歌recaptcha接口参数,https://www.google.com/recaptcha/admin
2、安装lua环境,nginx编译安装lua-nginx-module
3、nginx配置需要做人机验证的页面
- 111
- nginx配置
# 人机验证通过,需要过滤的接口 location ~ ^(/api1|api2|api3)$ { include vhost/valid.conf; access_by_lua_file lua/api_filter.lua; }
- 编写recaptcha.lua做页面人机验证逻辑
-- 1、解密cookies,ip是否已存在缓存 -- local headers = ngx.req.get_headers() -- 如果已存在验证过的cookies cap,解析正确则不拦截 local zhong_cap = ngx.var.cookie_cap if zhong_cap and #zhong_cap > 0 then local aes_128_cbc_with_iv = assert(aes:new(key,nil, aes.cipher(128,"cbc"), {iv=iv})) -- AES 128 CBC with IV and no SALT local cipherBytes = ngx.decode_base64(zhong_cap) local cache_ip = aes_128_cbc_with_iv:decrypt(cipherBytes) if cache_ip ~= nil and cache_ip and #cache_ip > 0 then ngx.log(ngx.INFO, "-------------cache_ip-------------"..cache_ip) local request_ip = ngx.var.ip ngx.log(ngx.INFO, "-------------request_ip-------------"..request_ip) if cache_ip == request_ip then cap_cache = "1" -- redis续期 redis_util.set_redis("cap:"..request_ip,cap,cap_second) -- ip已经缓存过,直接放行 ngx.log(ngx.INFO, "-------------正常转发-------------") ngx.exec("@proxy_pass") return; end end end ngx.log(ngx.INFO, "-------------人机验证-------------"..json.encode(ngx.var.request_uri)) local html = "<script>" .." window.onload = function() {" .." window.challenge_conf = {'is_interactive':1,'cserver_addr':'"/recaptcha/html/cap3.html','rule_id':1 };" .." var challenge_uri = '"/recaptcha/html/cap3.html';" .." var xhr = new XMLHttpRequest();" .." xhr.open('GET', challenge_uri + '?&' + Math.random());" .." xhr.send();" .." xhr.onload = function() {" .." if (xhr.status == 200) {" .." console.log(xhr.response);" .." document.write(xhr.response);" .." document.close();" .." }" .." };" .." }" .."</script>" .."<p>加载中...</p>" ngx.header.content_type="text/html;charset=utf8" ngx.say(html) return、
- 编写api_filter过滤是否通过人机验证逻辑
-- 判断白名单(白名单直接通过) for key, value in ipairs(white_apis) do local url = value["url"] local args = value["args"] if(url == request_uri) then ngx.log(ngx.INFO,"3") if not args then -- 白名单,无参数,直接通过 ngx.exec("@proxy_pass") return else local flag = 1 for args_k,args_v in pairs(args) do local request_v = tostring(arg_json[args_k]) args_v = tostring(args_v) if(args_v=="" or args_v == nil or args_v == 'nil')then if(request_v == "" or request_v == nil or request_v == 'nil')then else flag = 0 end else if(args_v == request_v) then else flag = 0 end end end if(flag == 1)then ngx.log(ngx.INFO,"白名单通过"..request_url) ngx.exec("@proxy_pass") return; end end end end -- 判断接口是否已通过人机验证 local remoteIp = ngx.var.ip local val = redis_util.get_redis("cap:"..remoteIp) ngx.log(ngx.INFO,"缓存"..json.encode(val)) if(val == "null")then ngx.exit(403) -- ngx.header.content_type="application/json;charset=UTF-8" -- local ret = { -- code= "200", -- data= { -- current= 1, -- size=15, -- }, -- msg= "操作成功", -- success= true, -- } -- ngx.say(json.encode(ret)) return; else ngx.exec("@proxy_pass") return; end
- 实现效果如下:
具体源码不免费,有需要可以联系QQ839293390,可定制化实现、部署。 标签:..,lua,--,ip,身份验证,local,nginx,人机,ngx From: https://www.cnblogs.com/suruozhong/p/17751984.html最后