A comprehensive firewall middleware for Flask applications
Project description
Flask-firewall
Flask-firewall is a powerful and easy-to-use firewall middleware for Flask applications, designed to protect against common web threats. It provides a wide range of security rules, including IP filtering, rate limiting, reCAPTCHA verification, XSS prevention, and more. Whether you're securing a small web app or a large API, Flask-firewall makes it simple to add robust security with minimal setup.
Features
- Simple Setup: Add security to your Flask app with just a few lines of code.
- Comprehensive Rules: Protect against XSS, SQL injection, path traversal, bots, and more.
- reCAPTCHA Support: Prevent bot abuse with Google reCAPTCHA, configured once.
- Rate Limiting: IP-based and session-based limits to stop DoS attacks.
- Flexible Configuration: Apply rules globally or to specific routes using decorators.
- Middleware Support: Extend rules with custom logic.
- Structured Logging: JSON logs for integration with tools like ELK or Splunk.
- Bypass Mechanism: Allow trusted clients to skip rules with a secret key.
Installation
Install Flask-firewall using pip:
pip install flask-firewall
Requirements
- Python 3.8 or higher
- Flask 2.0.0 or higher
- requests 2.25.0 or higher (for reCAPTCHA)
- pytz 2021.1 or higher (for time-based rules)
Usage
Basic Usage
Get started with Flask-firewall in minutes. Here's a simple example that blocks specific IPs and limits request rates:
from flask import Flask, jsonify
from flask_firewall import Firewall
app = Flask(__name__)
firewall = Firewall(app)
# Block specific IPs
firewall.block_ips(['192.168.1.100'])
# Limit requests to 100 per minute per IP
firewall.rate_limit(limit=100, period=60)
@app.route('/hello')
def hello():
return jsonify({"message": "Hello, secure world!"})
if __name__ == '__main__':
app.run(debug=True)
This setup blocks requests from 192.168.1.100 and ensures no IP sends more than 100 requests per minute.
Using reCAPTCHA
To protect against bots, add Google reCAPTCHA verification. Set the secret key once when initializing the firewall:
from flask import Flask, jsonify
from flask_firewall import Firewall
app = Flask(__name__)
# Set reCAPTCHA secret key once
firewall = Firewall(app, recaptcha_secret_key='your-recaptcha-secret-key')
# Apply reCAPTCHA, exempting certain routes
firewall.recaptcha(exempt_routes=['/public'])
@app.route('/submit', methods=['POST'])
def submit():
return jsonify({"message": "Form submitted successfully"})
if __name__ == '__main__':
app.run(debug=True)
Frontend Example (for reCAPTCHA):
<form method="POST" action="/submit">
<div class="g-recaptcha" data-sitekey="your_site_key_here"></div>
<button type="submit">Submit</button>
</form>
<script src="https://www.google.com/recaptcha/api.js"></script>
JavaScript (to send reCAPTCHA token):
grecaptcha.ready(function() {
grecaptcha.execute('your_site_key_here', {action: 'submit'}).then(function(token) {
fetch('/submit', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ recaptcha_token: token })
}).then(response => response.json()).then(data => console.log(data));
});
});
Obtain your reCAPTCHA site key and secret key from Google reCAPTCHA.
Protecting Specific Routes
Use the @firewall.protect decorator to apply rules to individual routes:
@app.route('/admin', methods=['GET'])
@firewall.protect(rules=[
firewall.RestrictedPathRule(['/admin'], allowed_ips=['127.0.0.1']),
firewall.HoneypotRule(['honeypot_field'])
])
def admin():
return jsonify({"message": "Admin access granted"})
Available Rules
Flask-firewall offers 27 security rules to protect your application:
| Rule | Description | Example Usage |
|---|---|---|
IPRule |
Allow or block specific IPs or ranges | firewall.allow_ips(['127.0.0.1']) |
RateLimitRule |
Limit requests per IP | firewall.rate_limit(limit=100, period=60) |
SessionRateLimitRule |
Limit requests per session token | firewall.session_rate_limit(limit=50, period=60) |
XSSRule |
Block XSS attempts | firewall.protect_from_xss() |
SQLInjectionRule |
Block SQL injection attempts | firewall.protect_from_sql_injection() |
PathTraversalRule |
Block path traversal attacks | firewall.protect_from_path_traversal() |
CSRFProtectionRule |
Enforce CSRF token validation | firewall.csrf_protection(exempt_routes=['/api']) |
MethodRule |
Restrict HTTP methods | firewall.restrict_methods(['GET', 'POST']) |
ReferrerRule |
Restrict referrers | firewall.restrict_referrers(['example.com']) |
ContentTypeRule |
Restrict content types | firewall.restrict_content_types(['application/json']) |
UserAgentRule |
Allow or block user agents | firewall.allow_user_agent(['Mozilla']) |
RequestSizeRule |
Limit request size | firewall.limit_request_size(max_size=2*1024*1024) |
OriginRule |
Restrict origins | firewall.restrict_origins(['https://example.com']) |
HeaderRule |
Forbid specific headers | firewall.forbid_headers(['X-Debug-Mode']) |
HostRule |
Restrict hosts | firewall.restrict_hosts(['example.com']) |
RequestBodyRule |
Validate JSON request bodies | firewall.validate_json_body(['user_id']) |
TimeBasedRule |
Restrict access by time | firewall.restrict_time(9, 17, 'UTC') |
CustomRegexRule |
Match custom regex patterns | firewall.custom_regex([r'admin.*login']) |
CommandInjectionRule |
Block command injection attempts | firewall.protect_from_command_injection() |
APIKeyRule |
Require valid API keys | firewall.require_api_key(lambda key: key == 'secret') |
SecureConnectionRule |
Enforce HTTPS | firewall.enforce_https() |
RestrictedPathRule |
Restrict paths by IP | firewall.restrict_paths(['/admin'], ['192.168.1.1']) |
ParameterValidationRule |
Validate parameters | firewall.validate_parameters({'user_id': lambda x: x.isdigit()}) |
HeaderValidationRule |
Validate headers | firewall.validate_headers({'Content-Type': lambda x: x == 'application/json'}) |
MethodPathRule |
Restrict methods per path | firewall.restrict_methods_for_paths({'/login': ['POST']}) |
RecaptchaRule |
Require reCAPTCHA verification | firewall.recaptcha(exempt_routes=['/public']) |
ProtocolVersionRule |
Restrict HTTP protocol versions | firewall.restrict_protocol(['HTTP/2.0']) |
HoneypotRule |
Detect bots via honeypot fields | firewall.add_honeypot(['honeypot_field']) |
Example Applications
Below are 8 example applications demonstrating how to use Flask-Firewall in various scenarios. Each example includes a complete Flask app with firewall rules tailored to specific use cases.
1. Basic IP Blocking
Protect a simple web app by blocking specific IP addresses.
from flask import Flask, jsonify
from flask_firewall import Firewall
app = Flask(__name__)
firewall = Firewall(app)
# Block malicious IPs
firewall.block_ips(['192.168.1.100', '10.0.0.50'])
@app.route('/')
def home():
return jsonify({"message": "Welcome to the secure app"})
if __name__ == '__main__':
app.run(debug=True)
Use Case: Ideal for small apps needing to block known malicious IPs without complex setup.
2. Rate-Limited Public API
Secure a public API with rate limiting to prevent abuse.
from flask import Flask, jsonify
from flask_firewall import Firewall
app = Flask(__name__)
firewall = Firewall(app)
# Limit to 50 requests per minute per IP
firewall.rate_limit(limit=50, period=60)
@app.route('/api/data')
def get_data():
return jsonify({"data": "Sample API response"})
if __name__ == '__main__':
app.run(debug=True)
Use Case: Protects APIs from DoS attacks or excessive usage by limiting requests per IP.
3. reCAPTCHA-Protected Form
Prevent bots from submitting forms using reCAPTCHA.
from flask import Flask, jsonify
from flask_firewall import Firewall
app = Flask(__name__)
firewall = Firewall(app, recaptcha_secret_key='your-recaptcha-secret-key')
# Apply reCAPTCHA to all routes except /info
firewall.recaptcha(exempt_routes=['/info'])
@app.route('/submit', methods=['POST'])
def submit():
return jsonify({"message": "Form submitted successfully"})
@app.route('/info')
def info():
return jsonify({"message": "Public info page"})
if __name__ == '__main__':
app.run(debug=True)
Frontend (add to templates/form.html):
<form method="POST" action="/submit">
<div class="g-recaptcha" data-sitekey="your_site_key_here"></div>
<button type="submit">Submit</button>
</form>
<script src="https://www.google.com/recaptcha/api.js"></script>
Use Case: Secures contact forms or login pages against automated bot submissions.
4. Admin Dashboard with Restricted Access
Restrict access to an admin dashboard to specific IPs.
from flask import Flask, jsonify
from flask_firewall import Firewall
app = Flask(__name__)
firewall = Firewall(app)
# Restrict /admin to trusted IPs
firewall.restrict_paths(['/admin'], allowed_ips=['127.0.0.1', '192.168.1.1'])
@app.route('/admin')
def admin():
return jsonify({"message": "Admin dashboard"})
@app.route('/')
def home():
return jsonify({"message": "Public page"})
if __name__ == '__main__':
app.run(debug=True)
Use Case: Ensures sensitive admin routes are only accessible from trusted networks.
5. Secure File Upload
Limit file uploads by content type and size to prevent abuse.
from flask import Flask, request, jsonify
from flask_firewall import Firewall
app = Flask(__name__)
firewall = Firewall(app)
# Restrict to image uploads, max 2MB
firewall.restrict_content_types(['image/jpeg', 'image/png'])
firewall.limit_request_size(max_size=2*1024*1024)
@app.route('/upload', methods=['POST'])
def upload():
file = request.files.get('file')
return jsonify({"message": f"Uploaded {file.filename}"})
if __name__ == '__main__':
app.run(debug=True)
Use Case: Secures file upload endpoints, common in content management systems.
6. Time-Restricted Access
Allow access only during business hours (e.g., 9 AM to 5 PM UTC).
from flask import Flask, jsonify
from flask_firewall import Firewall
app = Flask(__name__)
firewall = Firewall(app)
# Restrict access to 9 AM - 5 PM UTC
firewall.restrict_time(start_hour=9, end_hour=17, timezone='UTC')
@app.route('/business')
def business():
return jsonify({"message": "Business portal"})
if __name__ == '__main__':
app.run(debug=True)
Use Case: Useful for applications that should only be accessible during specific hours.
7. API Key Authentication
Require a valid API key for secure endpoints.
from flask import Flask, jsonify
from flask_firewall import Firewall
app = Flask(__name__)
firewall = Firewall(app)
# Validate API key
firewall.require_api_key(lambda key: key == 'my-secret-key', header='X-API-Key')
@app.route('/secure')
def secure():
return jsonify({"message": "Secure data"})
if __name__ == '__main__':
app.run(debug=True)
Use Case: Protects sensitive API endpoints, such as those handling user data.
8. XSS and SQL Injection Protection
Protect a web app from XSS and SQL injection attacks.
from flask import Flask, jsonify
from flask_firewall import Firewall
app = Flask(__name__)
firewall = Firewall(app)
# Block XSS and SQL injection attempts
firewall.protect_from_xss()
firewall.protect_from_sql_injection()
@app.route('/search')
def search():
query = request.args.get('q', '')
return jsonify({"results": f"Searched for {query}"})
if __name__ == '__main__':
app.run(debug=True)
Use Case: Secures user input forms or search endpoints against malicious payloads.
Advanced Configuration
Middleware Functions
Add custom logic to rules with middleware functions:
def log_request(request):
current_app.logger.info(f"Request from {request.remote_addr}")
firewall.rate_limit(middlewares=(log_request,))
Bypass Key
Allow trusted clients to bypass rules with a secret key:
firewall.set_bypass_key('supersecret')
# Request with header: X-Firewall-Bypass: supersecret
Custom Error Handling
Define a custom error handler for 403 responses:
def custom_error_handler(e):
return jsonify({"error": "Access Denied", "details": str(e)}), 403
firewall.set_error_handler(custom_error_handler)
Contributing
Contributions are welcome! To contribute:
- Fork the repository:
https://github.com/Ishanoshada/flask_firewall - Create a feature branch:
git checkout -b feature/your-feature - Commit your changes:
git commit -m 'Add your feature' - Push to the branch:
git push origin feature/your-feature - Open a pull request
Please include tests and update documentation for new features.
License
This project is licensed under the MIT License. See the LICENSE file for details.
Contact
- Author: Ishan Oshada
- Email: ic31908@gmail.com
- GitHub: Ishanoshada
- Issues: GitHub Issues
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file flask_firewall-0.1.0.tar.gz.
File metadata
- Download URL: flask_firewall-0.1.0.tar.gz
- Upload date:
- Size: 17.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.9.22
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
eeccb2512f30fe665076af1632b4db38c79a89e29719d0ffff536cd528dc924e
|
|
| MD5 |
ad751d728019df5d0a59193b19636f5e
|
|
| BLAKE2b-256 |
968262983cfbbb2f0d1621464edd67604a53ca71b9f56705d5de081a48831afc
|
File details
Details for the file flask_firewall-0.1.0-py3-none-any.whl.
File metadata
- Download URL: flask_firewall-0.1.0-py3-none-any.whl
- Upload date:
- Size: 13.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.9.22
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
601244b7e6f2ef5149ff100589f9beacda44ee5652aac0e2178f5e42c6db1ad4
|
|
| MD5 |
de2eb6aa014f9e683c5d0f9e78d15c05
|
|
| BLAKE2b-256 |
b0bc357cb60bd4055a5792525e41bc0dd0f3e0c2844e2866cbbcc69b44b1074f
|