越来越多的人使用VPS主机建站,但是与虚拟主机或者管理型的服务器相比,个人VPS主机基本上是无管理型的,即主机商只负责VPS主机的网络畅通,至于技术上的问题都得靠自己来解决。网站经常会受到一些自动化工具的扫描、注入、溢出挂马等等的情况。
商用虚拟主机有专门的运维工程师做好安全防范工作,正如上面所说VPS等等的虚拟云机是没有什么专门人员辅助运维的,这需要我们自己来进行操作,今天给他家介绍一款非常不错的Nginx(openresty)WEB应用防火墙模块ngx_lua_waf。ngx_lua_waf一个基于ngx_lua的web应用防火墙,代码非常的简单,开发者的初衷是方便使用,在高性能的同时保留其轻量级的特点。
Ngx_lua_waf的主要作用
- 防止sql注入,本地包含,部分溢出,fuzzing测试,xss,SSRF等web攻击
- 防止svn/备份之类文件泄漏
- 防止ApacheBench之类压力测试工具的攻击
- 屏蔽常见的扫描黑客工具,扫描器
- 屏蔽异常的网络请求
- 屏蔽图片附件类目录php执行权限
- 防止webshell上传
这里我们可以看出Ngx_lua_waf的功能还是相当丰富的,可以有效的拒绝大部分扫描攻击,对于防止网站被挂马有着非常显著的作用。
安装要求
Ngx_lua_waf的作者推荐使用lujit2.1做lua的支持,ngx_lua如果是0.9.2以上版本,建议正则过滤函数改为ngx.re.find,匹配效率会提高三倍左右。我们的Nginx只需要编译lua支持就可以部署这款WEB应用防火墙,为我们的服务器添加一道安全门。
使用说明
我们假设nginx安装路径为:/usr/local/nginx/conf/
我们只需要把ngx_lua_waf下载到conf目录下,解压命名为waf即可,在nginx.conf的http段添加,或者单独写作一个conf文件,使用include引用到nginx.conf中亦可。
- lua_package_path “/usr/local/nginx/conf/waf/?.lua”;
- lua_shared_dict limit 10m;
- init_by_lua_file /usr/local/nginx/conf/waf/init.lua;
- access_by_lua_file /usr/local/nginx/conf/waf/waf.lua;
配置config.lua里的waf规则目录(一般在waf/conf/目录下)
- RulePath = “/usr/local/nginx/conf/waf/wafconf/”
然后我们按照调试准则,先运行nginx -t检测一下配置是否正确,如果提示成功加载我们再重启nginx即可。
配置文件详细说明:
- RulePath = “/usr/local/nginx/conf/waf/wafconf/”
- –规则存放目录
- attacklog = “off”
- –是否开启攻击信息记录,需要配置logdir
- logdir = “/usr/local/nginx/logs/hack/”
- –log存储目录,该目录需要用户自己新建,切需要nginx用户的可写权限
- UrlDeny=”on”
- –是否拦截url访问
- Redirect=”on”
- –是否拦截后重定向
- CookieMatch = “on”
- –是否拦截cookie攻击
- postMatch = “on”
- –是否拦截post攻击
- whiteModule = “on”
- –是否开启URL白名单
- black_fileExt={“php”,”jsp”}
- –填写不允许上传文件后缀类型
- ipWhitelist={“127.0.0.1”}
- –ip白名单,多个ip用逗号分隔
- ipBlocklist={“1.0.0.1”}
- –ip黑名单,多个ip用逗号分隔
- CCDeny=”on”
- –是否开启拦截cc攻击(需要nginx.conf的http段增加lua_shared_dict limit 10m;)
- CCrate = “100/60”
- –设置cc攻击频率,单位为秒.
- –默认1分钟同一个IP只能请求同一个地址100次
- html=[[Please go away~~]]
- –警告内容,可在中括号内自定义
- 备注:不要乱动双引号,区分大小写
检查规则是否生效
部署完毕可以尝试如下命令:
- curl http://xxxx/test.php?id=../etc/passwd
- 返回”Please go away~~”字样,说明规则生效。
注意:默认,本机在白名单不过滤,可自行调整config.lua配置
分享自然正在使用的规则
自然把配置单独存储为一个waf.conf文件,在nginx.conf中使用include的方式加载。
waf.conf文件代码如下:
- lua_shared_dict limit 20m;
- lua_package_path “/usr/local/nginx/conf/waf/?.lua;;”;
- init_by_lua_file “/usr/local/nginx/conf/waf/init.lua”;
- access_by_lua_file “/usr/local/nginx/conf/waf/access.lua”;
waf文件夹下的config.lua配置如下:
- –WAF config file,enable = “on”,disable = “off”
- –waf status
- config_waf_enable = “on”
- –log dir
- config_log_dir = “/data/wwwlogs”
- –rule setting
- config_rule_dir = “/usr/local/nginx/conf/waf/wafconf”
- –enable/disable white url
- config_white_url_check = “on”
- –enable/disable white ip
- config_white_ip_check = “on”
- –enable/disable block ip
- config_black_ip_check = “on”
- –enable/disable url filtering
- config_url_check = “on”
- –enalbe/disable url args filtering
- config_url_args_check = “on”
- –enable/disable user agent filtering
- config_user_agent_check = “on”
- –enable/disable cookie deny filtering
- config_cookie_check = “on”
- –enable/disable cc filtering
- config_cc_check = “on”
- –cc rate the xxx of xxx seconds
- config_cc_rate = “60/60”
- –enable/disable post filtering
- config_post_check = “on”
- –config waf output redirect/html
- config_waf_output = “html”
- –if config_waf_output ,setting url
- config_waf_redirect_url = “/captcha”
- config_waf_captcha_html=[[
- <html>
- <head>
- <meta http-equiv=”content-type” content=”text/html; charset=UTF-8″>
- <title data-sw-translate>Please enter verification code – OneinStack WAF</title>
- <style> body { font-family: Tahoma, Verdana, Arial, sans-serif; }
- .head_title{margin-top:100px; font-family:”微软雅黑”; font-size:50px; font-weight:lighter;}
- p{font-family:”微软雅黑”; font-size:16px; font-weight:lighter; color:#666666;}
- .btn{ float:left;margin-left:15px; margin-top:5px; width:85px; height:30px; background:#56c458;font-family:”微软雅黑”; font-size:16px; color:#FFFFFF; border:0;}
- .inp_s{ float:left; margin-left:15px; margin-top:5px; width:200px; height:30px;}
- .yz{float:left; width:160px; height:40px;}
- .fors{ margin:0 auto;width:500px; height:40px;}
- .form {width: 500px; margin: 2em auto;}
- </style>
- </head>
- <body>
- <div align=”center”>
- <p><h1 class=”head_title” data-sw-translate>Sorry…</h1></p>
- <p data-sw-translate>Your query looks similar to an automated request from computer software. In order to protect our users, please forgive us for temporarily not processing your request.</p>
- <p data-sw-translate>To continue accessing the webpage, please enter the characters shown below:</p>
- <div class=”form”>
- <img id=”captcha-img” class=”yz” src=”https://oneinstack.com/restapi/v1/captchas/038fb48d9f8170e9a7c67aee79106a31″ alt=”Captcha image”><input id=”captcha-input” class=”inp_s” type=”text” name=”response” /><input id=”captcha-submit” class=”btn” type=”submit” data-sw-translate value=”Submit” />
- </div>
- </div>
- <script src=”https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js”></script>
- <script>
- var url = ‘https://oneinstack.com/restapi/v1/captchas’
- // 获取验证码 hash
- $.post(url).then((res) => {
- const {errno, errmsg, data} = JSON.parse(res)
- if (errno) {
- return alert(errmsg)
- }
- // 更新验证码图片
- document.querySelector(‘#captcha-img’).src = `${url}/${data}`
- // 提交验证码
- document.querySelector(‘#captcha-submit’).addEventListener(‘click’, e => {
- $.post(`${url}/check`, {
- key: data,
- code: document.querySelector(‘#captcha-input’).value,
- }).then(res => {
- const {errno, errmsg, data} = JSON.parse(res)
- if (errno) {
- return location.reload()
- }
- var targetUrl = new URLSearchParams(location.search).get(‘continue’)
- targetUrl = atob(targetUrl)
- location.href = targetUrl
- })
- })
- })
- window.SwaggerTranslator = {
- _words: [],
- translate: function () {
- var $this = this;
- $(‘[data-sw-translate]’).each(function () {
- $(this).html($this._tryTranslate($(this).html()));
- $(this).val($this._tryTranslate($(this).val()));
- $(this).attr(‘title’, $this._tryTranslate($(this).attr(‘title’)));
- });
- },
- _tryTranslate: function (word) {
- return this._words[$.trim(word)] !== undefined ? this._words[$.trim(word)] : word;
- },
- learn: function (wordsMap) {
- this._words = wordsMap;
- }
- };
- window.SwaggerTranslator.learn({
- “Please enter verification code – OneinStack WAF”: “输入验证码”,
- “Your query looks similar to an automated request from computer software. In order to protect our users, please forgive us for temporarily not processing your request.”: “您的查询看起来类似于来自计算机软件的自动请求。为了保护我们的用户,请原谅我们现在暂时不能处理您的请求。”,
- “To continue accessing the webpage, please enter the characters shown below:”: “要继续访问网页,请输入下面所示字符:”,
- “Sorry…”: “很抱歉…”,
- “Submit”: “提交”,
- });
- $(function () {
- window.SwaggerTranslator.translate();
- });
- </script>
- </body>
- </html>
- ]]
- config_output_html=[[
- <html xmlns=”http://www.w3.org/1999/xhtml”><head>
- <meta http-equiv=”Content-Type” content=”text/html; charset=utf-8″>
- <title>网站防火墙</title>
- <style>
- p {
- line-height:20px;
- }
- ul{ list-style-type:none;}
- li{ list-style-type:none;}
- </style>
- </head>
- <body style=” padding:0; margin:0; font:14px/1.5 Microsoft Yahei, 宋体,sans-serif; color:#555;”>
- <div style=”margin: 0 auto; width:1000px; padding-top:70px; overflow:hidden;”>
- <div style=”width:600px; float:left;”>
- <div style=” height:40px; line-height:40px; color:#fff; font-size:16px; overflow:hidden; background:#6bb3f6; padding-left:20px;”>网站防火墙 </div>
- <div style=”border:1px dashed #cdcece; border-top:none; font-size:14px; background:#fff; color:#555; line-height:24px; height:220px; padding:20px 20px 0 20px; overflow-y:auto;background:#f3f7f9;”>
- <p style=” margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;”><span style=” font-weight:600; color:#fc4f03;”>您的请求带有不合法参数,已被网站管理员设置拦截!</span></p>
- <p style=” margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;”>可能原因:您提交的内容包含危险的攻击请求</p>
- <p style=” margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;”>如何解决:</p>
- <ul style=”margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;”><li style=” margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;”>1)检查提交内容;</li>
- <li style=” margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;”>2)如网站托管,请联系空间提供商;</li>
- <li style=” margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;”>3)普通网站访客,请联系网站管理员;</li></ul>
- </div>
- </div>
- </div>
- </body></html>
- ]]
自然使用的oneinstack的包:http://mirrors.linuxeye.com/oneinstack/src/ngx_lua_waf.tar.gz
不要问我为什么,应为oneinstack非常好用。
总结
自然正在使用这款web应用防火墙,效果还是非常不错的。对于服务器安全比较看重的小伙伴们可以使用一下,不需要占用太多资源即可为网站部署一款效果显著的WEB应用防火墙,对于不像额外购买web应用防火墙的小伙伴而言是一个极佳的选择。