Skip to content

Commit

Permalink
use PCRE regex instead of LUA pattern and edit cors doc
Browse files Browse the repository at this point in the history
  • Loading branch information
fl0ppy-d1sk committed May 16, 2023
1 parent 4378f18 commit a9be973
Show file tree
Hide file tree
Showing 20 changed files with 161 additions and 140 deletions.
1 change: 0 additions & 1 deletion TODO
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,4 @@
- Plugins
- sessions helpers in utils
- sessions security : check IP address, check UA, ...
- CORS : edit security tuning doc + edit example
- fix db warnings (Got an error reading communication packets)
147 changes: 81 additions & 66 deletions docs/security-tuning.md

Large diffs are not rendered by default.

73 changes: 38 additions & 35 deletions docs/settings.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion examples/cors/autoconf.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ services:
labels:
- bunkerweb.SERVER_NAME=app1.example.com
- bunkerweb.USE_CORS=yes
- bunkerweb.CORS_ALLOW_ORIGIN=https://app2.example.com
- bunkerweb.CORS_ALLOW_ORIGIN=^https://app2\.example\.com$$
- bunkerweb.REMOTE_PHP=myapp1
- bunkerweb.REMOTE_PHP_PATH=/app

Expand Down
2 changes: 1 addition & 1 deletion examples/cors/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ services:
- USE_CLIENT_CACHE=yes
- USE_GZIP=yes
- app1.example.com_USE_CORS=yes
- app1.example.com_CORS_ALLOW_ORIGIN=https://app2.example.com
- app1.example.com_CORS_ALLOW_ORIGIN=^https://app2\.example\.com$$
- app1.example.com_ALLOWED_METHODS=GET|POST|HEAD|OPTIONS
- app1.example.com_REMOTE_PHP=myapp1
- app1.example.com_REMOTE_PHP_PATH=/app
Expand Down
2 changes: 1 addition & 1 deletion examples/cors/variables.env
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ DISABLE_DEFAULT_SERVER=yes
USE_CLIENT_CACHE=yes
USE_GZIP=yes
app1.example.com_USE_CORS=yes
app1.example.com_CORS_ALLOW_ORIGIN=https://app2.example.com
app1.example.com_CORS_ALLOW_ORIGIN=^https://app2\.example\.com$
app1.example.com_ALLOWED_METHODS=GET|POST|HEAD|OPTIONS
app1.example.com_LOCAL_PHP=/run/php/php-fpm.sock
app1.example.com_LOCAL_PHP_PATH=/var/www/html/app1.example.com
Expand Down
13 changes: 13 additions & 0 deletions src/bw/lua/bunkerweb/utils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -626,4 +626,17 @@ utils.new_cachestore = function()
return require "bunkerweb.cachestore":new(use_redis)
end

utils.regex_match = function(str, regex, options)
local all_options = "o"
if options then
all_options = all_options .. options
end
local match, err = ngx.re.match(str, regex, all_options)
if err then
logger:log(ngx.ERR, "error while matching regex " .. regex .. "with string " .. str)
return nil
end
return match
end

return utils
8 changes: 4 additions & 4 deletions src/common/core/blacklist/blacklist.lua
Original file line number Diff line number Diff line change
Expand Up @@ -294,15 +294,15 @@ function blacklist:is_blacklisted_uri()
-- Check if URI is in ignore list
local ignore = false
for i, ignore_uri in ipairs(self.lists["IGNORE_URI"]) do
if ngx.ctx.bw.uri:match(ignore_uri) then
if utils.regex_match(ngx.ctx.bw.uri, ignore_uri) then
ignore = true
break
end
end
-- Check if URI is in blacklist
if not ignore then
for i, uri in ipairs(self.lists["URI"]) do
if ngx.ctx.bw.uri:match(uri) then
if utils.regex_match(ngx.ctx.bw.uri, uri) then
return true, "URI " .. uri
end
end
Expand All @@ -315,15 +315,15 @@ function blacklist:is_blacklisted_ua()
-- Check if UA is in ignore list
local ignore = false
for i, ignore_ua in ipairs(self.lists["IGNORE_USER_AGENT"]) do
if ngx.ctx.bw.http_user_agent:match(ignore_ua) then
if utils.regex_match(ngx.ctx.bw.http_user_agent, ignore_ua) then
ignore = true
break
end
end
-- Check if UA is in blacklist
if not ignore then
for i, ua in ipairs(self.lists["USER_AGENT"]) do
if ngx.ctx.bw.http_user_agent:match(ua) then
if utils.regex_match(ngx.ctx.bw.http_user_agent, ua) then
return true, "UA " .. ua
end
end
Expand Down
4 changes: 1 addition & 3 deletions src/common/core/blacklist/jobs/blacklist-download.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,7 @@ def check_line(kind: str, line: bytes) -> Tuple[bool, bytes]:
if asn_rx.match(real_line):
return True, real_line
elif kind in ("USER_AGENT", "IGNORE_USER_AGENT"):
return True, line.replace(b"\\ ", b" ").replace(b"\\.", b"%.").replace(
b"\\\\", b"\\"
).replace(b"-", b"%-")
return True, b"(?:\\b)" + line + b"(?:\\b)"
elif kind in ("URI", "IGNORE_URI"):
if uri_rx.match(line):
return True, line
Expand Down
8 changes: 4 additions & 4 deletions src/common/core/blacklist/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
"BLACKLIST_USER_AGENT": {
"context": "multisite",
"default": "",
"help": "List of User-Agent, separated with spaces, to block.",
"help": "List of User-Agent (PCRE regex), separated with spaces, to block.",
"id": "blacklist-user-agent",
"label": "Blacklist User-Agent",
"regex": "^.*$",
Expand All @@ -99,7 +99,7 @@
"BLACKLIST_URI": {
"context": "multisite",
"default": "",
"help": "List of URI, separated with spaces, to block.",
"help": "List of URI (PCRE regex), separated with spaces, to block.",
"id": "blacklist-uri",
"label": "Blacklist URI",
"regex": "^( *(/[\\w\\].~:/?#[@!$&'()*+,;=-]*)(?!.*\\2(?!.)) *)*$",
Expand Down Expand Up @@ -171,7 +171,7 @@
"BLACKLIST_IGNORE_USER_AGENT": {
"context": "multisite",
"default": "",
"help": "List of User-Agent, separated with spaces, to ignore in the blacklist.",
"help": "List of User-Agent (PCRE regex), separated with spaces, to ignore in the blacklist.",
"id": "blacklist-ignore-user-agent",
"label": "Blacklist ignore User-Agent",
"regex": "^.*$",
Expand All @@ -189,7 +189,7 @@
"BLACKLIST_IGNORE_URI": {
"context": "multisite",
"default": "",
"help": "List of URI, separated with spaces, to ignore in the blacklist.",
"help": "List of URI (PCRE regex), separated with spaces, to ignore in the blacklist.",
"id": "blacklist-ignore-uri",
"label": "Blacklist ignore URI",
"regex": "^( *(/[\\w\\].~:/?#[@!$&'()*+,;=-]*)(?!.*\\2(?!.)) *)*$",
Expand Down
9 changes: 3 additions & 6 deletions src/common/core/cors/cors.lua
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ function cors:header()
ngx.header.Vary = "Origin"
end
-- Check if Origin is allowed
if self.variables["CORS_ALLOW_ORIGIN"] ~= "*" and not ngx.ctx.bw.http_origin:match(self.variables["CORS_ALLOW_ORIGIN"]) then
if ngx.ctx.bw.http_origin and self.variables["CORS_DENY_REQUEST"] == "yes" and self.variables["CORS_ALLOW_ORIGIN"] ~= "*" and not utils.regex_match(ngx.ctx.bw.http_origin, self.variables["CORS_ALLOW_ORIGIN"]) then
self.logger:log(ngx.WARN, "origin " .. ngx.ctx.bw.http_origin .. " is not allowed")
return self:ret(true, "origin " .. ngx.ctx.bw.http_origin .. " is not allowed")
end
Expand Down Expand Up @@ -78,11 +78,8 @@ function cors:access()
return self:ret(true, "service doesn't use CORS")
end
-- Deny as soon as possible if needed
if self.variables["CORS_DENY_REQUEST"] == "yes" and ngx.ctx.bw.http_origin then
if self.variables["CORS_ALLOW_ORIGIN"] ~= "*" and not ngx.ctx.bw.http_origin:match(self.variables["CORS_ALLOW_ORIGIN"]) then
self.logger:log(ngx.WARN, "origin " .. ngx.ctx.bw.http_origin .. " is not allowed")
return self:ret(true, "origin " .. ngx.ctx.bw.http_origin .. " is not allowed, denying access", utils.get_deny_status())
end
if ngx.ctx.bw.http_origin and self.variables["CORS_DENY_REQUEST"] == "yes" and self.variables["CORS_ALLOW_ORIGIN"] ~= "*" and not utils.regex_match(ngx.ctx.bw.http_origin, self.variables["CORS_ALLOW_ORIGIN"]) then
return self:ret(true, "origin " .. ngx.ctx.bw.http_origin .. " is not allowed, denying access", utils.get_deny_status())
end
-- Send CORS policy with a 204 (no content) status
if ngx.ctx.bw.request_method == "OPTIONS" and ngx.ctx.bw.http_origin then
Expand Down
2 changes: 1 addition & 1 deletion src/common/core/cors/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"CORS_ALLOW_ORIGIN": {
"context": "multisite",
"default": "*",
"help": "Allowed origins to make CORS requests (LUA pattern) or *.",
"help": "Allowed origins to make CORS requests : PCRE regex or *.",
"id": "cors-allow-origin",
"label": "Allowed origins",
"regex": "^.*$",
Expand Down
4 changes: 2 additions & 2 deletions src/common/core/greylist/greylist.lua
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ end
function greylist:is_greylisted_uri()
-- Check if URI is in greylist
for i, uri in ipairs(self.lists["URI"]) do
if ngx.ctx.bw.uri:match(uri) then
if utils.regex_match(ngx.ctx.bw.uri, uri) then
return true, "URI " .. uri
end
end
Expand All @@ -243,7 +243,7 @@ end
function greylist:is_greylisted_ua()
-- Check if UA is in greylist
for i, ua in ipairs(self.lists["USER_AGENT"]) do
if ngx.ctx.bw.http_user_agent:match(ua) then
if utils.regex_match(ngx.ctx.bw.http_user_agent, ua) then
return true, "UA " .. ua
end
end
Expand Down
4 changes: 1 addition & 3 deletions src/common/core/greylist/jobs/greylist-download.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,7 @@ def check_line(kind: str, line: bytes) -> Tuple[bool, bytes]:
if asn_rx.match(real_line):
return True, real_line
elif kind == "USER_AGENT":
return True, line.replace(b"\\ ", b" ").replace(b"\\.", b"%.").replace(
b"\\\\", b"\\"
).replace(b"-", b"%-")
return True, b"(?:\\b)" + line + b"(?:\\b)"
elif kind == "URI":
if uri_rx.match(line):
return True, line
Expand Down
4 changes: 2 additions & 2 deletions src/common/core/greylist/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
"GREYLIST_USER_AGENT": {
"context": "multisite",
"default": "",
"help": "List of User-Agent, separated with spaces, to put into the greylist.",
"help": "List of User-Agent (PCRE regex), separated with spaces, to put into the greylist.",
"id": "greylist-user-agent",
"label": "Greylist User-Agent",
"regex": "^.*$",
Expand All @@ -99,7 +99,7 @@
"GREYLIST_URI": {
"context": "multisite",
"default": "",
"help": "List of URI, separated with spaces, to put into the greylist.",
"help": "List of URI (PCRE regex), separated with spaces, to put into the greylist.",
"id": "greylist-uri",
"label": "Greylist URI",
"regex": "^.*$",
Expand Down
4 changes: 2 additions & 2 deletions src/common/core/limit/limit.lua
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ function limit:init()
local i = 0
for srv, vars in pairs(variables) do
for var, value in pairs(vars) do
if var:match("LIMIT_REQ_URL") then
if utils.regex_match(var, "LIMIT_REQ_URL") then
local url = value
local rate = vars[var:gsub("URL", "RATE")]
if data[srv] == nil then
Expand Down Expand Up @@ -106,7 +106,7 @@ function limit:access()
local rate = nil
local uri = nil
for k, v in pairs(self.rules) do
if k ~= "/" and ngx.ctx.bw.uri:match(k) then
if k ~= "/" and utils.regex_match(ngx.ctx.bw.uri, k) then
rate = v
uri = k
break
Expand Down
2 changes: 1 addition & 1 deletion src/common/core/limit/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"LIMIT_REQ_URL": {
"context": "multisite",
"default": "/",
"help": "URL where the limit request will be applied.",
"help": "URL (PCRE regex) where the limit request will be applied or special value / for all requests.",
"id": "limit-req-url",
"label": "Limit request URL",
"regex": "^[\\w\\].~:/^%?#[@!$&'()*+,;=-]+$",
Expand Down
4 changes: 1 addition & 3 deletions src/common/core/whitelist/jobs/whitelist-download.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,7 @@ def check_line(kind: str, line: bytes) -> Tuple[bool, bytes]:
if asn_rx.match(real_line):
return True, real_line
elif kind == "USER_AGENT":
return True, line.replace(b"\\ ", b" ").replace(b"\\.", b"%.").replace(
b"\\\\", b"\\"
).replace(b"-", b"%-")
return True, b"(?:\\b)" + line + b"(?:\\b)"
elif kind == "URI":
if uri_rx.match(line):
return True, line
Expand Down
4 changes: 2 additions & 2 deletions src/common/core/whitelist/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
"WHITELIST_USER_AGENT": {
"context": "multisite",
"default": "",
"help": "List of User-Agent, separated with spaces, to whitelist.",
"help": "List of User-Agent (PCRE regex), separated with spaces, to whitelist.",
"id": "whitelist-user-agent",
"label": "Whitelist User-Agent",
"regex": "^.*$",
Expand All @@ -99,7 +99,7 @@
"WHITELIST_URI": {
"context": "multisite",
"default": "",
"help": "List of URI, separated with spaces, to whitelist.",
"help": "List of URI (PCRE regex), separated with spaces, to whitelist.",
"id": "whitelist-uri",
"label": "Whitelist URI",
"regex": "^( *(/[\\w\\].~:/?#[@!$&'()*+,;=-]*)(?!.*\\2(?!.)) *)*$",
Expand Down
4 changes: 2 additions & 2 deletions src/common/core/whitelist/whitelist.lua
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ end
function whitelist:is_whitelisted_uri()
-- Check if URI is in whitelist
for i, uri in ipairs(self.lists["URI"]) do
if ngx.ctx.bw.uri:match(uri) then
if utils.regex_match(ngx.ctx.bw.uri, uri) then
return true, "URI " .. uri
end
end
Expand All @@ -299,7 +299,7 @@ end
function whitelist:is_whitelisted_ua()
-- Check if UA is in whitelist
for i, ua in ipairs(self.lists["USER_AGENT"]) do
if ngx.ctx.bw.http_user_agent:match(ua) then
if utils.regex_match(ngx.ctx.bw.http_user_agent, ua) then
return true, "UA " .. ua
end
end
Expand Down

0 comments on commit a9be973

Please sign in to comment.