Spaces:
Sleeping
Sleeping
Claude
Claude Sonnet 5
Add rate limiting, tests, better extraction, and HF auto-deploy
ebab0e2 unverified Download app/security.py from Almaatla/web-scraper: direct link, hf CLI and curl.
- Browser
- Download file 1.78 kB
-
https://huggingface.co/spaces/Almaatla/web-scraper/resolve/main/app/security.py
- Command line
-
hf download hf://spaces/Almaatla/web-scraper/app/security.py
-
curl -L -o security.py https://huggingface.co/spaces/Almaatla/web-scraper/resolve/main/app/security.py
1.78 kB
| import ipaddress | |
| import socket | |
| from urllib.parse import urlparse | |
| from app.errors import ScrapeError | |
| # Hostnames worth blocking explicitly because they don't resolve to a | |
| # "private" IP range but still expose sensitive data (cloud metadata APIs). | |
| BLOCKED_HOSTNAMES = {"metadata.google.internal"} | |
| def assert_url_is_safe(url: str, *, resolver=socket.getaddrinfo) -> None: | |
| """Best-effort SSRF guard. | |
| Rejects non-http(s) schemes and hostnames that resolve to | |
| private/loopback/link-local/reserved addresses. This narrows the attack | |
| surface but is not a complete defense against DNS rebinding, since the | |
| browser performs its own DNS resolution when it actually fetches the | |
| page (after this check has passed). | |
| `resolver` matches the signature of socket.getaddrinfo(host, port) and | |
| is injectable so tests don't depend on real DNS. | |
| """ | |
| parsed = urlparse(url) | |
| if parsed.scheme not in ("http", "https"): | |
| raise ScrapeError(400, "Only http and https URLs are supported.") | |
| hostname = parsed.hostname | |
| if not hostname: | |
| raise ScrapeError(400, "URL is missing a hostname.") | |
| if hostname.lower() in BLOCKED_HOSTNAMES: | |
| raise ScrapeError(400, "This host is not allowed.") | |
| try: | |
| addr_infos = resolver(hostname, None) | |
| except OSError: | |
| raise ScrapeError(400, "Could not resolve host.") | |
| for _family, _type, _proto, _canonname, sockaddr in addr_infos: | |
| ip = ipaddress.ip_address(sockaddr[0]) | |
| if ( | |
| ip.is_private | |
| or ip.is_loopback | |
| or ip.is_link_local | |
| or ip.is_multicast | |
| or ip.is_reserved | |
| or ip.is_unspecified | |
| ): | |
| raise ScrapeError(400, "This host resolves to a disallowed address.") | |