Skip to content

tn3w/flask-Humanify

flask-Humanify

A strong bot protection system for Flask with many features: rate limiting, special rules for users, web crawler detection, and automatic bot detection.

Github PyPI Libraries.io


from flask import Flask from flask_humanify import Humanify app = Flask(__name__) humanify = Humanify(app, challenge_type="one_click", image_dataset="ai_dogs") # Register the middleware to deny access to bots humanify.register_middleware(app, action="challenge") @app.route("/") def index(): """  A route that is protected against bots and DDoS attacks.  """ return "Hello, Human!" if __name__ == "__main__": app.run()

Advanced Protection Rules

You can customize bot protection with advanced filtering rules:

# Protect specific endpoints with regex patterns humanify.register_middleware( app, action="challenge", endpoint_patterns=["api.*", "admin.*"] # Protect all API and admin endpoints ) # Protect specific URL paths humanify.register_middleware( app, action="deny_access", url_patterns=["/sensitive/*", "/admin/*"] # Deny bot access to sensitive areas ) # Exclude certain patterns from protection humanify.register_middleware( app, endpoint_patterns=["api.*"], exclude_patterns=["api.public.*"] # Don't protect public API endpoints ) # Filter by request parameters humanify.register_middleware( app, request_filters={ "method": ["POST", "PUT", "DELETE"], # Only protect write operations "args.admin": "true", # Only when admin=true query parameter exists "headers.content-type": "regex:application/json.*" # Match content type with regex } )

Route-Level Protection with Decorators

Flask-Humanify provides powerful decorators for fine-grained bot protection on specific routes:

@require_human(action="challenge")

Protects a route by challenging suspected bots with a captcha.

from flask_humanify import require_human @app.route("/protected") @require_human() def protected(): return "Only humans can access this" @app.route("/strict") @require_human(action="deny_access") def strict(): return "Bots are blocked without a challenge"

Parameters:

  • action (str): Action to take when a bot is detected
    • "challenge" (default): Show captcha challenge
    • "deny_access": Block access immediately

@always_challenge

Forces all visitors (including humans) to solve a captcha before accessing the route.

from flask_humanify import always_challenge @app.route("/sensitive") @always_challenge def sensitive(): return "Everyone must solve a captcha"

@block_bots

Immediately blocks all detected bots without showing a captcha challenge.

from flask_humanify import block_bots @app.route("/no-bots") @block_bots def no_bots(): return "Bots cannot access this route"

@exempt_from_protection

Exempts a route from all Humanify protection, including middleware rules.

from flask_humanify import exempt_from_protection @app.route("/public-api") @exempt_from_protection def public_api(): return {"data": "No bot protection on this endpoint"}

Decorator Priority

When both middleware and decorators are used:

  1. @exempt_from_protection - Highest priority, bypasses all protection
  2. Route-specific decorators - Override middleware settings for that route
  3. Middleware rules - Apply to routes without decorators

Usage

Installation

Install the package with pip:

pip install flask-humanify --upgrade

Optional: Enhanced Security with re2

For better performance and protection against ReDoS (Regular Expression Denial of Service) attacks, install the google-re2 library:

pip install google-re2

Flask-Humanify will automatically use re2 if available, providing:

  • Guaranteed linear-time regex execution (no catastrophic backtracking)
  • Better performance with complex patterns
  • Enhanced security when using custom endpoint_patterns, url_patterns, or request_filters

The library works without re2, but installing it is recommended for production environments.

Basic Setup

from flask import Flask from flask_humanify import Humanify app = Flask(__name__) humanify = Humanify(app)

Configuration Options

Humanify can be configured with various options to customize bot detection and challenge behavior:

humanify = Humanify( app, challenge_type="one_click", # Challenge type: "grid" or "one_click" image_dataset="ai_dogs", # Image dataset: "ai_dogs", "animals", "characters", "keys" audio_dataset=None, # Enable audio challenges: "characters" or None retrys=3, # Maximum failed attempts before blocking hardness=1, # Challenge difficulty: 1 (easy) to 5 (hard) behind_proxy=False, # Set True if behind a proxy/load balancer use_client_id=False # Use secure client IDs instead of IP addresses )

Configuration Parameters:

  • challenge_type: Type of visual challenge

    • "one_click": Select one matching image from a grid (easier, faster)
    • "grid": Select multiple matching images from a 3x3 grid (harder)
  • image_dataset: Dataset for image challenges

    • "ai_dogs": AI-generated dog images
    • "animals": Various animal images
    • "characters": Character/letter recognition
    • "keys": Key/lock matching
  • audio_dataset: Enable audio accessibility challenges

    • None: Disabled (default)
    • "characters": Audio character recognition in multiple languages
  • retrys: Number of failed attempts before temporary block (default: 3)

  • hardness: Challenge difficulty level (1-5)

    • 1: Easy - minimal distortion
    • 3: Medium - moderate distortion
    • 5: Hard - maximum distortion
  • behind_proxy: Enable when behind reverse proxy/load balancer

    • Automatically configures ProxyFix for correct IP detection
  • use_client_id: Use secure client IDs instead of IP addresses

    • Better for privacy and shared IP scenarios
    • Stored in secure HTTP-only cookies

Additional Features

Rate Limiting

Flask-Humanify includes a powerful rate limiting feature to protect your application from excessive requests:

from flask import Flask from flask_humanify import Humanify, RateLimiter app = Flask(__name__) humanify = Humanify(app) # Initialize with default limits (10 requests per 10 seconds) rate_limiter = RateLimiter(app) # Or use human-readable limit strings rate_limiter = RateLimiter(app, default_limit="100/day") # Configure client tracking (defaults to IP-based) rate_limiter = RateLimiter( app, default_limit="10/minute", use_client_id=True, # Use secure client IDs instead of IPs behind_proxy=True # Enable if behind a proxy/load balancer )

Route-Specific Rate Limits

You can set different rate limits for specific routes or patterns:

# Using decorator syntax @app.route("/api/data") @rate_limiter.limit("5/minute") # Limit specific route def get_data(): return "data" # Using pattern matching rate_limiter.set_route_limit("/api/*", "100/hour") # All API routes rate_limiter.set_route_limit("/admin/<id>", "5/minute") # Admin routes # Exempt routes from rate limiting @app.route("/health") @rate_limiter.exempt def health_check(): return "OK"

Advanced Usage

The rate limiter provides methods for managing and monitoring rate limits:

# Reset rate limits for a client rate_limiter.reset_client("client_id") # Reset all routes rate_limiter.reset_client("client_id", "/api/data:GET") # Reset specific route # Get client statistics stats = rate_limiter.get_client_stats("client_id") """ Returns: {  "route:method": {  "current_requests": 5,  "next_reset": 1629123456.78  } } """ # Check rate limits programmatically if rate_limiter.is_rate_limited(): return "Too many requests!"

Features:

  • Flexible rate limit formats: "10/second", "5 per minute", "100/day"
  • Route-specific rate limits using decorators or patterns
  • Client tracking via IPs or secure client IDs
  • Proxy support with X-Forwarded-For headers
  • Route exemptions for health checks and critical endpoints
  • Built-in rate limit monitoring and management
  • Automatic rate limit page with return URL

CAPTCHA Integration

Flask-Humanify includes built-in support for multiple CAPTCHA providers to add an extra layer of protection:

from flask import Flask from flask_humanify import CaptchaEmbed app = Flask(__name__) # Initialize CAPTCHA with automatic theme detection and language captcha = CaptchaEmbed( app, theme="auto", # Options: "light", "dark", "auto" language="auto", # Use specific language code like "en" if needed recaptcha_site_key="your_site_key", # For Google reCAPTCHA recaptcha_secret="your_secret_key", hcaptcha_site_key="your_site_key", # For hCaptcha hcaptcha_secret="your_secret_key", turnstile_site_key="your_site_key", # For Cloudflare Turnstile turnstile_secret="your_secret_key", friendly_site_key="your_site_key", # For Friendly Captcha friendly_secret="your_secret_key", altcha_secret="your_secret_key" # For Altcha (a random generated secret) ) @app.route("/protected", methods=["GET", "POST"]) def protected(): if request.method == "POST": # Validate the CAPTCHA response if captcha.is_recaptcha_valid(): # Or use is_hcaptcha_valid(), is_turnstile_valid(), etc. return "Success!" return render_template("form.html")

In your templates, you can easily embed any supported CAPTCHA:

<!-- Templates automatically get access to CAPTCHA embeds --> <form method="POST"> {{ recaptcha|safe }} <!-- For Google reCAPTCHA --> {{ hcaptcha|safe }} <!-- For hCaptcha --> {{ turnstile|safe }} <!-- For Cloudflare Turnstile --> {{ friendly|safe }} <!-- For Friendly Captcha --> {{ altcha|safe }} <!-- For Altcha (with default hardness) --> {{ altcha1|safe }} <!-- For Altcha (with hardness level 1-5) --> <button type="submit">Submit</button> </form>

The CAPTCHA integration features:

  • Automatic dark/light theme detection
  • Multiple CAPTCHA provider support
  • Customizable difficulty levels for Altcha
  • Easy validation methods
  • Automatic template context integration

Error Handling

Flask-Humanify provides a clean error handling system:

from flask import Flask from flask_humanify import Humanify, ErrorHandler app = Flask(__name__) humanify = Humanify(app) # Handle all standard HTTP errors error_handler = ErrorHandler(app) # Use custom template with placeholders: EXCEPTION_TITLE, EXCEPTION_CODE, EXCEPTION_MESSAGE error_handler = ErrorHandler(app, template_path="templates/error.html") # Or handle only specific error codes error_handler = ErrorHandler(app, errors=[404, 429, 500]) # Or handle only specific error codes with a custom template error_handler = ErrorHandler(app, errors={404: {"template": "404.html"}})

The error handler:

  • Renders user-friendly error pages
  • Uses the custom exception.html template
  • Provides appropriate error messages and descriptions
  • Includes HTTP status codes and titles

Bot Detection Features

Flask-Humanify automatically detects various types of suspicious traffic:

  • VPN Detection: Identifies traffic from major VPN providers (NordVPN, ProtonVPN, ExpressVPN, etc.)
  • Proxy Detection: Detects proxy servers and anonymizers
  • Datacenter IPs: Flags requests from datacenter IP ranges
  • Tor Exit Nodes: Identifies Tor network exit points
  • Web Crawlers: Recognizes legitimate and malicious crawlers via user-agent analysis
  • Forum Spammers: Blocks known spam sources from StopForumSpam database
  • Firehol Blocklists: Uses Firehol Level 1 blocklist for known malicious IPs

All detection happens automatically with no additional configuration required.

Complete Example

Here's a complete example combining all features:

from flask import Flask from flask_humanify import ( Humanify, RateLimiter, ErrorHandler, require_human, always_challenge, block_bots, exempt_from_protection, ) app = Flask(__name__) # Setup core protection with custom configuration humanify = Humanify( app, challenge_type="one_click", image_dataset="animals", audio_dataset="characters", # Enable audio accessibility retrys=3, hardness=2, behind_proxy=True, use_client_id=True ) # Protect all API routes with middleware humanify.register_middleware( action="challenge", url_patterns="/api/*", exclude_patterns="/api/public/*" ) # Add rate limiting rate_limiter = RateLimiter(app, default_limit="100/hour") rate_limiter.set_route_limit("/api/data", "10/minute") # Add error handling error_handler = ErrorHandler(app) @app.route("/") def index(): return "Hello, Human!" @app.route("/api/public/status") @exempt_from_protection def public_status(): return {"status": "ok"} @app.route("/login") @always_challenge def login(): return "Login page - everyone must solve captcha" @app.route("/admin") @block_bots def admin(): return "Admin area - bots blocked immediately" @app.route("/protected") @require_human(action="challenge") def protected(): return "Protected content" if __name__ == "__main__": app.run(debug=True)

Security Best Practices

  • Use HTTPS: Always enable HTTPS in production for secure cookie transmission
  • Behind Proxy: Set behind_proxy=True when using reverse proxies or load balancers
  • Client IDs: Consider use_client_id=True for better privacy and shared IP handling
  • Rate Limiting: Combine bot protection with rate limiting for comprehensive defense
  • Retry Limits: Adjust retrys based on your security requirements (lower = stricter)
  • Challenge Difficulty: Balance hardness between security and user experience
  • Pattern Matching: Use specific patterns in middleware to protect only necessary routes

License

This project is licensed under the MIT License - see the LICENSE file for details.

About

A strong bot protection system for Flask with many features: rate limiting, special rules for users, web crawler detection, and automatic bot detection.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Sponsor this project

Contributors