基于Nginx+Lua自建Web应用防火墙
简介
对于信息类网站,总是会被各种不同目的的爬虫、采集器等不断的抓取或恶意访问,这些会让网站不堪重负,导致页面无法正常访问,极大的影响用户体验。针对此种情况,我们就需要对所有的访问来进行访问控制。
此时Web应用防火墙(Web Application Firewall,简称 WAF)就可以助我们一臂之力,它可以为网站提供一站式安全防护。WAF可以有效识别Web业务流量的恶意特征,在对流量进行清洗和过滤后,将正常、安全的流量返回给服务器,避免网站服务器被恶意入侵导致服务器性能异常等问题,保障网站的业务安全和数据安全。
Web应用防火墙主要功能如下:
- 提供Web应用攻击防护。
- 缓解恶意CC攻击,过滤恶意的Bot流量,保障服务器性能正常。
- 支持对HTTP和HTTPS流量进行访问控制。
从WAF的定义及功能看,它的位置应该处于流量入口处。如果选用商业产品,多和CDN配合使用;如果自行开发,其位置应该在负载均衡Nginx上。结合lua可以进行二次扩展,实现个性化访问控制需求。
分析
在使用Nginx+lua实现个性化需求前,我们首先需要了解我们的网站的流量组成:
爬虫流量
百度、bing、谷歌、360、一搜、神马、今日头条、采集器等
异常流量
单IP大流量访问、多IP大流量访问
恶意攻击
DDos、CC、SQL注入、暴力破解等
正常流量
三方渠道大流量访问
以上基本概括了我们网站的主要流量来源,这些流量我们可以从基础防护和动态防护两个层面展开。
基础防护
Nginx 不仅在负载均衡层面发挥着重要作用,其内置的一些基础模块,也可以在一定程度上做一些防护。
1.安全防护
对于站点流量,我们可以主动分析客户端请求的特征,如user_agent、url、query_string ;结合业务特点,可以对其制定一些规则来进行主动防范,在应对异常流量时起到一定的防护作用。
vim x.x.cn.conf
# 在站点文件添加web安全限制,返回不同的状态码
include conf.d/safe.conf;# 安全规则文件
vim safe.conf
# 禁SQL注入 Block SQL injections
set $block_sql_injections 0;
if ($query_string ~ "union.*select.*(.*)") {
set $block_sql_injections 1;
}
if ($request_uri ~* "select((/\*+/)|[+ ]+|(%20)+)") {set $block_sql_injections 1;
}
if ($request_uri ~* "union((/\*+/)|[+ ]+|(%20)+)") {set $block_sql_injections 1;
}
if ($request_uri ~* "order((/\*+/)|[+ ]+|(%20)+)by") {set $block_sql_injections 1;
}
#匹配"group/**/by", "group+by", "group by"
if ($request_uri ~* "group((/\*+/)|[+ ]+|(%20)+)by") {set $block_sql_injections 1;
}
if ($block_sql_injections = 1) {
return 444;
} # 禁掉文件注入
set $block_file_injections 0;
if ($query_string ~ "[a-zA-Z0-9_]=http://") {
set $block_file_injections 1;
}
if ($query_string ~ "[a-zA-Z0-9_]=(..//?)+") {
set $block_file_injections 1;
}
if ($query_string ~ "[a-zA-Z0-9_]=/([a-z0-9_.]//?)+") {
set $block_file_injections 1;
}
if ($block_file_injections = 1) {
return 444;
} # 禁掉溢出攻击
set $block_common_exploits 0;
if ($query_string ~ "(<|%3C).*script.*(>|%3E)") {
set $block_common_exploits 1;
}
if ($query_string ~ "GLOBALS(=|[|%[0-9A-Z]{0,2})") {
set $block_common_exploits 1;
}
if ($query_string ~ "_REQUEST(=|[|%[0-9A-Z]{0,2})") {
set $block_common_exploits 1;
}
if ($query_string ~ "proc/self/environ") {
set $block_common_exploits 1;
}
if ($query_string ~ "mosConfig_[a-zA-Z_]{1,21}(=|%3D)") {
set $block_common_exploits 1;
}
if ($query_string ~ "base64_(en|de)code(.*)") {
set $block_common_exploits 1;
}
if ($block_common_exploits = 1) {
return 444;
} # 禁spam字段
set $block_spam 0;
if ($query_string ~ "b(ultram|unicauca|valium|viagra|vicodin|xanax|ypxaieo)b") {
set $block_spam 1;
}
if ($query_string ~ "b(erections|hoodia|huronriveracres|impotence|levitra|libido)b") {
set $block_spam 1;
}
if ($query_string ~ "b(ambien|bluespill|cialis|cocaine|ejaculation|erectile)b") {
set $block_spam 1;
}
if ($query_string ~ "b(lipitor|phentermin|pro[sz]ac|sandyauer|tramadol|troyhamby)b") {
set $block_spam 1;
}
if ($block_spam = 1) {
return 444;
} # 禁掉user-agents
set $block_user_agents 0; #禁止agent为空
#if ($http_user_agent ~ ^$) {
#set $block_user_agents 1;
#} # Don’t disable wget if you need it to run cron jobs!
if ($http_user_agent ~ "Wget") {
set $block_user_agents 1;
} # Disable Akeeba Remote Control 2.5 and earlier
if ($http_user_agent ~ "Indy Library") {
set $block_user_agents 1;
} # Common bandwidth hoggers and hacking tools.
if ($http_user_agent ~ "libwww-perl") {
set $block_user_agents 1;
}
if ($http_user_agent ~ "GetRight") {
set $block_user_agents 1;
}
if ($http_user_agent ~ "GetWeb!") {
set $block_user_agents 1;
}
if ($http_user_agent ~ "Go!Zilla") {
set $block_user_agents 1;
}
if ($http_user_agent ~ "Download Demon") {
set $block_user_agents 1;
}
if ($http_user_agent ~ "Go-Ahead-Got-It") {
set $block_user_agents 1;
}
if ($http_user_agent ~ "TurnitinBot") {
set $block_user_agents 1;
}
if ($http_user_agent ~ "GrabNet") {
set $block_user_agents 1;
} if ($block_user_agents = 1) {
return 444;
} #spider
set $spider '2';
if ( $http_user_agent ~ .+Baiduspider.+ ){set $spider '0';
}
if ( $http_user_agent ~ .+Googlebot.+){set $spider '0';
}
if ( $http_user_agent ~ .+bingbot.+){set $spider '0';
}
if ( $http_user_agent ~ .+JikeSpider.+){set $spider '0';
}
if ( $http_user_agent ~ .+YoudaoBot.+){set $spider '0';
}
if ( $http_user_agent ~ .+Sosospider.+){set $spider '0';
}
if ( $http_user_agent ~ Yahoo!.+){set $spider '0';
}
if ( $http_user_agent ~ Sogou.+){set $spider '0';
}
if ( $http_user_agent ~ .+msnbot.+){set $spider '0';
}
if ( $http_user_agent ~ .+YandexBot.+){set $spider '0';
}
if ( $http_user_agent ~ .+Spider.+){set $spider '0';
}if ( $http_user_agent ~ YisouSpider){set $spider '1';
}
#if ( $http_user_agent ~ LBBROWSER){# set $spider '1';
#}
if ($spider = '1') {return 445;
}
通过分析客户端的user_agent、url、query_string 初步分析是否具备统一特征,并根据其行为返回不同的状态码:
- 444 sql注入、文件注入等攻击类请求
- 445 不符合user_agent规则的请求
通过状态码,我们可以快速定位请求属于哪类安全范畴。
2.连接数、频率限制
对于站点的访问连接数、访问频率,我们可以使用以下两个模块来做一些策略。此时可以对异常流量、恶意攻击起到一定的作用。
ngx_http_limit_conn_module
限制每个已定义的 key 的连接数量,特别是来自单个 IP 地址的连接数量。
ngx_http_limit_req_module
限制请求的处理速率,特别是单一的IP地址的请求的处理速率。它基于漏桶算法进行限制。
#针对url1访问频率每分100个limit_req_zone $binary_remote_addr zone=req_limit4:10m rate=100r/m;#针对url2访问频率每秒5个,burst 5个limit_req_zone $binary_remote_addr zone=req_limit3:10m rate=5r/s;#针对url3问频率每秒50个,burst 10个limit_req_zone $binary_remote_addr zone=req_limit2:10m rate=50r/s;#针对url4访问频率每分30个,burst 10个limit_req_zone $binary_remote_addr zone=req_limit1:10m rate=30r/m;
对于频率的阈值需要结合站点的实际访问流量、峰值来具体设置。基于漏桶算法,可以对突发流量进行整形,避免单一IP或多IP的大流量请求压垮服务器。
3.map自定义变量
map 指令通过使用 nginx 的内置变量创建自定义变量, 由 ngx_http_map_module 模块提供的,默认情况下安装 nginx 都会安装该模块。通过自定义变量来匹配某些特定规则,进行访问控制。
我们可以通过map来设置白名单,不在白名单的IP将返回403。
vim map.conf
map $remote_addr $clientip {# 默认为false;default fase;# 精确匹配或正则匹配IP,则返回true1.1.1.1 true;~*12.12.3 true;
}
# 如果客户端ip为false 则返回403
if( $clientip = 'false')
{return 403;
}
4.小结
基础防护在针对一些有规律的特征流量时,基于nginx基础模块做的一些工作。但对于一些动态流量的访问,这些规则就显得有些死板,无法满足需求。此时就行需要基于nginx+lua做一些个性化的需求。
动态防护
1.策略分析
基于WAF,结合日常流量的统计分析,我们主要想实现以下几方面:
黑白名单
对于三方合作渠道的IP加入白名单,没有规则策略;
通过分析日常流量,将异常行为的IP加到黑名单,前端直接返回403;
最大访问量
对于不在白名单内的IP,每个IP的每天访问量在正常情况下应该是要有上限的,为避免IP过量访问我们需要应该进行限制;
人机验证
(1)对于不在白名单内的IP,每个IP在一定周期内的访问量超限,此时需要跳转至验证码页进行人机验证;
(2)如果验证码页验证次数超限,则认定为暴力破解,将IP进行封禁一段时间;
(3)暴力破解的IP封禁超时后,重新解禁,再次访问将重新认证;
反查域名
对于冒充搜索引擎试图跳过访问策略的请求,我们将进行域名反查;确定是否为真正的爬虫,若为搜索引擎则加入白名单。
2.实施规划
1.openresty环境部署
组件 | 备注 |
---|---|
openresty | nginx+lua |
lua-resty-redis | lua连接redis |
redis | 存放客户端请求实时数据 |
人机验证功能页 | 由前端提供此页面 |
# 0.基础依赖
yum install -y GeoIP GeoIP-devel GeoIP-data libtool openssl openssl-devel
# 1.创建用户
groupadd openresty
useradd -G operesty openresty -s /bin/nologin# 2.准备源码包
openresty-xxx.tar.gz
pcre-xxx.tar.gztar -zxvf openresty-xxx.tar.gz
tar -zxvf pcre-xxx.tar.gz
# 3.安装 LuaJIT
cd openresty-xxx/bundle/LuaJIT-xxx
make clean
make
make install# 4.安装openresty
cd openresty-xxx
./configure --prefix=/usr/local/openresty --with-http_realip_module --with-pcre=../pcre-xxx --with-luajit --with-file-aio --with-http_sub_module --with-http_stub_status_module --with-http_ssl_module --with-http_realip_module --with-http_gzip_static_module --without-select_module --without-poll_module --with-http_geoip_module
make
make install# 5.lua-resty-redis模块安装
wget https://github.com/openresty/lua-resty-redis/archive/master.zip
unzip master.zip
cd lua-resty-redis-master#将lib拷贝到openresty安装目录下的lua文件夹内
cp -rf lib /usr/local/openresty/conf/lua
cd /usr/local/openresty/conf/lua/lib
ln -s redis.lua resty/redis.lua# 6. 安装redis
yum install redis -y
/etc/init.d/redis start
至此openresty的基础文件已经部署完毕,下一步需要加载lua脚本实现相关的策略配置。
2.lua脚本规划
统一将lua模块及相关脚本存放在/usr/local/openresty/conf/lua
目录下,其中:
- lib 存放lua模块
- access 存放lua脚本
lua|--lib| |-resty| | |-redis.lua| |-redis.lua #redis驱动|--access| |-config.lua #统一配置文件| |-access_init.lua #加载配置文件、获取客户端IP的方法| |-access_ip.lua #黑白名单过滤| |-access_veryfycode.lua #验证码
规划完成后,我们就需要在oprneresty加载即可。
vim nginx.conf
# 在http区域内添加如下配置。#加载lua配置初始化
init_by_lua_file '/usr/local/openresty/nginx/conf/lua/access/access_init.lua';#lua-resty-redis
lua_package_path "/usr/local/openresty/nginx/conf/lua/lib/resty/?.lua;;";#黑白名单封禁ip
access_by_lua_file '/usr/local/openresty/nginx/conf/lua/access/access_ip.lua';
其中init_by_lua_file、access_by_lua_file 就是openresty执行流程中的不同阶段,我们根据访问流程可以在各阶段配置不同的访问策略。
3.openresty执行流程
如图openresty执行流程,在相应的阶段我们的策略如下:
1.init初始化阶段
由于init阶段是流程的第一阶段,即nginx加载全局参数阶段,因此也需要首先加载我们的配置文件:
# vim config.lua
--waf统一配置文件--ip白名单
ipWhitelist={--"10.0.0.0-10.255.255.255",
--神马搜索
"42.156.0.0-42.156.255.255",
"42.120.0.0-42.120.255.255",
"106.11.0.0-106.11.255.255",
--三方渠道
"113.5.18.230-113.5.18.231",
"113.5.18.234",
--内网
"192.168.0.0-192.168.255.255",
}----ip黑名单
ipBlocklist={"39.104.180.188",
"42.236.10.1-42.236.10.254",
}
以上配置文件中的客户端单个地址和地址段,都是通过access_init.lua
来加载config.lua
配置文件并由相关方法进行IP解析:
# vim access_init.lua
--此文件为需要在http段配置init_by_lua_file '/usr/local/nginx/lua/access/access_init.lua';
--注意:由于连接reids无法在init阶段使用,因此验证码由单独的access_verifycode.lua文件使用;
--封禁策略:
--增加ip黑名单、白名单的ip段支持package.path = "/usr/local/openresty/nginx/conf/lua/access/?.lua;/usr/local/openresty/nginx/conf/lua/lib/?.lua;"
package.cpath = "/usr/local/openresty/nginx/conf/lua/?.so;/usr/local/openresty/nginx/conf/lua/lib/?.so;"--加载配置文件
require "config"--获取客户端ip
function getClientIp()IP = ngx.var.remote_addr if IP == nil thenIP = "unknown"endreturn IP
endfunction ipToDecimal(ckip)local n = 4local decimalNum = 0local pos = 0for s, e in function() return string.find(ckip, '.', pos, true) end don = n - 1decimalNum = decimalNum + string.sub(ckip, pos, s-1) * (256 ^ n)pos = e + 1if n == 1 then decimalNum = decimalNum + string.sub(ckip, pos, string.len(ckip)) endendreturn decimalNum
end# 白名单过滤
function whiteip()if next(ipWhitelist) ~= nil thenlocal cIP = getClientIp()local numIP = 0if cIP ~= "unknown" then numIP = tonumber(ipToDecimal(cIP)) endfor _,ip in pairs(ipWhitelist) dolocal s, e = string.find(ip, '-', 0, true)if s == nil and cIP == ip thenreturn trueelseif s ~= nil thensIP = tonumber(ipToDecimal(string.sub(ip, 0, s - 1)))eIP = tonumber(ipToDecimal(string.sub(ip, e + 1, string.len(ip))))if numIP >= sIP and numIP <= eIP thenreturn trueendendendendreturn false
end# 黑名单过滤
function blockip()if next(ipBlocklist) ~= nil thenlocal cIP = getClientIp()local numIP = 0if cIP ~= "unknown" then numIP = tonumber(ipToDecimal(cIP)) endfor _,ip in pairs(ipBlocklist) dolocal s, e = string.find(ip, '-', 0, true)if s == nil and cIP == ip thenngx.exit(403)return trueelseif s ~= nil thensIP = tonumber(ipToDecimal(string.sub(ip, 0, s - 1)))eIP = tonumber(ipToDecimal(string.sub(ip, e + 1, string.len(ip))))if numIP >= sIP and numIP <= eIP thenngx.exit(403)return trueendendendendreturn false
end
2.access阶段
1.黑白名单过滤
access阶段是nginx接受用户请求阶段,此时需要调用init阶段的方法获取客户端IP,与配置文件文件的黑白名单进行比较。
- 客户端IP在黑名单,直接返回403;
- 客户端IP在黑白名单,跳过策略限制;
--封禁策略:
--若需配置单独的ip及ip段黑白名单,请将此文件绑定到location的access_by_lua_file '/usr/local/openresty/conf/lua/access/access_ip.lua'package.path = "/usr/local/openresty/nginx/conf/lua/access/?.lua;/usr/local/openresty/nginx/conf/lua/lib/?.lua;"
package.cpath = "/usr/local/openresty/nginx/conf/lua/?.so;/usr/local/openresty/nginx/conf/lua/lib/?.so;"--示例:
--ip白名单
--ipWhitelist={"127.0.0.1","192.168.0.0-192.168.255.255"}
--ip黑名单
--ipBlocklist={"10.11.2.102"}if whiteip() then
elseif blockip() then
elsereturn
end
注意:我们将access_ip.lua
放在http区域
,说明黑白名单过滤是全局生效的,当然也可以绑定到某个location区域
局部生效。
2.人机验证
通过验证码实现人机验证,具体的验证码界面需要前端配置,openresty只负责将异常客户端跳转至验证码页面。
人机验证的策略如下:
1.每个ip每天访问总量上限400次,超出限制页面直接返回457;
2.每个ip半小时访问量上限为10次,超限后跳转至验证码;
(1)bind后,100次访问内仍未通过人机验证,则返回456;
(2)全天访问超400次访问,直接返回457;
3.搜索引擎通过反查域名确定是否为真正的爬虫,若为搜索引擎则加入白名单;
4.访问列表页>10,则直接跳转到验证码页;
注意:
- 此脚本所在服务器须安装nslookup命令;
- 每个ip的访问总量是每天累计的;
- 对需要进行验证码防采集的location,请配置access_by_lua_file ‘/usr/local/openresty/conf/lua/access/access_verifycode.lua’;
具体代码如下:
-- 添加验证码验证-- ip访问频率时间段(半小时)
local ip_time_out = 1800-- ip_time_out时间段内ip访问量
local max_connect_count = 10-- 每天ip访问量
local max_connect_count_perday = 400-- bind后,在 max_bind_count 次数内仍未解封,则返回456
local max_bind_count = 100-- 微信浏览器user_agent
local weixin_agent = "MicroMessenger"-- 搜索引擎名称
local crawl = { "Baiduspider", "Googlebot", "Sogou web spider", "360Spider" }
-- 搜索引擎关键词
local keyword = { "baidu", "google", "sogou", "360" }local bind_reaseon = { robot = "robot", limit_bind = "limit_bind", limit_perday = "limit_perday" }-- KEYS[1]是key_bind
-- KEYS[2]是key_count
-- ARGV[1]是ip_time_out + 1
-- ARGV[2]是max_connect_count
local bind_eval_string = "" .." local bind_count = redis.call('get', KEYS[1])" .." if bind_count and tonumber(bind_count) > 0 then" .." redis.call('incr', KEYS[1])" .." else" .." local access_count = redis.call('incr', KEYS[2])" .." if access_count == 1 then" .." redis.call('expire', KEYS[2], ARGV[1])" .." end" .." if access_count >= tonumber(ARGV[2]) then" .." redis.call('set', KEYS[1], 1, 'EX', '864000')" .." end" .." end" .." return bind_count"local function check_access(cache)local today_date = os.date("%Y-%m-%d")local this_time_period = math.floor(os.time() / ip_time_out)local key_nslookup = "nslookup_" .. ngx.var.remote_addrlocal key_bind = "bind_" .. ngx.var.remote_addrlocal key_white = "white_" .. ngx.var.remote_addrlocal key_count = "count_" .. this_time_period .. "_" .. ngx.var.remote_addrlocal key_count_perday = "count_perday_" .. today_date .. "_" .. ngx.var.remote_addrlocal is_whitelocal should_bindlocal res, err-- 检查是否白名单res, err = cache:get(key_white)if res == nil thenreturn nilelseif res == ngx.null thenis_white = nilelseis_white = resendif not is_white then--搜索引擎爬虫判断if ngx.var.http_user_agent ~= nil then-- 微信公众号访问跳过验证码访问if string.find(ngx.var.http_user_agent, weixin_agent) ~= nil thenis_white = "wx"else-- 非微信浏览器的ua判断for i, v in ipairs(crawl) doif string.find(ngx.var.http_user_agent, v) ~= nil then--反查搜索引擎域名res, err = cache:get(key_nslookup)if res == nil or res == ngx.null thenlocal handle = io.popen("nslookup " .. ngx.var.remote_addr)res = handle:read("*all")handle:close()cache:set(key_nslookup, res, "EX", "86400")endif string.find(res, keyword[i]) ~= nil thenres, err = cache:set(key_white, "spider", "EX", "8640000")is_white = "spider"endbreakendendendendendif not is_white then-- 检查是否已经 bind, eval 脚本中会对 key_bind key_count 进行计数,并在达到访问上限后,设置 key_bindlocal bind_countres, err = cache:eval(bind_eval_string, 2, key_bind, key_count, ip_time_out + 1, max_connect_count)if res == nil thenngx.log(ngx.ERR, "eval failed: " .. tostring(err))bind_count = 0elseif res == ngx.null thenbind_count = 0elsebind_count = resendif tonumber(bind_count) >= max_bind_count thenshould_bind = bind_reaseon.limit_bindelseif tonumber(bind_count) >= 1 thenshould_bind = bind_reaseon.robotendif not should_bind thenif check_is_reading_list() thenshould_bind = bind_reaseon.robotendendendif not should_bind thenif is_white == nil or (is_white ~= "wx" and is_white ~= "spider") thenres, err = cache:incr(key_count_perday)if res == nil thenres = 0endif res == 1 thencache:expire(key_count_perday, 86400)endif res >= max_connect_count_perday thenshould_bind = bind_reaseon.limit_perdayendendendreturn 1, should_bind
endlocal function check_visit_limit()local should_bindlocal redis = require "resty.redis"local cache = redis:new()cache:set_timeout(300000)local ok, err = cache:connect("192.168.3.129", 10005)if ok thenok, should_bind = check_access(cache)if ok thencache:set_keepalive(60000, 200)elsecache:close()endelsengx.log(ngx.INFO, "failed to connect redis" .. tostring(err))endif should_bind == bind_reaseon.limit_bind thenngx.exit(456)elseif should_bind == bind_reaseon.limit_perday thenngx.exit(457)elseif should_bind == bind_reaseon.robot thenlocal source = ngx.encode_base64(ngx.var.scheme .. "://" .. ngx.var.host .. ngx.var.request_uri)-- 前端提供的验证码页local dest = "http://authcode.xxx.cn/authcode.html" .. "?fromurl=" .. source-- 触发策略,跳转到验证码页面ngx.redirect(dest, 302)end
endlocal function doVerify()if whiteip() thenelseif blockip() thenelsecheck_visit_limit()end
enddoVerify()
注意:人机验证依赖redis存储统计信息,同时也可以通过匹配客户端的IP来匹配,用于解封误封的客户端。
总结
经过长时间的流量分析、攻防实战,通过自建的WAF我们防住了大部分的恶意访问。正所谓“道高一尺,魔高一丈”,如今的盗采行为已经和常规访问无差别,通过一般的人机验证已经无法区分。过于严格的策略,则会“伤敌一千,自损八百”,因此我们还是要找到一个合适平衡点。
基于Nginx+Lua自建Web应用防火墙相关推荐
- 基于nginx tomcat redis分布式web应用的session共享配置
一.前言 nginx 作为目前最流行的开源反向代理HTTP Server,用于实现资源缓存.web server负载均衡等功能,由于其轻量级.高性能.高可靠等特点在互联网项目中有着非常普遍的应用,相关 ...
- 基于nginx的高可用web集群
文章目录 一.写在前面 编译下载 nginx.conf文件解析 安装好后的操作 日志问题,不同级别的错误 二.环境搭建学习 web服务器配置 错误页面跳转 IO多路复用 在nginx里部署https服 ...
- 基于 Nginx+lua+Memcache 实现灰度发布
点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 一.灰度发布原理说明 灰度发布在百度百科中解释: 灰度发布 ...
- CentOS Linux下用Nginx和Naxsi搭建Web应用防火墙
Naxsi是一个开源,高性能,低维护规则,nginx的Web应用程序防火墙模块,著名的Web服务器和反向代理.它的目标是帮助人们保护其Web应用程序,对跨站脚本,SQL注入,跨站请求伪造,本地和远程文 ...
- 基于nginx搭建直播,web播放视频方案
1 流媒体服务器nginx搭建: #nginx源码 git clone https://github.com/nginx/nginx.git #nginx的rtmp模块源码 git c ...
- 开源框架openresty+nginx 实现web应用防火墙(WAF)
1.简介 Web应用防火墙(Web Application Firewall, WAF),通过对HTTP(S)请求进行检测,识别并阻断SQL注入.跨站脚本攻击(Cross Site Scripting ...
- 用Nginx+Lua(OpenResty)开发高性能Web应用
在互联网公司,Nginx可以说是标配组件,但是主要场景还是负载均衡.反向代理.代理缓存.限流等场景:而把Nginx作为一个Web容器使用的还不是那么广泛.Nginx的高性能是大家公认的,而Nginx开 ...
- 使用Nginx+Lua(OpenResty)开发高性能Web应用
在互联网公司,Nginx可以说是标配组件,但是主要场景还是负载均衡.反向代理.代理缓存.限流等场景:而把Nginx作为一个Web容器使用的还不是那么广泛.Nginx的高性能是大家公认的,而Nginx开 ...
- 「京东开涛」使用Nginx+Lua(OpenResty)开发高性能Web应用
几乎所有互联网公司,Nginx可以说是标配组件,但是主要场景还是负载均衡.反向代理.代理缓存.限流等场景:而把Nginx作为一个Web容器使用的还不是那么广泛.Nginx的高性能是大家公认的,而Ngi ...
- _Linux自编译云锁Web网站防火墙,看完小白也能保护网站安全
图/文:迷神 之前写了一篇云锁防护网站入侵攻击的文章,但是那个是基于宝塔自带的添加模块功能,有的人说,不带那个功能.那接下来,我们就讲讲Linux下通过自编译Nginx添加云锁Web网站防火墙模块,这 ...
最新文章
- OWA登录页面显示为英文而不是中文
- hibernate教程--持久化类状态
- 【51CTO/BBS】请教: SQL里有没有字符串组合Join的函数??
- python中fork创建新的进程
- 最近流行的12个笑话,好笑又有道理
- 企业内部自建用户行为分析平台全过程
- c语言迷宫源码,C语言迷宫源代码
- 补发 四人小组 组队简单说明
- No MyBatis mapper was found in ‘[xx]‘ package. Please check your configuration.
- 中国各省常住人口和GDP数据( 2001-2019年)
- Python爬虫_宅男福利?妹纸勿点__一蓑烟雨任平生
- 线性代数感悟之4 通过增广矩阵查看解的情况上篇
- 矢量绘图软件源码定制开发,类似visio绘图,大量复合图元模板,可编程动态控制图元
- 学习日记12(类和对象)
- 什么是开关量,I/O区分详细解答
- Leetcode-数据结构-350. 两个数组的交集 II
- 英文单词缩写----DXNRY – Dictionary 字典
- python3画直方图出现“Polygon‘ object has no property ‘normed”
- postgre数据库字符串函数和日期函数操作小记
- DTS 及其在PG 数据库生态中的应用