Hotdry.
ai-security

PostHog安全漏洞链分析:从SSRF到RCE的多层防御架构设计

深入分析PostHog安全事件中的SSRF、ClickHouse SQL注入与默认Postgres凭据导致的RCE攻击链,设计可落地的多层防御架构与自动化检测机制。

2025 年初,安全研究员 Mehmet Ince 在对开源产品分析平台 PostHog 进行安全评估时,发现了一个复杂的安全漏洞链。这个攻击链从看似无害的 SSRF 漏洞开始,通过 ClickHouse 的 SQL 注入漏洞,最终利用默认 PostgreSQL 凭据实现了远程代码执行(RCE)。本文将从技术角度深入分析这一漏洞链,并设计一套可落地的多层防御架构。

漏洞链全景:三层攻击路径

第一层:SSRF 漏洞的发现与利用

PostHog 作为一款支持数千个外部集成的产品分析平台,其核心功能之一是通过 webhook 与外部系统通信。安全研究员在代码审计中发现,虽然test_slack_webhook端点进行了 SSRF 验证,但保存 webhook 配置的端点却没有相同的安全检查。

技术细节

  • CVE-2024-9710: Rust Webhook Handler SSRF 信息泄露漏洞
  • CVE-2025-1522: database_schema SSRF 信息泄露漏洞
  • CVE-2025-1521: slack_incoming_webhook SSRF 信息泄露漏洞

攻击者可以通过直接向项目 API 发送PATCH请求,绕过前端验证,将 webhook URL 设置为localhost或其他内部地址。Rust webhook worker 在处理作业时,不会重新验证这些 URL,直接发起服务器端请求,形成了 SSRF 原语。

第二层:ClickHouse SQL 注入漏洞

PostHog 的架构明确将 ClickHouse 作为主要分析后端。默认情况下,ClickHouse 在 TCP 端口 8123 上暴露 HTTP API,且自托管部署中通常不需要认证。

关键发现:ClickHouse 的postgresql()表函数存在 SQL 注入漏洞。该函数允许 ClickHouse 从远程 PostgreSQL 数据库读取或写入数据,但在处理用户输入时使用了错误的转义机制。

-- 攻击者控制的输入
SELECT * FROM postgresql('db:5432','posthog','posthog_table\'','posthog','posthog')

ClickHouse 尝试使用反斜杠转义单引号,但在 PostgreSQL 中,正确的转义方式是使用两个单引号。这个转义错误导致了 SQL 注入漏洞。

第三层:RCE 链的形成

攻击者通过 SSRF 访问 ClickHouse HTTP API,利用 SQL 注入漏洞执行任意 PostgreSQL 查询。通过COPY FROM PROGRAM功能,可以在 PostgreSQL 服务器上执行操作系统命令,实现 RCE。

完整攻击链

  1. 绕过 webhook URL 验证,保存指向内部 ClickHouse 的 URL
  2. 触发 webhook,Rust worker 发起 SSRF 请求到 ClickHouse HTTP API
  3. 利用 ClickHouse 的 postgresql 表函数 SQL 注入漏洞
  4. 通过COPY FROM PROGRAM执行系统命令
  5. 利用默认 PostgreSQL 凭据获取 shell 访问权限

技术深度分析:漏洞成因与绕过机制

SSRF 验证的 TOCTOU 问题

PostHog 的 SSRF 验证存在时间差攻击(TOCTOU)风险。raise_if_user_provided_url_unsafe函数在验证时检查 URL 是否安全,但在实际请求时可能已经发生变化。攻击者可以通过快速修改 DNS 记录或使用 URL 重定向绕过验证。

ClickHouse 的转义逻辑缺陷

ClickHouse 在处理 PostgreSQL 表函数参数时,错误地使用了反斜杠转义。在 PostgreSQL 中,字符串常量中的单引号应该通过两个连续的单引号转义,而不是反斜杠。

-- ClickHouse的错误转义
'posthog_table\''

-- PostgreSQL期望的转义
'posthog_table'''

这个转义错误使得攻击者可以闭合原始查询,注入自己的 SQL 语句。

默认凭据的风险放大

PostHog 在自托管部署中使用默认的 PostgreSQL 凭据(用户名和密码均为 "posthog")。虽然这简化了安装过程,但在安全漏洞存在时显著放大了风险。攻击者一旦获得 SQL 注入能力,就可以直接使用这些默认凭据访问数据库。

多层防御架构设计

第一层:输入验证与边界控制

实施要点

  1. 统一验证层:所有接受 URL 输入的端点必须使用相同的验证逻辑,避免测试端点与保存端点验证不一致
  2. SSRF 防护清单
    • 禁止访问 RFC 1918 私有地址空间(10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)
    • 禁止访问回环地址(127.0.0.0/8, ::1)
    • 禁止访问链路本地地址(169.254.0.0/16)
    • 实施 DNS 重绑定防护
  3. TOCTOU 防护:在请求发起时重新验证 URL,避免时间差攻击

代码实现示例

def validate_url_safety(url):
    """统一的URL安全验证函数"""
    parsed = urlparse(url)
    
    # 检查IP地址黑名单
    if parsed.hostname in INTERNAL_IP_BLACKLIST:
        raise ValidationError("Internal addresses are not allowed")
    
    # DNS解析检查
    try:
        resolved_ips = socket.gethostbyname_ex(parsed.hostname)[2]
        for ip in resolved_ips:
            if is_internal_ip(ip):
                raise ValidationError("DNS resolves to internal address")
    except socket.gaierror:
        raise ValidationError("Invalid hostname")
    
    return True

第二层:ClickHouse 安全配置

安全参数配置

  1. HTTP API 访问控制

    # clickhouse-config.xml
    <http_port>8123</http_port>
    <http_server_default_response></http_server_default_response>
    
    <!-- 启用认证 -->
    <users>
      <default>
        <password>strong_password_here</password>
        <access_management>1</access_management>
        <networks>
          <ip>::/0</ip>
        </networks>
      </default>
    </users>
    
    <!-- 限制表函数使用 -->
    <allow_experimental_table_functions>0</allow_experimental_table_functions>
    
  2. 网络隔离策略

    • ClickHouse HTTP API 仅允许来自应用服务器的访问
    • 使用网络策略或防火墙规则限制 8123 端口的访问
    • 考虑使用 Unix 域套接字替代 TCP 端口
  3. 查询审计与监控

    -- 启用查询日志
    SET log_queries = 1;
    
    -- 监控异常查询模式
    CREATE MATERIALIZED VIEW suspicious_queries
    ENGINE = MergeTree()
    ORDER BY (event_time)
    AS SELECT 
        query,
        user,
        client_hostname,
        event_time
    FROM system.query_log
    WHERE query LIKE '%postgresql(%' 
       OR query LIKE '%FROM PROGRAM%'
       OR query LIKE '%COPY %'
    

第三层:PostgreSQL 安全加固

安全配置清单

  1. 修改默认凭据:安装后立即更改默认用户名和密码

  2. 最小权限原则

    -- 创建专用用户,仅授予必要权限
    CREATE USER posthog_app WITH PASSWORD 'strong_password';
    GRANT CONNECT ON DATABASE posthog TO posthog_app;
    GRANT SELECT, INSERT, UPDATE ON ALL TABLES IN SCHEMA public TO posthog_app;
    REVOKE EXECUTE ON FUNCTION pg_catalog.pg_ls_dir FROM posthog_app;
    REVOKE EXECUTE ON FUNCTION pg_catalog.pg_read_file FROM posthog_app;
    
  3. 禁用危险功能

    -- 限制COPY FROM PROGRAM使用
    ALTER ROLE posthog_app NOSUPERUSER;
    
    -- 或通过扩展限制
    CREATE EXTENSION pgaudit;
    CREATE POLICY block_program_copy ON command
    USING (command_tag != 'COPY');
    
  4. 连接限制

    -- pg_hba.conf配置
    # 仅允许应用服务器访问
    host    posthog    posthog_app    10.0.1.0/24    md5
    
    # 拒绝所有其他连接
    host    all        all            0.0.0.0/0      reject
    

第四层:运行时监控与检测

自动化检测机制

  1. SSRF 攻击检测

    class SSRFDetector:
        def __init__(self):
            self.suspicious_patterns = [
                r'localhost',
                r'127\.0\.0\.1',
                r'192\.168\.',
                r'10\.',
                r'172\.(1[6-9]|2[0-9]|3[0-1])\.',
                r'metadata\.google\.internal',
                r'169\.254\.'
            ]
        
        def detect(self, url, response):
            """检测SSRF攻击尝试"""
            for pattern in self.suspicious_patterns:
                if re.search(pattern, url) or re.search(pattern, response.text):
                    return True
            return False
    
  2. SQL 注入检测

    • 监控包含异常转义字符的查询
    • 检测COPY FROM PROGRAM等危险操作
    • 实施查询频率限制
  3. RCE 尝试检测

    # 系统进程监控
    # 监控异常进程创建
    auditctl -a always,exit -F arch=b64 -S execve -k posthog_monitor
    
    # 网络连接监控
    # 检测到未知IP的出站连接
    

可落地的安全参数配置

Webhook 安全配置

# posthog安全配置
security:
  webhook:
    # URL验证配置
    validation:
      enabled: true
      block_internal_ips: true
      dns_rebinding_protection: true
      timeout: 5  # 秒
    
    # 请求限制
    rate_limit:
      enabled: true
      requests_per_minute: 60
      burst_size: 10
    
    # 重定向控制
    redirects:
      max_redirects: 3
      allow_internal_redirects: false

ClickHouse 安全参数

clickhouse:
  security:
    # API访问控制
    http_api:
      enabled: true
      port: 8123
      require_authentication: true
      ip_whitelist:
        - "10.0.1.0/24"  # 应用服务器网段
    
    # 查询限制
    query_restrictions:
      max_query_size: 1048576  # 1MB
      max_execution_time: 30   # 秒
      read_only_mode: true     # 生产环境启用
    
    # 表函数控制
    table_functions:
      postgresql_enabled: false
      url_enabled: false
      file_enabled: false

PostgreSQL 安全基线

# postgresql.conf安全配置
# 连接安全
listen_addresses = '10.0.1.100'  # 仅监听内网IP
port = 5432
ssl = on

# 认证配置
password_encryption = scram-sha-256
auth_delay.milliseconds = 1000  # 认证延迟,防止暴力破解

# 查询监控
log_statement = 'ddl'           # 记录DDL语句
log_min_duration_statement = 1000  # 记录执行超过1秒的查询

# 危险功能限制
shared_preload_libraries = 'pgaudit'
pgaudit.log = 'all, -misc'

监控与告警清单

实时监控指标

  1. SSRF 尝试监控

    • 包含内部 IP 的 webhook URL 保存尝试
    • 到内部服务的异常 HTTP 请求
    • DNS 解析到内部地址的尝试
  2. SQL 注入检测

    • 包含异常转义字符的 ClickHouse 查询
    • postgresql()表函数的异常使用
    • 查询执行时间异常
  3. RCE 迹象监控

    • PostgreSQL 中COPY FROM PROGRAM的执行
    • 异常进程创建
    • 到未知 IP 的出站网络连接

告警阈值配置

alerts:
  ssrf_attempt:
    threshold: 3  # 每小时3次尝试
    severity: high
    
  sql_injection:
    threshold: 1  # 立即告警
    severity: critical
    
  rce_attempt:
    threshold: 1  # 立即告警
    severity: critical
    
  default_credentials:
    detection: true  # 检测默认凭据使用
    severity: medium

应急响应与修复流程

漏洞确认后的立即行动

  1. 隔离受影响系统

    • 临时禁用 webhook 功能
    • 限制 ClickHouse HTTP API 访问
    • 加强 PostgreSQL 访问控制
  2. 补丁应用

    # 更新PostHog到安全版本
    docker-compose pull
    docker-compose up -d
    
    # 验证修复
    curl -X POST https://your-posthog/api/user/test_slack_webhook/ \
      -H "Content-Type: application/json" \
      -d '{"webhook":"http://localhost/"}'
    # 应该返回错误
    
  3. 凭据轮换

    -- 轮换PostgreSQL密码
    ALTER USER posthog WITH PASSWORD 'new_strong_password_$(date +%s)';
    
    -- 轮换ClickHouse密码
    ALTER USER default IDENTIFIED WITH sha256_password BY 'new_password';
    

长期安全改进

  1. 架构优化

    • 考虑使用消息队列替代直接 HTTP 调用
    • 实现服务间 mTLS 认证
    • 引入 API 网关进行统一访问控制
  2. 安全测试集成

    • 将 SSRF 测试纳入 CI/CD 流水线
    • 定期进行渗透测试
    • 实施自动化安全扫描
  3. 监控体系完善

    • 建立安全事件关联分析
    • 实施用户行为分析(UEBA)
    • 构建威胁情报集成

总结与最佳实践

PostHog 安全事件揭示了现代微服务架构中的典型安全挑战:单个组件的漏洞可能通过服务间依赖被串联放大。防御此类攻击链需要多层安全控制:

  1. 纵深防御:在每一层(应用、数据库、网络)都实施安全控制
  2. 最小权限:每个组件仅拥有完成其功能所需的最小权限
  3. 输入验证:对所有用户输入进行严格验证,包括内部 API 调用
  4. 默认安全:安装后立即修改默认配置,特别是凭据
  5. 持续监控:建立全面的安全监控和告警体系

通过实施本文提出的多层防御架构和安全参数配置,组织可以显著降低类似攻击链的风险,同时为未来的安全威胁做好准备。安全不是一次性的任务,而是需要持续投入和改进的过程。

资料来源

  1. Mehmet Ince, "Inside PostHog: How SSRF, a ClickHouse SQL Escaping 0day, and Default PostgreSQL Credentials Formed an RCE Chain", mdisec.com, 2025-12-15
  2. NVD, "CVE-2025-1520 - PostHog ClickHouse Table Functions SQL Injection Remote Code Execution Vulnerability", nvd.nist.gov
查看归档