feat: added captcha serving service to haproxy

This commit is contained in:
Eugene Prodan
2021-06-07 23:44:39 +03:00
parent 1dff57f048
commit 0fde9b873b
7 changed files with 1656 additions and 3 deletions

19
README.MD Normal file
View File

@ -0,0 +1,19 @@
## HaProxy DDoS protection system PoC
If there is an unusual HTTP requests flow to a specific domain, the system detects it and triggers DDoS protection mode.
Each new client will be first forced to complete hCaptcha, before proceeding to the website.
##### How to test
- export hcaptcha sitekey and secret:
```bash
export HCAPTCHA_SITEKEY=xxxXXxxx
export HCAPTCHA_SECRET=xxxXXxxx
```
- run docker compose:
```bash
docker compose up
```
- visit *http://127.0.0.1/captcha*

View File

@ -9,6 +9,9 @@ services:
volumes:
- ./haproxy/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg
- ./scripts/:/usr/local/etc/haproxy/scripts/
environment:
- HCAPTCHA_SECRET=${HCAPTCHA_SECRET}
- HCAPTCHA_SITEKEY=${HCAPTCHA_SITEKEY}
nginx:
image: "nginx:latest"

View File

@ -95,8 +95,26 @@ STOPSIGNAL SIGUSR1
ADD haproxy/docker-entrypoint.sh /usr/local/bin/
RUN ln -s usr/local/bin/docker-entrypoint.sh / # backwards compat
RUN apt-get update && apt-get install luarocks -y
RUN luarocks install luasocket
# This is terrible mess but we need it for simple testing purposes of our POC
RUN apt-get update && apt-get install libssl-dev make nano wget gcc libreadline-dev unzip git -y
RUN wget http://www.lua.org/ftp/lua-5.3.5.tar.gz &&\
tar -zxf lua-5.3.5.tar.gz &&\
cd lua-5.3.5 &&\
make linux test &&\
make install
RUN wget "https://luarocks.org/releases/luarocks-3.3.1.tar.gz" &&\
tar zxpf luarocks-3.3.1.tar.gz &&\
cd luarocks-3.3.1 &&\
./configure --with-lua-include=/usr/local/include --lua-version=5.3 --lua-suffix=5.3 &&\
make &&\
make install
RUN /usr/local/bin/luarocks install luasocket &&\
/usr/local/bin/luarocks install luasec &&\
/usr/local/bin/luarocks install net-url
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
# no USER for backwards compatibility (to try to avoid breaking existing users)

View File

@ -15,6 +15,7 @@ frontend http-in
default_backend servers
# http-request lua.test-payload
http-request use-service lua.hello-world if { path /hello_world }
http-request use-service lua.hcaptcha-view if { path /captcha }
backend servers
server server1 nginx:80 maxconn 32

1559
scripts/JSON.lua Normal file

File diff suppressed because it is too large Load Diff

51
scripts/hcaptcha.lua Normal file
View File

@ -0,0 +1,51 @@
hcaptcha = {}
local url = require("net.url")
local https = require("ssl.https")
local json = require("json")
function hcaptcha.view(applet)
local hcaptcha_secret = os.getenv("HCAPTCHA_SECRET")
local hcaptcha_sitekey = os.getenv("HCAPTCHA_SITEKEY")
local response
if applet.method == "GET" then
response =
[[
<form method="POST">
<div class="h-captcha" data-sitekey="%s"></div>
<script src="https://hcaptcha.com/1/api.js" async defer></script>
<input type="submit" value="Submit">
</form>
]]
response = string.format(response, hcaptcha_sitekey)
elseif applet.method == "POST" then
local parsed_body = url.parseQuery(applet.receive(applet))
if parsed_body["h-captcha-response"] then
local url =
string.format(
"https://hcaptcha.com/siteverify?secret=%s&response=%s",
hcaptcha_secret,
parsed_body["h-captcha-response"]
)
local body, code, headers, status = https.request(url)
local api_response = json:decode(body)
if api_response.success == true then
print("HCAPTCHA SUCCESSFULLY PASSED")
print("... success captcha flow goes here ...")
else
print("HCAPTCHA FAILED", body)
end
end
response = "Thank you for submitting"
end
applet:set_status(200)
applet:add_header("content-type", "text/html")
applet:add_header("content-length", string.len(response))
applet:start_response()
applet:send(response)
end

View File

@ -1,5 +1,7 @@
package.path = package.path .. "./?.lua;/usr/local/etc/haproxy/scripts/?.lua"
require("guard")
require("hcaptcha")
core.register_service("hello-world", "http", guard.hello_world);
core.register_service("hello-world", "http", guard.hello_world)
core.register_service("hcaptcha-view", "http", hcaptcha.view)