简介

对于信息类网站,总是会被各种不同目的的爬虫、采集器等不断的抓取或恶意访问,这些会让网站不堪重负,导致页面无法正常访问,极大的影响用户体验。针对此种情况,我们就需要对所有的访问来进行访问控制。

此时Web应用防火墙(Web Application Firewall,简称 WAF)就可以助我们一臂之力,它可以为网站提供一站式安全防护。WAF可以有效识别Web业务流量的恶意特征,在对流量进行清洗和过滤后,将正常、安全的流量返回给服务器,避免网站服务器被恶意入侵导致服务器性能异常等问题,保障网站的业务安全和数据安全。

Web应用防火墙主要功能如下:

  • 提供Web应用攻击防护。
  • 缓解恶意CC攻击,过滤恶意的Bot流量,保障服务器性能正常。
  • 支持对HTTP和HTTPS流量进行访问控制。

从WAF的定义及功能看,它的位置应该处于流量入口处。如果选用商业产品,多和CDN配合使用;如果自行开发,其位置应该在负载均衡Nginx上。结合lua可以进行二次扩展,实现个性化访问控制需求。

分析

在使用Nginx+lua实现个性化需求前,我们首先需要了解我们的网站的流量组成:

  1. 爬虫流量

    百度、bing、谷歌、360、一搜、神马、今日头条、采集器等

  2. 异常流量

    单IP大流量访问、多IP大流量访问

  3. 恶意攻击

    DDos、CC、SQL注入、暴力破解等

  4. 正常流量

  5. 三方渠道大流量访问

以上基本概括了我们网站的主要流量来源,这些流量我们可以从基础防护和动态防护两个层面展开。

基础防护

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,结合日常流量的统计分析,我们主要想实现以下几方面:

  1. 黑白名单

    对于三方合作渠道的IP加入白名单,没有规则策略;

    通过分析日常流量,将异常行为的IP加到黑名单,前端直接返回403;

  2. 最大访问量

    对于不在白名单内的IP,每个IP的每天访问量在正常情况下应该是要有上限的,为避免IP过量访问我们需要应该进行限制;

  3. 人机验证

    (1)对于不在白名单内的IP,每个IP在一定周期内的访问量超限,此时需要跳转至验证码页进行人机验证;

    (2)如果验证码页验证次数超限,则认定为暴力破解,将IP进行封禁一段时间;

    (3)暴力破解的IP封禁超时后,重新解禁,再次访问将重新认证;

  4. 反查域名

    对于冒充搜索引擎试图跳过访问策略的请求,我们将进行域名反查;确定是否为真正的爬虫,若为搜索引擎则加入白名单。

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应用防火墙相关推荐

  1. 基于nginx tomcat redis分布式web应用的session共享配置

    一.前言 nginx 作为目前最流行的开源反向代理HTTP Server,用于实现资源缓存.web server负载均衡等功能,由于其轻量级.高性能.高可靠等特点在互联网项目中有着非常普遍的应用,相关 ...

  2. 基于nginx的高可用web集群

    文章目录 一.写在前面 编译下载 nginx.conf文件解析 安装好后的操作 日志问题,不同级别的错误 二.环境搭建学习 web服务器配置 错误页面跳转 IO多路复用 在nginx里部署https服 ...

  3. 基于 Nginx+lua+Memcache 实现灰度发布

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 一.灰度发布原理说明 灰度发布在百度百科中解释: 灰度发布 ...

  4. CentOS Linux下用Nginx和Naxsi搭建Web应用防火墙

    Naxsi是一个开源,高性能,低维护规则,nginx的Web应用程序防火墙模块,著名的Web服务器和反向代理.它的目标是帮助人们保护其Web应用程序,对跨站脚本,SQL注入,跨站请求伪造,本地和远程文 ...

  5. 基于nginx搭建直播,web播放视频方案

    1 流媒体服务器nginx搭建: #nginx源码     git clone https://github.com/nginx/nginx.git #nginx的rtmp模块源码     git c ...

  6. 开源框架openresty+nginx 实现web应用防火墙(WAF)

    1.简介 Web应用防火墙(Web Application Firewall, WAF),通过对HTTP(S)请求进行检测,识别并阻断SQL注入.跨站脚本攻击(Cross Site Scripting ...

  7. 用Nginx+Lua(OpenResty)开发高性能Web应用

    在互联网公司,Nginx可以说是标配组件,但是主要场景还是负载均衡.反向代理.代理缓存.限流等场景:而把Nginx作为一个Web容器使用的还不是那么广泛.Nginx的高性能是大家公认的,而Nginx开 ...

  8. 使用Nginx+Lua(OpenResty)开发高性能Web应用

    在互联网公司,Nginx可以说是标配组件,但是主要场景还是负载均衡.反向代理.代理缓存.限流等场景:而把Nginx作为一个Web容器使用的还不是那么广泛.Nginx的高性能是大家公认的,而Nginx开 ...

  9. 「京东开涛」使用Nginx+Lua(OpenResty)开发高性能Web应用

    几乎所有互联网公司,Nginx可以说是标配组件,但是主要场景还是负载均衡.反向代理.代理缓存.限流等场景:而把Nginx作为一个Web容器使用的还不是那么广泛.Nginx的高性能是大家公认的,而Ngi ...

  10. _Linux自编译云锁Web网站防火墙,看完小白也能保护网站安全

    图/文:迷神 之前写了一篇云锁防护网站入侵攻击的文章,但是那个是基于宝塔自带的添加模块功能,有的人说,不带那个功能.那接下来,我们就讲讲Linux下通过自编译Nginx添加云锁Web网站防火墙模块,这 ...

最新文章

  1. OWA登录页面显示为英文而不是中文
  2. hibernate教程--持久化类状态
  3. 【51CTO/BBS】请教: SQL里有没有字符串组合Join的函数??
  4. python中fork创建新的进程
  5. 最近流行的12个笑话,好笑又有道理
  6. 企业内部自建用户行为分析平台全过程
  7. c语言迷宫源码,C语言迷宫源代码
  8. 补发 四人小组 组队简单说明
  9. No MyBatis mapper was found in ‘[xx]‘ package. Please check your configuration.
  10. 中国各省常住人口和GDP数据( 2001-2019年)
  11. Python爬虫_宅男福利?妹纸勿点__一蓑烟雨任平生
  12. 线性代数感悟之4 通过增广矩阵查看解的情况上篇
  13. 矢量绘图软件源码定制开发,类似visio绘图,大量复合图元模板,可编程动态控制图元
  14. 学习日记12(类和对象)
  15. 什么是开关量,I/O区分详细解答
  16. Leetcode-数据结构-350. 两个数组的交集 II
  17. 英文单词缩写----DXNRY – Dictionary 字典
  18. python3画直方图出现“Polygon‘ object has no property ‘normed”
  19. postgre数据库字符串函数和日期函数操作小记
  20. DTS 及其在PG 数据库生态中的应用

热门文章

  1. oracle归档日志百分比,Oracle归档日志处理
  2. html如何消除空格字符串,jquery如何去除字符串的空格
  3. python脚本转换为EXE文件
  4. 11 week blog
  5. nodejs文件相关模块
  6. jQuery节点创建与属性的处理 创建节点
  7. phpstorm设置背景图片
  8. LintCode Python 简单级题目 112.删除链表中的重复元素
  9. WebApi基于Token和签名的验证
  10. QML 自定义鼠标光标