Update anti_ddos_challenge.lua

Added Feature to detect Tor users
Added Feature to block or allow Tor users (Allowing Tor users will still require for them to go through the authentication process the same as everyone else so don't worry)
Added Feature to encrypt Tor headers making them as Dynamic as possible
Added Feature to encrypt Tor cookies making them as Dynamic as possible
Added Tor Javascript Checks

Fixed unwanted collision bug between header x_auth_header_name when encrypted it was not unique so I made it unique to avoid any clashes in the future.
This commit is contained in:
C0nw0nk 2020-02-05 15:55:21 +00:00 committed by GitHub
parent 6087320fd7
commit 3563ed21f0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 142 additions and 3 deletions

View File

@ -201,6 +201,37 @@ local ip_blacklist = {
--"192.168.0.1", --localhost
}
--[[
Allow or block all Tor users
1 = Allow
2 = block
]]
local tor = 1 --Allow Tor Users
--[[
Unique ID to identify each individual Tor user who connects to the website
Using their User-Agent as a static variable to latch onto works well.
ngx.var.http_user_agent --Default
]]
local tor_remote_addr = ngx.var.http_user_agent
--[[
X-Tor-Header to be static or Dynamic setting this as dynamic is the best form of security
1 = Static
2 = Dynamic
]]
local x_tor_header = 2 --Default 2
local x_tor_header_name = "x-tor" --tor header name
local x_tor_header_name_allowed = "true" --tor header value when we want to allow access
local x_tor_header_name_blocked = "blocked" --tor header value when we want to block access
--[[
Tor Cookie values
]]
local cookie_tor = challenge.."_tor" --our tor cookie
local cookie_tor_value_allow = "allow" --the value of the cookie when we allow access
local cookie_tor_value_block = "deny" --the value of the cookie when we block access
--[[
TODO:
Google ReCaptcha
@ -290,7 +321,7 @@ if string.match(string.lower(ngx.var.host), ".onion") then
remote_addr = "tor"
end
if remote_addr == "tor" then
remote_addr = ngx.var.http_user_agent
remote_addr = tor_remote_addr
end
--function to check if ip address is whitelisted to bypass our auth
@ -495,10 +526,66 @@ local user_agent = ngx.var.http_user_agent --user agent of browser
local expected_header_status = 200
local authentication_page_status_output = 503
--Put our vars into storage for use later on
local challenge_original = challenge
local cookie_name_start_date_original = cookie_name_start_date
local cookie_name_end_date_original = cookie_name_end_date
local cookie_name_encrypted_start_and_end_date_original = cookie_name_encrypted_start_and_end_date
--[[
Start Tor detection
]]
if x_tor_header == 2 then --if x-tor-header is dynamic
x_tor_header_name = calculate_signature(tor_remote_addr .. x_tor_header_name .. currentdate):gsub("_","") --make the header unique to the client and for todays date encrypted so every 24 hours this will change and can't be guessed by bots gsub because header bug with underscores so underscore needs to be removed
x_tor_header_name_allowed = calculate_signature(tor_remote_addr .. x_tor_header_name_allowed .. currentdate):gsub("_","") --make the header unique to the client and for todays date encrypted so every 24 hours this will change and can't be guessed by bots gsub because header bug with underscores so underscore needs to be removed
x_tor_header_name_blocked = calculate_signature(tor_remote_addr .. x_tor_header_name_blocked .. currentdate):gsub("_","") --make the header unique to the client and for todays date encrypted so every 24 hours this will change and can't be guessed by bots gsub because header bug with underscores so underscore needs to be removed
end
if encrypt_anti_ddos_cookies == 2 then --if Anti-DDoS Cookies are to be encrypted
cookie_tor = calculate_signature(tor_remote_addr .. cookie_tor .. currentdate) --encrypt our tor cookie name
cookie_tor_value_allow = calculate_signature(tor_remote_addr .. cookie_tor_value_allow .. currentdate) --encrypt our tor cookie value for allow
cookie_tor_value_block = calculate_signature(tor_remote_addr .. cookie_tor_value_block .. currentdate) --encrypt our tor cookie value for block
end
--block tor function to block traffic from tor users
local function blocktor()
local output = ngx.exit(ngx.HTTP_FORBIDDEN) --deny user access
return output
end
--check the connecting client to see if they have our required matching tor cookie name in their request
local tor_cookie_name = "cookie_" .. cookie_tor
local tor_cookie_value = ngx.var[tor_cookie_name] or ""
if tor_cookie_value == cookie_tor_value_allow then --if their cookie value matches the value we expect
if tor == 2 then --perform check if tor users should be allowed or blocked if tor users already browsing your site have been granted access and you change this setting you want them to be blocked now so this makes sure they are denied any further access before their cookie expires
blocktor()
end
remote_addr = tor_remote_addr --set the remote_addr as the tor_remote_addr value
end
if tor_cookie_value == cookie_tor_value_block then --if the provided cookie value matches our block cookie value
blocktor()
end
local cookie_tor_value = "" --create variable to store if tor should be allowed or disallowed
local x_tor_header_name_value = "" --create variable to store our expected header value
if tor == 1 then --if tor users should be allowed
cookie_tor_value = cookie_tor_value_allow --set our value as our expected allow value
x_tor_header_name_value = x_tor_header_name_allowed --set our value as our expected allow value
else --tor users should be blocked
cookie_tor_value = cookie_tor_value_block --set our value as our expected block value
x_tor_header_name_value = x_tor_header_name_blocked --set our value as our expected block value
end
--[[
End Tor detection
]]
local answer = calculate_signature(remote_addr) --create our encrypted unique identification for the user visiting the website.
if x_auth_header == 2 then --if x-auth-header is dynamic
x_auth_header_name = calculate_signature(remote_addr .. currentdate):gsub("_","") --make the header unique to the client and for todays date encrypted so every 24 hours this will change and can't be guessed by bots gsub because header bug with underscores so underscore needs to be removed
x_auth_header_name = calculate_signature(remote_addr .. x_auth_header_name .. currentdate):gsub("_","") --make the header unique to the client and for todays date encrypted so every 24 hours this will change and can't be guessed by bots gsub because header bug with underscores so underscore needs to be removed
end
if encrypt_anti_ddos_cookies == 2 then --if Anti-DDoS Cookies are to be encrypted
@ -536,6 +623,33 @@ local function grant_access()
--if x-auth-answer is correct to the user unique id time stamps etc meaning browser figured it out then set a new cookie that grants access without needed these checks
local req_headers = ngx.req.get_headers() --get all request headers
if req_headers["x-requested-with"] == "XMLHttpRequest" then --if request header matches request type of XMLHttpRequest
if req_headers[x_tor_header_name] == x_tor_header_name_value then --if the header and value are what we expect then the client is legitimate
remote_addr = tor_remote_addr --set as our defined static tor variable to use
challenge = calculate_signature(remote_addr .. challenge_original .. currentdate) --create our encrypted unique identification for the user visiting the website again. (Stops a double page refresh loop)
answer = calculate_signature(remote_addr) --create our answer again under the new remote_addr (Stops a double page refresh loop)
cookie_name_start_date = calculate_signature(remote_addr .. cookie_name_start_date_original .. currentdate) --create our cookie_name_start_date again under the new remote_addr (Stops a double page refresh loop)
cookie_name_end_date = calculate_signature(remote_addr .. cookie_name_end_date_original .. currentdate) --create our cookie_name_end_date again under the new remote_addr (Stops a double page refresh loop)
cookie_name_encrypted_start_and_end_date = calculate_signature(remote_addr .. cookie_name_encrypted_start_and_end_date_original .. currentdate) --create our cookie_name_encrypted_start_and_end_date again under the new remote_addr (Stops a double page refresh loop)
set_cookie1 = challenge.."="..answer.."; path=/; expires=" .. ngx.cookie_time(currenttime+expire_time) .. "; Max-Age=" .. expire_time .. ";" --apply our uid cookie incase javascript setting this cookies time stamp correctly has issues
set_cookie2 = cookie_name_start_date.."="..currenttime.."; path=/; expires=" .. ngx.cookie_time(currenttime+expire_time) .. "; Max-Age=" .. expire_time .. ";" --start date cookie
set_cookie3 = cookie_name_end_date.."="..(currenttime+expire_time).."; path=/; expires=" .. ngx.cookie_time(currenttime+expire_time) .. "; Max-Age=" .. expire_time .. ";" --end date cookie
set_cookie4 = cookie_name_encrypted_start_and_end_date.."="..calculate_signature(remote_addr .. currenttime .. (currenttime+expire_time) ).."; path=/; expires=" .. ngx.cookie_time(currenttime+expire_time) .. "; Max-Age=" .. expire_time .. ";" --start and end date combined to unique id
set_cookie5 = cookie_tor.."="..cookie_tor_value.."; path=/; expires=" .. ngx.cookie_time(currenttime+expire_time) .. "; Max-Age=" .. expire_time .. ";" --create our tor cookie to identify the client as a tor user
set_cookies = {set_cookie1 , set_cookie2 , set_cookie3 , set_cookie4, set_cookie5}
ngx.header["Set-Cookie"] = set_cookies
ngx.header["X-Content-Type-Options"] = "nosniff"
ngx.header["X-Frame-Options"] = "SAMEORIGIN"
ngx.header["X-XSS-Protection"] = "1; mode=block"
ngx.header["Cache-Control"] = "public, max-age=0 no-store, no-cache, must-revalidate, post-check=0, pre-check=0"
ngx.header["Pragma"] = "no-cache"
ngx.header["Expires"] = "0"
ngx.header.content_type = "text/html; charset=" .. default_charset
ngx.status = expected_header_status
ngx.exit(ngx.HTTP_NO_CONTENT)
end
--ngx.log(ngx.ERR, "x-auth-answer result | "..req_headers[x_auth_header_name]) --output x-auth-answer to log
if req_headers[x_auth_header_name] == JavascriptPuzzleVars_answer then --if the answer header provided by the browser Javascript matches what our Javascript puzzle answer should be
set_cookie1 = challenge.."="..cookie_value.."; path=/; expires=" .. ngx.cookie_time(currenttime+expire_time) .. "; Max-Age=" .. expire_time .. ";" --apply our uid cookie incase javascript setting this cookies time stamp correctly has issues
@ -625,6 +739,31 @@ end
local JavascriptPuzzleVariable_name = "_" .. stringrandom(10)
--[[
Begin Tor Browser Checks
Because Tor blocks browser fingerprinting / tracking it actually makes it easy to detect by comparing screen window sizes if they do not match we know it is Tor
]]
local javascript_detect_tor = [[
var sw, sh, ww, wh, v;
sw = screen.width;
sh = screen.height;
ww = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth || 0;
wh = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight || 0;
if ((sw == ww) && (sh == wh)) {
v = true;
if (!(ww % 200) && (wh % 100)) {
v = true;
}
}
//v = true; //test var nulled out used for debugging purpose
if (v == true) {
xhttp.setRequestHeader(']] .. x_tor_header_name .. [[', ']] .. x_tor_header_name_value .. [[');
}
]]
--[[
End Tor Browser Checks
]]
local javascript_REQUEST_headers = [[
xhttp.setRequestHeader(']] .. x_auth_header_name .. [[', ]] .. JavascriptPuzzleVariable_name .. [[); //make the answer what ever the browser figures it out to be
xhttp.setRequestHeader('X-Requested-with', 'XMLHttpRequest');
@ -634,7 +773,7 @@ xhttp.setRequestHeader(']] .. x_auth_header_name .. [[', ]] .. JavascriptPuzzleV
xhttp.setRequestHeader('X-Requested-Type', 'GET');
xhttp.setRequestHeader('X-Requested-Type-Combination', 'GET'); //Encrypted for todays date
xhttp.withCredentials = true;
]]
]] .. javascript_detect_tor
local JavascriptPuzzleVariable = [[
var ]] .. JavascriptPuzzleVariable_name .. [[=]] .. JavascriptPuzzleVars ..[[;