T09 · Insecure Skill Coding Practices
- Location
fetch.py:196- Finding
SSRF Protection Can Be Bypassed Through Redirects and DNS Rebinding
- Content
View full analysis
None: """ URL 访问安全检查: - 仅 http/https - 可选白名单 NEWS_CN_ALLOW_HOSTS - 默认拦截本机/私网/链路本地等地址(NEWS_CN_BLOCK_PRIVATE=0 可关闭) """ p = urlparse(url) if p.scheme not in ("http", "https"): raise ValueError("only http(s) URLs allowed") host = (p.hostname or "").strip().lower() if not host: raise ValueError("url host is empty") if not _host_allowed_by_env(host): raise ValueError("host not allowed by NEWS_CN_ALLOW_HOSTS: %s" % host) if not _env_on("NEWS_CN_BLOCK_PRIVATE", "1"): return if host == "localhost" or host.endswith(".localhost"): raise ValueError("blocked private/local host: %s" % host) ips = _resolve_host_ips(host) if not ips: # 解析失败时保持安全默认,避免未知主机绕过 raise ValueError("dns resolve failed for host: %s" % host) bad = [ip for ip in ips if _ip_is_privateish(ip)] if bad: raise ValueError("blocked private/local address for host %s: %s" % (host, ",".join(bad))) def _fetch_url(url: str, timeout: float, max_bytes: int = 3_500_000) -> bytes: _validate_remote_url(url) ua = os.environ.get( "NEWS_CN_UA", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36", ) req = urllib.request.Request( url, headers={ "User-Agent": ua, "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8", # 避免 urllib 不解压 gzip 导致乱解析 "Accept-Encoding": "identity", }, ) ctx = ssl.create_default_context() with urllib.request.urlopen(req, timeout=timeout, context=ctx) as resp: ...[truncated 2609 chars]- Remediation
View remediation
