drmaxnix/fuckai

By drmaxnix

Updated 29 days ago

Docker Web Application Firewall (WAF) for Protecting Web Apps against AI Scrapers

Image
Security
Machine learning & AI
0

1.9K

drmaxnix/fuckai repository overview

Source Code: git.tjdev.de/DrMaxNix/fuckai

fuckai - A Prototype for the fckai Project

Docker Web Application Firewall (WAF) for Protecting Web Apps against AI Scrapers

Screenshot

How It Works

  1. Your server stack consists of these three components:
    • the reverse proxy, which will terminate SSL connections and forward traffic to the fuckai container
    • the fuckai container, which will either forward traffic to the application container, or present a challenge page
    • the application container
  2. The challenge page will be displayed if the client does not present a valid key cookie
  3. The key is essentially a signed combination of the client's ip address and a time component (either changing daily or weekly)
  4. To obtain this key from the fuckai api, the challenge page contains a few lines of JavaScript that the client needs to execute (and optionally click a button to run it)

Caution

As the fuckai container and your application don't know the client's IP address (they only see the address of the container before them), the first link in the chain (eg. your reverse proxy) must forward the client's IP address to following containers using the `X-Forwarded-For` HTTP header. fuckai expects this header to be set; a missing or wrong `X-Forwarded-For` header value will lead to unexpected behavior!

Caution

If your server is reachable via public IPv6 and your reverse proxy is running inside a docker container, you must also enable IPv6 in your docker network: `enable_ipv6: true`. If you don't do this, IPv6 connections will not use docker's NAT, they will be proxied to IPv4 instead; thus, from the persepective of your reverse proxy, these connections will come from a local address (e.g. `172.18.0.1`). In this case, all clients will be treated as having the same ip address, which basically defeats the purpose of giving different keys to different clients.

Setup Instructions

1. Set up fuckai

Add the fuckai service to your docker-compose.yml, mount your host system's timezone files and point it to your application container:

services:
  fuckai:
    image: drmaxnix/fuckai:1
    restart: unless-stopped
    environment:
      APPLICATION_HOST: "app"
    volumes:
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    ports:
      - 127.0.0.1:80:80
  
  app:
    # ...
2. Configure your reverse proxy

Now point your reverse proxy at port 80 of the fuckai container.

Important

Make sure, you don't point your reverse proxy directly at the application container and check that your application container has no publicly accessible http/https ports (eg. remove `ports` entries from `docker-compose.yml`)

Configuration Options

Following configuration options are available by setting environment variables:

OptionTypeDefaultDescription
DEBUGboolfalseWhether debug information should be visible (not safe for production usage!)
DEBUG_BREAK_CHALLENGEboolfalseWhether the challenge should always fail; useful for keeping the challenge page on screen while tweaking the note and footer content
LOG_ALLboolfalseLog following requests: All
LOG_APIboolfalseLog following requests: Going to the fuckai API
LOG_CHALLENGEboolfalseLog following requests: Intercepted by a challenge page
LOG_VALIDATEDboolfalseLog following requests: Allowed to access the application only because they presented a valid key
BRANDINGbooltrueWhether branding text should be displayed on the challenge page
KEYTYPEstringsecret+ip+dateHow to build the cookie keys (see below for possible values and explanations)
CHALLENGEstringjsWhich kind of challenge to use (see below for possible values and explanations)
APPLICATION_HOST🔸host/ipHostname or ip address of application to forward requests to
APPLICATION_PORTint80Port number of application to forward requests to
COMMENTstringComment text to add to the first and last line of the challenge page's raw html (here it is most likely to show up in an error message if the challenge page is breaking some kind of api; this text could contain a short explanation and ways to contact you for reporting problems)
NOTE_HTMLstringCustom html code to be inserted between the explanation text and the status section (make sure to wrap any text in <span> elements!)
FOOTER_HTMLstringCustom html code to be inserted at the end of the page (make sure to wrap any text in <span> elements!)

Options marked with 🔸 are required

List of Available Key Types

The key that allows the client temporary access to the application is built from multiple components. Generally, it always contains a secret component, which will be regenerated at each container start. All components will then be hashed to basically create a signed form of all non-secret components. Selecting the right components to build the key is crucial in determining when clients will be presented with the challenge page again. Or in other words: they determine how long and for which client a single key is valid. Following component combinations are currently available:

KeytypeKey derivation example (simplified)Description
secretsha1("LBAdA7k9...")All clients share the same key; key becomes invalid only on container restarts
secret+datesha1("LBAdA7k9..." + "2025-09-29")All clients share the same key; key becomes invalid every day
secret+weeksha1("LBAdA7k9..." + "2025-35")All clients share the same key; key becomes invalid every week
secret+ipsha1("LBAdA7k9..." + "203.0.113.124")Every client receives their own key; key becomes invalid only on container restarts
secret+ip+datesha1("LBAdA7k9..." + "203.0.113.124" + "2025-09-29")Every client receives their own key; key becomes invalid every day
secret+ip+weeksha1("LBAdA7k9..." + "203.0.113.124" + "2025-35")Every client receives their own key; key becomes invalid every week

List of Available Challenge Types

To separate bots from living creatures, we ask visitors to do a challenge. Depending on how eagerly you want to do this separation, you can pick from multiple challenges with varying difficulty. Following challenges are currently available:

ChallengeDescription
jsThe client's browser must execute a small JavaScript snippet; does not require any user interaction
buttonThe user must click on a big button on the challenge page; requires easy/short user interaction

Allowlist files

To prevent losing SEO or breaking APIs, certain paths can be added to a whitelist, which will cause these paths to always be allowed, regardless of whether a valid key has been provided or not. For this, there are three files that can be mounted into the container:

  • /allow-str.txt: List of allowed paths (exact match)
  • /allow-beg.txt: List of allowed path prefixes
  • /allow-reg.txt: List of allowed path regex patterns

If you have these files set up and saved in the same directory as your docker-compose.yml, you can simply mount them into the container as follows:

services:
  fuckai:
    # ...
    volumes:
      # ...
      - ./allow-str.txt:/allow-str.txt:ro
      - ./allow-beg.txt:/allow-beg.txt:ro
      - ./allow-reg.txt:/allow-reg.txt:ro
Example allowlist files

allow-str.txt:

# allow robots and sitemap files
/robots.txt
/sitemap.xml

# allow home page for seo
/

# allow the about main page
/about

allow-beg.txt:

# allow all api calls
/api/

# allow all files in the .well-known directory
/.well-known/

# allow all files in the assets directory
/assets/

# allow the about sub-pages
/about/

allow-reg.txt:

# allow user profile pages
^/user/[a-z0-9_-]+$
Allowlist file presets

Attribution / Credits

Tag summary

Content type

Image

Digest

sha256:486831208

Size

9.1 MB

Last updated

29 days ago

docker pull drmaxnix/fuckai