# Guide : Capture HTTP Nginx et Apache httpd via ja4ebpf ## Vue d'ensemble ja4ebpf peut capturer le trafic HTTP complet depuis deux serveurs web différents : - **Nginx** ✅ : via `recvfrom()` syscall (kretprobe sur `__x64_sys_recvfrom`) - **Apache httpd** ✅ : via `apr_socket_recv()` uprobe dans libapr-1.so.0 ### Statut de validation | Serveur | Kernel | Statut | Méthode | Headers capturés | |---------|--------|--------|---------|------------------| | nginx | CentOS 8 (4.18) | ✅ Validé | kretprobe `__x64_sys_recvfrom` | Tous (sans troncature) | | nginx | Rocky Linux 9 (5.14+) | ✅ Validé | kretprobe `__x64_sys_recvfrom` | Tous (sans troncature) | | nginx | Rocky Linux 10 (6.12) | ✅ Validé | kretprobe `__x64_sys_recvfrom` | Tous (sans troncature) | | Apache httpd | CentOS 8 (4.18) | ✅ Validé | uprobe `apr_socket_recv` | Tous (sans troncature) | | Apache httpd | Rocky Linux 10 (6.12) | ✅ Validé | uprobe `apr_socket_recv` | Tous (sans troncature) | | Apache httpd | Rocky Linux 9 (5.14+) | ✅ Compatible | uprobe `apr_socket_recv` | Même méthode | ## Configuration ### Configuration YAML ```yaml uprobes: enabled: true servers: ["nginx", "apache"] # Active les deux serveurs ``` ### Variables d'environnement ```bash JA4EBPF_UPROBES_ENABLED=true JA4EBPF_UPROBES_SERVERS=nginx,apache ``` ## Architecture de capture ### Nginx (kretprobe) ``` ┌─────────────┐ │ nginx worker │─┐ └─────────────┘ │ ├─ recvfrom() ──┐ │ │ ┌──────▼──────┐ │ │ kretprobe │ │ │ __x64_sys │ │ │ recvfrom │ │ └─────────────┘ │ │ ┌───────▼──────┐ │ ja4ebpf │ │ user space │ └─────────────┘ ``` ### Apache httpd (uprobe apr_socket_recv) ``` ┌─────────────┐ │ httpd worker │─┐ └─────────────┘ │ ├─ apr_socket_recv() (libapr-1.so.0) ──┐ │ │ ┌──────▼──────┐ │ │ uprobe │ │ │ entry/return│ │ │ apr_socket │ │ │ _recv │ │ └─────────────┘ │ │ ┌───────▼──────┐ │ ja4ebpf │ │ user space │ └─────────────┘ ``` **Avantage Apache** : L'uprobe sur `apr_socket_recv` capture directement au niveau application Apache Portable Runtime, ce qui la rend universelle sur tous les kernels 4.18+ (pas de dépendance aux tracepoints/kernel functions). ## Déploiement multi-servers ### Scénario 1 : ja4ebpf sur chaque serveur web ``` ┌─────────────────┐ ┌─────────────────┐ │ rocky9 (nginx) │ │ centos8 (apache)│ │ │ │ │ │ ┌────────────┐ │ │ ┌────────────┐ │ │ │ nginx │ │ │ │ Apache │ │ │ └─────┬──────┘ │ │ └─────┬──────┘ │ │ │ │ │ │ │ │ ┌─────▼──────┐ │ │ ┌─────▼──────┐ │ │ │ ja4ebpf │ │ │ │ ja4ebpf │ │ │ └────────────┘ │ │ └────────────┘ │ │ │ │ │ │ capture: recvfrom│ │ capture: apr_socket_recv └──────────────────┘ └──────────────────┘ IP: 192.168.42.40 IP: 192.168.42.228 ``` **Configuration** : ```bash # rocky9 JA4EBPF_UPROBES_SERVERS=nginx # centos8 JA4EBPF_UPROBES_SERVERS=apache ``` ### Scénario 2 : ja4ebpf sur machine tierce (recommandé) ``` ┌─────────────────────────────────────────────────┐ │ analysis VM (ja4ebpf) │ │ │ │ ┌────────────┐ ┌─────────────┐ │ │ │ nginx │ │ Apache │ │ │ └──────┬─────┘ └──────┬──────┘ │ │ │ │ │ │ └───────┬───────┘ │ │ │ │ │ ┌───────▼──────────┐ │ │ │ ja4ebpf │ │ │ │ (nginx/Apache) │ │ │ └─────────────────┘ │ └───────────────────────────────────────────────────┘ ``` **Configuration** : ```yaml uprobes: enabled: true servers: ["nginx", "apache"] ``` ## Validation ### Vérification nginx ```bash # Vérifier que nginx capture curl http://192.168.42.40/test -H "User-Agent: Test" -H "X-Request-ID: test-nginx-001" # Logs ja4ebpf tail -f /tmp/ja4ebpf-test.log | grep "\[nginx\]" # Exemple: [nginx] HTTP: pid=116276 fd=8 GET /test (headers=5) # ClickHouse sudo docker exec analysis-clickhouse-1 clickhouse-client --query \ "SELECT method, path, header_user_agent FROM ja4_logs.http_logs \ WHERE time > now() - INTERVAL 1 MINUTE ORDER BY time DESC LIMIT 10" ``` ### Vérification Apache ```bash # Vérifier que Apache capture curl http://192.168.42.228/server-status -H "User-Agent: Test" -H "X-Request-ID: test-apache-001" # Logs ja4ebpf tail -f /tmp/ja4ebpf-apache.log | grep "\[apache\]" # Exemple: [apache] HTTP: pid=71850 GET /server-status (data_len=420) # ClickHouse sudo docker exec analysis-clickhouse-1 clickhouse-client --query \ "SELECT method, path, header_user_agent FROM ja4_logs.http_logs \ WHERE time > now() - INTERVAL 1 MINUTE ORDER BY time DESC LIMIT 10" ``` ## Tests de validation ### Test 1 : Headers complets ```bash # Test nginx (20+ headers) curl http://192.168.42.40/api/test \ -H "User-Agent: Mozilla/5.0 (Validation-Agent)" \ -H "Accept: application/json" \ -H "Authorization: Bearer token" \ -H "X-Custom-1: value1" \ -H "X-Custom-2: value2" \ ... (jusqu'à 20 headers) # Test Apache (20+ headers) curl http://192.168.42.228/api/test \ -H "User-Agent: Mozilla/5.0 (Validation-Agent)" \ -H "Accept: application/json" \ -H "Authorization: Bearer token" \ -H "X-Custom-1: value1" \ -H "X-Custom-2: value2" \ ... (jusqu'à 20 headers) ``` ### Test 2 : Path et query longs ```bash # nginx curl "http://192.168.42.40/api/v1/users/12345/profile/preferences?include=all&filter=active&sort=desc" # Apache curl "http://192.168.42.228/api/v1/users/12345/profile/preferences?include=all&filter=active&sort=desc" ``` ### Validation ClickHouse ```sql -- Requête pour vérifier la capture SELECT src_ip, method, path, query, substring(header_user_agent, 1, 40) as ua_preview, length(header_order_signature) as header_count, substring(header_order_signature, 1, 60) as headers_preview FROM ja4_logs.http_logs WHERE time > now() - INTERVAL 5 MINUTE ORDER BY time DESC LIMIT 20 FORMAT Pretty ``` ## Résultats de validation ### Nginx (via recvfrom) - ✅ VALIDÉ sur Rocky Linux 9 - ✅ Méthode HTTP capturée - ✅ Path complet sans troncature - ✅ Query string complète - ✅ Tous les headers capturés (y compris custom X-*) - ✅ User-Agent complet - ✅ Ordre des headers préservé - ✅ Données ClickHouse sans troncature **Exemple de capture validée** : ```sql SELECT method, path, host, length(header_order_signature) as headers_count, header_order_signature FROM ja4_logs.http_logs WHERE path = '/test-nginx-final' -- Résultat : headers_count=6 -- header_order_signature: host;accept;user-agent;x-request-id;x-custom-1;x-custom-2 ``` ### Apache httpd (via apr_socket_recv) - ✅ VALIDÉ **CentOS 8 (kernel 4.18)** : - ✅ 2 événements HTTP capturés - ✅ Uprobe apr_socket_recv fonctionnel - ✅ libapr-1.so.0 détecté automatiquement **Rocky 10 (kernel 6.12)** : - ✅ 1 événement HTTP capturé - ✅ Même méthode uprobe compatible - ✅ Universelle sur kernels 4.18+ **Rapport complet** : `services/ja4ebpf/docs/APACHE_HTTP_VALIDATION.md` ## Dépannage ### Apache ne capture pas ```bash # Vérifier que Apache httpd utilise libapr sudo lsof -p $(pgrep httpd | head -1) | grep libapr # Vérifier que libapr-1.so.0 existe ls -la /usr/lib64/libapr-1.so.0 # Vérifier les PIDs Apache pgrep -a httpd # Vérifier l'attachement uprobe sudo bpftool prog show | grep apr_socket_recv # Vérifier les logs ja4ebpf tail -f /tmp/ja4ebpf-apache.log | grep -E "(\[uprobes\]|\[apache\])" ``` ### Nginx ne capture pas ```bash # Vérifier les kretprobes attachés sudo bpftool prog show | grep recvfrom # Vérifier les PIDs nginx pgrep -a nginx | wc -l # Vérifier les logs ja4ebpf tail -f /tmp/ja4ebpf-test.log | grep nginx ``` ## Fichiers BPF ### uprobe_nginx.c - `SEC("tp/syscalls/sys_enter_recvfrom")` : Sauvegarde arguments recvfrom - `SEC("kretprobe/__x64_sys_recvfrom")` : Capture données + envoi vers pb_nginx_http ### uprobe_apache.c - `SEC("uprobe/apr_socket_recv")` : Sauvegarde buf_ptr et len (entry) - `SEC("uretprobe/apr_socket_recv")` : Capture données + envoi vers pb_apache_http ## Limitations 1. **Architecture nginx** : Le kretprobe `__x64_sys_recvfrom` est spécifique à l'architecture x86_64 2. **Local** : La capture doit se faire sur la même machine que le serveur web (pour accéder aux syscalls/fonctions) 3. **Performance** : Chaque syscall/appel lu génère un événement BPF - le trafic très élevé peut impacter les performances 4. **Apache only RedHat** : libapr-1.so.0 paths configurés pour RHEL/CentOS/Rocky/AlmaLinux uniquement ## Références - Documentation complète : `docs/services/ja4ebpf.md` - Rapport validation Apache : `services/ja4ebpf/docs/APACHE_HTTP_VALIDATION.md` - Rapport validation nginx multi-kernel : `services/ja4ebpf/docs/NGINX_MULTI_KERNEL_VALIDATION.md` - Rapport validation nginx/ClickHouse : `services/ja4ebpf/docs/CLICKHOUSE_VALIDATION_REPORT.md`