"""
SSRF (服务端请求伪造) 漏洞知识
"""

from ..base import KnowledgeDocument, KnowledgeCategory


SSRF = KnowledgeDocument(
    id="vuln_ssrf",
    title="Server-Side Request Forgery (SSRF)",
    category=KnowledgeCategory.VULNERABILITY,
    tags=["ssrf", "request", "url", "network", "internal", "cloud"],
    severity="high",
    cwe_ids=["CWE-918"],
    owasp_ids=["A10:2021"],
    content="""
SSRF允许攻击者诱使服务器向内部资源或任意外部地址发起请求。

## 危险模式

### Python
```python
# 危险 - 直接使用用户URL
response = requests.get(user_provided_url)
urllib.request.urlopen(url_from_user)
httpx.get(user_url)

# 危险 - URL拼接
base_url = "http://internal-api/"
requests.get(base_url + user_path)

# 危险 - 图片/文件获取
image_url = request.args.get('url')
response = requests.get(image_url)
```

### Node.js
```javascript
// 危险
fetch(req.body.url);
axios.get(userUrl);
http.get(url, callback);
```

## 攻击目标
1. 内部服务 (localhost, 127.0.0.1, 内网IP)
2. 云元数据服务
   - AWS: http://169.254.169.254/latest/meta-data/
   - GCP: http://metadata.google.internal/
   - Azure: http://169.254.169.254/metadata/
3. 内部API和数据库
4. 文件协议 (file://)

## 绕过技术
```
# IP绕过
http://127.0.0.1 -> http://127.1 -> http://0
http://localhost -> http://[::1]
http://2130706433 (十进制)
http://0x7f000001 (十六进制)

# DNS重绑定
attacker.com -> 解析到内网IP

# URL解析差异
http://evil.com@internal/
http://internal#@evil.com
```

## 检测要点
1. 所有发起HTTP请求的地方
2. URL参数是否来自用户
3. 是否有URL白名单验证
4. 是否限制了协议和端口

## 安全实践
1. URL白名单验证
2. 禁止访问内部IP地址
3. 使用DNS解析验证
4. 限制协议（仅http/https）
5. 禁用重定向或限制重定向

## 修复示例
```python
import ipaddress
from urllib.parse import urlparse

def is_safe_url(url):
    try:
        parsed = urlparse(url)
        
        # 只允许http/https
        if parsed.scheme not in ['http', 'https']:
            return False
        
        # 解析IP
        import socket
        ip = socket.gethostbyname(parsed.hostname)
        ip_obj = ipaddress.ip_address(ip)
        
        # 禁止私有IP
        if ip_obj.is_private or ip_obj.is_loopback:
            return False
        
        # 白名单域名
        if parsed.hostname not in ALLOWED_HOSTS:
            return False
            
        return True
    except:
        return False

# 使用
if is_safe_url(user_url):
    response = requests.get(user_url, allow_redirects=False)
```
""",
)
