A simple, yet powerful way to secure your Python web applications across multiple frameworks.
In today's web landscape, security is paramount. secure.py is a lightweight Python library designed to effortlessly add security headers to your web applications, protecting them from common vulnerabilities. Whether you're using Django, Flask, FastAPI, or any other popular framework, secure.py
provides a unified API to enhance your application's security posture.
secure.py supports the following Python web frameworks:
Strict-Transport-Security
, X-Frame-Options
, and more.Python 3.10 or higher
This library leverages modern Python features introduced in Python 3.10 and 3.11, such as:
|
): Simplifies type annotations.match
statement): Enhances control flow.cached_property
: Optimize memory usage and performance.Note: If you're using an older version of Python (3.6 to 3.9), please use version 0.3.0 of this library, which maintains compatibility with those versions.
Dependencies
This library has no external dependencies outside of the Python Standard Library.
You can install secure.py using pip, pipenv, or poetry:
pip:
pip install secure
Pipenv:
pipenv install secure
Poetry:
poetry add secure
Once installed, you can quickly integrate secure.py
into your project:
import secure
# Initialize secure headers with default settings
secure_headers = secure.Secure.with_default_headers()
# Apply the headers to your framework response object
secure_headers.set_headers(response)
For frameworks like FastAPI and Starlette that support asynchronous operations, use the async method:
import secure
# Initialize secure headers with default settings
secure_headers = secure.Secure.with_default_headers()
# Apply the headers asynchronously to your framework response object
await secure_headers.set_headers_async(response)
import secure
# Create a Secure instance with default headers
secure_headers = secure.Secure.with_default_headers()
# Apply default secure headers to a response object
secure_headers.set_headers(response)
By default, secure.py
applies the following headers when using with_default_headers()
:
Cache-Control: no-store
Cross-Origin-Opener-Policy: same-origin
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self'; object-src 'none'
Strict-Transport-Security: max-age=31536000
Permissions-Policy: geolocation=(), microphone=(), camera=()
Referrer-Policy: strict-origin-when-cross-origin
Server:
X-Content-Type-Options: nosniff
secure.py
allows you to customize headers such as Content-Security-Policy and Permissions-Policy with ease:
import secure
# Build a custom CSP policy
csp = (
secure.ContentSecurityPolicy()
.default_src("'self'")
.script_src("'self'", "cdn.example.com")
.style_src("'unsafe-inline'")
.img_src("'self'", "images.example.com")
.connect_src("'self'", "api.example.com")
)
# Apply it to secure headers
secure_headers = secure.Secure(csp=csp)
Resulting HTTP headers:
Content-Security-Policy: default-src 'self'; script-src 'self' cdn.example.com; style-src 'unsafe-inline'; img-src 'self' images.example.com; connect-src 'self' api.example.com
import secure
# Build a custom Permissions Policy
permissions = (
secure.PermissionsPolicy()
.geolocation("'self'")
.camera("'none'")
.microphone("'none'")
)
# Apply it to secure headers
secure_headers = secure.Secure(permissions=permissions)
Resulting HTTP headers:
Permissions-Policy: geolocation=('self'), camera=('none'), microphone=('none')
from fastapi import FastAPI
from secure import Secure
app = FastAPI()
secure_headers = Secure.with_default_headers()
@app.middleware("http")
async def add_security_headers(request, call_next):
response = await call_next(request)
await secure_headers.set_headers_async(response)
return response
@app.get("/")
def read_root():
return {"Hello": "World"}
from flask import Flask, Response
from secure import Secure
app = Flask(__name__)
secure_headers = Secure.with_default_headers()
@app.after_request
def add_security_headers(response: Response):
secure_headers.set_headers(response)
return response
@app.route("/")
def home():
return "Hello, world"
if __name__ == "__main__":
app.run()
For more details, including advanced configurations and integration examples, please visit the full documentation.
This library implements security recommendations from trusted sources:
We have included attribution comments in the source code where appropriate.
This project is licensed under the terms of the MIT License.
Contributions are welcome! If you'd like to contribute to secure.py
, please feel free to open an issue or submit a pull request on GitHub.
For a detailed list of changes, please refer to the CHANGELOG.
We would like to thank the contributors of MDN Web Docs and OWASP Secure Headers Project for their invaluable resources and guidelines that help make the web a safer place.