safehttpx
safehttpx is a small Python library designed to protect applications from Server Side Request Forgery (SSRF) attacks. It provides an asynchronous `safehttpx.get()` method, which wraps `httpx.AsyncClient.get()` while performing DNS validation using Google DNS and implementing mitigation for DNS rebinding attacks. The current version is 0.1.7, and releases are irregular, driven primarily by security updates and the needs of its primary consumer, Gradio.
Warnings
- gotcha Setting `_transport=False` in `safehttpx.get()` explicitly bypasses all SSRF protections, effectively making the call equivalent to a raw `httpx.AsyncClient.get()`. This should only be used if you fully understand and accept the security implications.
- gotcha `safehttpx.get()` is an asynchronous function. It must be `await`-ed within an `async` function. In a script, you'll need to use `asyncio.run()` to execute the async call.
- gotcha safehttpx's DNS validation relies on Google DNS by default. While generally robust, highly restrictive network environments or specific corporate policies might require custom DNS resolvers. This could lead to legitimate external domains being blocked if Google DNS is unreachable or if local DNS records differ.
- gotcha safehttpx primarily focuses on securing `GET` requests. While it wraps `httpx`, users who directly instantiate `httpx.AsyncClient` or use other HTTP methods (like `POST`, `PUT`) without explicit safehttpx wrappers might inadvertently bypass the SSRF protections for those requests. The `safehttpx` module currently only exposes a `get` method.
- breaking As `safehttpx` is a wrapper around `httpx`, it is implicitly affected by breaking changes in `httpx` (e.g., changes in redirect handling or SSL configuration). While `safehttpx` may pin `httpx` versions, custom environment setups could lead to mismatches.
Install
-
pip install safehttpx
Imports
- get
import safehttpx as sh await sh.get(...)
Quickstart
import asyncio
import safehttpx as sh
async def fetch_safe_url():
try:
response = await sh.get("https://huggingface.co")
response.raise_for_status() # Raise an exception for HTTP errors
print(f"Success: {response.status_code} - {response.url}")
# Example of blocked internal IP
await sh.get("http://127.0.0.1")
except ValueError as e:
print(f"Validation Error: {e}")
except Exception as e:
print(f"An unexpected error occurred: {e}")
if __name__ == "__main__":
asyncio.run(fetch_safe_url())