fix(ja4ebpf): split bpf2go generate into Ja4Tc + Ja4Ssl, fix RPM systemd-rpm-macros

- Use two separate //go:generate directives (Ja4Tc for tc_capture.c, Ja4Ssl
  for uprobe_ssl.c) to avoid duplicate LICENSE symbol and multi-file clang issue
- Update loader.go to hold tcObjs/sslObjs separately with correct field names:
  UprobeSslSetFd, UprobeSslReadEntry, UretprobeSslReadExit,
  KprobeAccept4Entry, KretprobeAccept4Exit
- Add systemd-rpm-macros to all three RPM build stages (el8/el9/el10)
  so that %{_unitdir} macro resolves correctly
- RPMs now build successfully for el8, el9, el10

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
toto
2026-04-11 23:21:11 +02:00
parent a1e4c1dad5
commit 3b047b680a
155 changed files with 197011 additions and 599 deletions

View File

@ -53,7 +53,7 @@ Ce document présente une architecture complète de détection et classification
- 3.3 Couche L4 — TCP
- 3.4 Couche L5 — TLS
- 3.5 Couche L7 — HTTP
- 3.6 Corrélation inter-couches (logcorrelator)
- 3.6 Corrélation inter-couches (ja4ebpf)
- 3.7 Agrégation temporelle et features dérivées
- 3.8 Détection ML semi-supervisée (full pipeline)
@ -112,7 +112,7 @@ La quatrième génération en émergence combine : analyse corrélée en temps r
Ce document décrit une architecture opérationnelle positionnée à la frontière Gen3/Gen4, déployée en production sur un serveur Apache. Les contributions techniques originales incluent :
1. **Corrélation TCP/TLS/HTTP** en temps réel via le module logcorrelator (clé : `src_ip:src_port`, timeout orphelin 500 ms)
1. **Corrélation TCP/TLS/HTTP** en temps réel via ja4ebpf (clé : `src_ip:src_port`, 256 shards, timeout orphelin 500 ms)
2. **Fingerprinting HTTP/2 passif** : extraction des trames SETTINGS, WINDOW_UPDATE, PRIORITY et de l'ordre des pseudo-headers directement depuis le stream TCP
3. **Architecture EIF bifurquée** : modèle complet (≈ 45 features L3→L7) et modèle applicatif (≈ 35 features L7 uniquement), évitant le biais de zérotage sur le trafic non corrélé
4. **Ensemble triple-voix + MetaLearner** : fusion EIF + AE + XGBoost avec régression logistique apprise sur étiquettes accumulées
@ -461,10 +461,10 @@ Résultat : les coupes ne sont plus liées aux axes, éliminant les artéfacts g
Deux modèles EIF s'exécutent en parallèle à chaque cycle de 300 secondes :
- **Modèle Complet** (≈ 45 features, L3→L7) : appliqué sur les sessions corrélées (correlated=1) pour lesquelles ja4sentinel a pu corréler les métadonnées TCP/TLS avec la requête HTTP. Inclut toutes les features des familles F1F7.
- **Modèle Complet** (≈ 45 features, L3→L7) : appliqué sur les sessions corrélées (correlated=1) pour lesquelles ja4ebpf a pu corréler les métadonnées TCP/TLS avec la requête HTTP. Inclut toutes les features des familles F1F7.
- **Modèle Applicatif** (≈ 35 features, L7 uniquement) : appliqué sur les sessions non corrélées (correlated=0) — trafic passant par un CDN ou proxy qui ne permet pas la corrélation TCP/TLS. Zeroed les features TCP/TLS pour ce modèle éviterait d'introduire un biais systématique de zéro-imputation.
La bifurcation est justifiée par le fait que les features TCP/TLS ne sont disponibles que lorsque ja4sentinel a corrélé la connexion réseau avec la requête HTTP. Imputer ces features à zéro pour le trafic non corrélé créerait un signal artificiel (zéro n'est pas neutre pour un EIF — il est interprété comme une valeur réelle).
La bifurcation est justifiée par le fait que les features TCP/TLS ne sont disponibles que lorsque ja4ebpf a corrélé la connexion réseau avec la requête HTTP. Imputer ces features à zéro pour le trafic non corrélé créerait un signal artificiel (zéro n'est pas neutre pour un EIF — il est interprété comme une valeur réelle).
#### 2.4.2b Autoencoders (AE) et détection d'anomalies
@ -799,18 +799,18 @@ httpcloak est un outil d'évasion qui tente d'imiter l'empreinte TLS de Chrome.
┌──────────────────────────────────────────────────────────────────┐
│ SOURCES DE DONNÉES │
├───────────────────────────┬──────────────────────────────────────┤
ja4sentinel │ mod_reqin_log
(Source B) │ (Source A)
TC ingress (XDP/TC) │ uprobe SSL_read
Couches L3/L4/L5 │ Couche L7 HTTP déchiffré
│ │ │
libpcap, CAP_NET_RAW │ Module Apache personnalisé
Couches L3/L4/L5 │ Couches L7 HTTP + L5 HTTP/2
│ - IP header (TTL, DF) │ - src_ip, src_port
- TCP SYN (MSS, Window, │ - timestamp_ns (nanoseconde)
Options, Scale) │ - méthode, chemin, query
- TLS ClientHello │ - version HTTP
(JA4, JA4T, ALPN, SNI) │ - en-têtes (bruts + ordre)
│ │ - statut, taille, durée_ms
│ │ - HTTP/2 preface passif :
réseau XDP/TC → │ Go Magic Bytes dispatcher →
│ - SYN : TTL, IP-ID, DF, HTTP/1.1 : method, path, query,
MSS, Window, Scale │ headers (bruts + ordre),
- TLS ClientHello : │ status, taille, durée_ms,
JA4, ALPN, SNI │ timestamp_ns (nanoseconde)
- HTTP port 80/8080 │ HTTP/2 (depuis preface client) :
│ │ ordre pseudo-headers
│ │ WINDOW_UPDATE, PRIORITY flag,
│ │ SETTINGS (7 params individuels), │
│ │ WINDOW_UPDATE, PRIORITY flag, │
│ │ ordre pseudo-headers │
@ -819,8 +819,8 @@ httpcloak est un outil d'évasion qui tente d'imiter l'empreinte TLS de Chrome.
└─────────────┬─────────────┘
┌─────────▼─────────┐
logcorrelator
Corrélation in-memory
(ja4ebpf)
│ Clé: src_ip:port │
│ Keep-Alive multi-│
│ request tracking │
@ -899,7 +899,7 @@ Features : `avg_ttl` (TTL moyen sur la fenêtre), `ttl_std` (écart-type du TTL
### 3.3 Couche L4 — TCP
**TCP Keep-Alive et multiplexage HTTP** : à ne pas confondre avec HTTP Keep-Alive (`Connection: keep-alive`). Le TCP Keep-Alive est un mécanisme de détection de connexions mortes au niveau du noyau (envoi de paquets ACK vides après inactivité). L'HTTP Keep-Alive, en revanche, maintient la connexion TCP ouverte pour réutilisation par plusieurs requêtes HTTP successives. Le module mod_reqin_log trace le nombre de requêtes HTTP dans chaque connexion TCP via `max_keepalives`.
**TCP Keep-Alive et multiplexage HTTP** : à ne pas confondre avec HTTP Keep-Alive (`Connection: keep-alive`). Le TCP Keep-Alive est un mécanisme de détection de connexions mortes au niveau du noyau (envoi de paquets ACK vides après inactivité). L'HTTP Keep-Alive, en revanche, maintient la connexion TCP ouverte pour réutilisation par plusieurs requêtes HTTP successives. ja4ebpf trace le nombre de requêtes HTTP dans chaque connexion TCP via `max_keepalives` dans le gestionnaire de corrélation in-memory.
**Coefficient de variation (CV)** : mesure adimensionnelle de variabilité, CV = σ/μ. Un CV ≈ 0 indique une régularité élevée (automatisation à timer fixe) ; un CV ≈ 13 indique une variabilité naturelle (humain). Applicable à `syn_timing_cv` (variabilité du délai SYN→ClientHello) et à `cadence_cv` (variabilité des intervalles inter-requêtes).
@ -932,18 +932,18 @@ Features : `avg_ttl` (TTL moyen sur la fenêtre), `ttl_std` (écart-type du TTL
### 3.5 Couche L7 — HTTP
La couche L7 constitue la couche la plus riche en features comportementales. Le module **mod_reqin_log** est un module Apache personnalisé qui enregistre chaque requête HTTP avec une précision nanoseconde via `clock_gettime(CLOCK_REALTIME)`.
La couche L7 constitue la couche la plus riche en features comportementales. L'agent **ja4ebpf** capture le flux HTTP déchiffré via un uprobe sur `SSL_read` (OpenSSL/BoringSSL), avec une précision nanoseconde via `bpf_ktime_get_ns()`.
Données capturées par mod_reqin_log : `src_ip`, `src_port`, `timestamp_ns` (nanoseconde absolu), `method`, `path`, `query_string`, `http_version`, `headers_raw` (en-têtes bruts dans leur ordre d'émission), `header_order_signature` (hash de l'ordre), `status_code`, `response_size`, `duration_ms`. L'horodatage nanoseconde est critique pour le calcul des features temporelles F8 (cadence_cv, lag1_autocorrelation, benford_deviation, root_to_first_asset_delay).
Données capturées par ja4ebpf : `src_ip`, `src_port`, `timestamp_ns` (nanoseconde absolu), `method`, `path`, `query_string`, `http_version`, `headers_raw` (en-têtes bruts dans leur ordre d'émission), `header_order_signature` (hash de l'ordre), `status_code`, `response_size`, `duration_ms`. L'horodatage nanoseconde est critique pour le calcul des features temporelles F8 (cadence_cv, lag1_autocorrelation, benford_deviation, root_to_first_asset_delay).
**Fingerprinting HTTP/2 passif intégré** : pour les connexions HTTP/2, mod_reqin_log capture passivement le preface client via un hook `ap_hook_process_connection` enregistré en priorité `APR_HOOK_FIRST`, exécuté avant `mod_http2`. Ce hook effectue une lecture spéculative (`AP_MODE_SPECULATIVE`) de 512 octets sur les filtres d'entrée de la connexion, qui déclenche transparentement le handshake TLS (`mod_ssl`) et retourne les données déchiffrées sans les consommer. Le preface H2 est ensuite parsé pour en extraire :
**Fingerprinting HTTP/2 passif intégré** : pour les connexions HTTP/2, ja4ebpf identifie le protocole via le Go Magic Bytes dispatcher qui reconnaît le preface `PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n` dans le flux SSL_read déchiffré. Le parser HTTP/2 extrait ensuite les frames depuis ce flux déchiffré sans aucune instrumentation côté serveur web :
- Les 7 paramètres SETTINGS individuels (IDs 16 et 8), chacun stocké dans une colonne ClickHouse dédiée (`h2_header_table_size`, `h2_enable_push`, `h2_max_concurrent_streams`, `h2_initial_window_size`, `h2_max_frame_size`, `h2_max_header_list_size`, `h2_enable_connect_protocol`), avec la valeur -1 pour les paramètres absents du preface client
- L'incrément `h2_window_update` de la frame WINDOW_UPDATE sur la connexion (stream ID 0)
- Le flag `h2_has_priority` indiquant la présence d'un champ PRIORITY dans la frame HEADERS
- L'ordre des pseudo-headers `h2_pseudo_order` (ex. `m,a,s,p`) extrait par décodage HPACK partiel de la première frame HEADERS
- Le fingerprint composite `h2_fingerprint` au format Akamai et la chaîne brute `h2_settings_fp`
Les données H2 sont stockées dans les notes de la connexion primaire (`c->notes`). Pour les connexions HTTP/2, `mod_http2` crée des connexions secondaires (c2) par stream ; le hook `log_request` accède aux notes H2 via `r->connection->master` (connexion primaire c1). Le hook retourne `DECLINED` après stockage, laissant `mod_http2` gérer la suite normalement.
Les données H2 sont associées à la session courante via la clé `src_ip:src_port` dans le gestionnaire de corrélation in-memory de ja4ebpf, puis transmises en batch à ClickHouse avec les données TCP/TLS correspondantes.
**Colonnes HTTP/2 dans `ja4_logs.http_logs`** :
@ -966,11 +966,11 @@ La convention `-1` pour les paramètres SETTINGS absents est essentielle : elle
Toutes les features des familles F1F6 et F8 proviennent de cette couche, agrégées sur des fenêtres temporelles de 300 secondes (5 minutes) par session (src_ip).
### 3.6 Corrélation inter-couches (logcorrelator)
### 3.6 Corrélation inter-couches (ja4ebpf)
**Clé de corrélation** : `(src_ip, src_port)` — le tuple source identifie de manière unique une connexion TCP à un instant donné (une connexion TCP est identifiée par le 4-tuple src_ip:src_port:dst_ip:dst_port, mais dst_ip:dst_port étant fixes pour un serveur, le 2-tuple src suffit).
**Gestion du HTTP Keep-Alive** : une connexion TCP peut transporter plusieurs requêtes HTTP successives. logcorrelator maintient une table de connexions indexée par `(src_ip, src_port)`. Chaque requête HTTP reçue de mod_reqin_log est associée à l'enregistrement TCP/TLS ouvert correspondant, et `max_keepalives` est incrémenté. L'enregistrement reste ouvert jusqu'à la déconnexion TCP ou l'expiration.
**Gestion du HTTP Keep-Alive** : une connexion TCP peut transporter plusieurs requêtes HTTP successives. ja4ebpf maintient un gestionnaire de corrélation in-memory organisé en 256 shards (partitionnement par hash de src_ip pour éviter la contention). Chaque requête HTTP capturée via l'uprobe SSL_read est associée à l'enregistrement TCP/TLS ouvert correspondant, et `max_keepalives` est incrémenté. Un GC toutes les 100 ms libère les sessions expirées.
**Timeout orphelin** : si aucun enregistrement réseau ne correspond à une requête HTTP dans les 500 ms, la requête est enregistrée comme orpheline (`correlated=0`). Cela se produit quand le trafic arrive via un CDN ou un proxy inverse qui établit une nouvelle connexion TCP entre le proxy et le serveur, rendant l'adresse source TCP celle du proxy plutôt que celle du client original.
@ -1099,9 +1099,7 @@ Le système `browser_confidence` à 6 axes (§3.8) fournit un score agrégé uti
- **Compression d'en-têtes HPACK** : [RFC 7541](https://www.rfc-editor.org/rfc/rfc7541) définit HPACK, une compression d'en-têtes HTTP par table d'indexation. L'ordre des entrées dans la table statique HPACK est normalisé, mais l'ordre de sérialisation des pseudo-headers est laissé à l'implémentation.
- **Contrôle de flux** : mécanisme de fenêtres (`WINDOW_UPDATE`) limitant le débit pour éviter la saturation du récepteur.
Après terminaison TLS par Apache (`mod_ssl`), le flux HTTP/2 est déchiffré et disponible en clair. Le fingerprinting passif est réalisé directement par **mod_reqin_log** via un hook `process_connection` enregistré en priorité `APR_HOOK_FIRST`. Ce hook s'exécute **avant** `mod_http2` et effectue une lecture spéculative (`AP_MODE_SPECULATIVE`, 512 octets) sur `c->input_filters`, déclenchant transparentement le handshake TLS. Si les données commencent par le magic HTTP/2 (`PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n`), le parser binaire extrait les frames SETTINGS, WINDOW_UPDATE et HEADERS du preface client, stocke les résultats dans `c->notes`, puis retourne `DECLINED` pour laisser `mod_http2` rer la connexion. Cette approche ne consomme pas les données et n'interfère pas avec le traitement HTTP/2 normal.
**Note architecturale** : l'approche par filtre de connexion (`AP_FTYPE_CONNECTION`) a été abandonnée car `mod_http2` prend le contrôle complet de la connexion via son propre hook `process_connection` les filtres d'entrée de connexion ne sont jamais invoqués pour les connexions HTTP/2. Le hook `process_connection` à priorité haute est la seule technique fiable pour intercepter le preface H2 avant `mod_http2`.
Après terminaison TLS par le serveur web, le flux HTTP/2 est déchiffré et disponible en clair dans le contexte d'OpenSSL/BoringSSL. Le fingerprinting passif est réalisé par **ja4ebpf** via un uprobe sur `SSL_read`. Lorsque le Go Magic Bytes dispatcher détecte le magic HTTP/2 (`PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n`) dans le flux déchiffré, le parser H2 extrait les frames SETTINGS, WINDOW_UPDATE et HEADERS du preface client, sans modifier ni interrompre le flux. Cette approche est agnostique au serveur web (Apache, Nginx, Varnish, HAProxy) et ne nécessite aucun module natif installé côté serveur.
#### Frame SETTINGS
@ -1397,7 +1395,7 @@ Le module `browser_matcher` génère les features suivantes dans le vecteur feat
| `h2_pseudo_order` | String | Ordre observé (ex. `m,a,s,p`) | `[impl.]` (colonne `h2_pseudo_order` dans `http_logs`) |
| `tls_h2_family_mismatch` | UInt8 | 1 si JA4 dit Chrome mais H2 SETTINGS dit Firefox/outil | `[impl.]` (feature F4) |
Les features `h2_window_update_value`, `h2_has_priority_frames` et `h2_pseudo_order` sont désormais capturées par mod_reqin_log et stockées dans des colonnes individuelles de `ja4_logs.http_logs`. De plus, chaque paramètre SETTINGS HTTP/2 dispose de sa propre colonne (`h2_header_table_size`, `h2_enable_push`, `h2_max_concurrent_streams`, `h2_initial_window_size`, `h2_max_frame_size`, `h2_max_header_list_size`, `h2_enable_connect_protocol`) avec la valeur -1 pour les paramètres absents du preface client. La feature `tls_h2_family_mismatch` est implémentée dans le vecteur feature global (famille F4 TLS features) et se calcule à partir des données JA4 existantes et des colonnes H2 individuelles disponibles dans `ja4_logs.http_logs`. Les features `browser_match_*` requièrent l'exécution complète du module `browser_matcher.py`.
Les features `h2_window_update_value`, `h2_has_priority_frames` et `h2_pseudo_order` sont désormais capturées par ja4ebpf via le parser HTTP/2 du flux SSL_read déchiffré et stockées dans des colonnes individuelles de `ja4_logs.http_logs`. De plus, chaque paramètre SETTINGS HTTP/2 dispose de sa propre colonne (`h2_header_table_size`, `h2_enable_push`, `h2_max_concurrent_streams`, `h2_initial_window_size`, `h2_max_frame_size`, `h2_max_header_list_size`, `h2_enable_connect_protocol`) avec la valeur -1 pour les paramètres absents du preface client. La feature `tls_h2_family_mismatch` est implémentée dans le vecteur feature global (famille F4 TLS features) et se calcule à partir des données JA4 existantes et des colonnes H2 individuelles disponibles dans `ja4_logs.http_logs`. Les features `browser_match_*` requièrent l'exécution complète du module `browser_matcher.py`.
### 3.9.5 Maintenance des signatures
@ -1508,7 +1506,7 @@ La famille 1 capture les signaux de volume et de cadence bruts. Ces features son
| Scraper simple (connexion par req) | 1 |
| Bot pipeline agressif | > 100 |
**Implémentation** : mod_reqin_log incrémente un compteur par connexion TCP (`src_ip:src_port`) à chaque requête HTTP reçue. Le maximum sur la session est agrégé dans `view_ai_features_1h`.
**Implémentation** : ja4ebpf incrémente un compteur via le gestionnaire de corrélation in-memory par connexion TCP (`src_ip:src_port`) à chaque requête HTTP reçue. Le maximum sur la session est agrégé dans `view_ai_features_1h`.
#### count_login_post `[impl.]`
@ -2637,7 +2635,7 @@ Cette asymétrie constitue un signal exploitable : un flux HTTP sans résolution
#### Technique : ratio DNS shadow
Capture DNS passive via `ja4sentinel` étendu au port UDP/53, puis corrélation avec les flux HTTP :
Capture DNS passive via `ja4ebpf` étendu au port UDP/53, puis corrélation avec les flux HTTP :
```
dns_shadow_ratio = requêtes HTTP vers hôte X / résolutions DNS de l'hôte X observées
@ -2658,7 +2656,7 @@ Les bots utilisant DoH contournent l'analyse DNS shadow. Cependant, les connexio
Le fingerprinting **JA4D/JA4D6** des requêtes DHCP/DHCPv6 pourrait compléter l'analyse en identifiant les dispositifs derrière NAT, ajoutant une couche d'identification au-delà de l'adresse IP. Cette extension est envisagée comme travail futur conjoint à DNS Shadow Analysis.
**`[todo]` Non implémenté** : nécessite l'extension de `ja4sentinel` pour la capture UDP/53. Travail futur priorité 1 (voir §6.6).
**`[todo]` Non implémenté** : nécessite l'extension de `ja4ebpf` pour la capture UDP/53. Travail futur priorité 1 (voir §6.6).
---
@ -2946,13 +2944,13 @@ Un seul utilisateur réel alterne quelques connexions (26 ports source actifs
**browser_matcher complet (§3.9)** :
- État actuel : modules `[partiel]` (logique de score partielle, base de signatures incomplète)
- Données H2 brutes : `[impl.]` — capture des 7 paramètres SETTINGS individuels, WINDOW_UPDATE, flag PRIORITY et ordre pseudo-headers par mod_reqin_log via hook `process_connection` (APR_HOOK_FIRST, AP_MODE_SPECULATIVE). Colonnes individuelles dans `ja4_logs.http_logs` (`h2_header_table_size`, `h2_enable_push`, `h2_max_concurrent_streams`, `h2_initial_window_size`, `h2_max_frame_size`, `h2_max_header_list_size`, `h2_enable_connect_protocol`, `h2_window_update`, `h2_has_priority`, `h2_pseudo_order`)
- Données H2 brutes : `[impl.]` — capture des 7 paramètres SETTINGS individuels, WINDOW_UPDATE, flag PRIORITY et ordre pseudo-headers par ja4ebpf via le parser HTTP/2 du flux SSL_read déchiffré. Colonnes individuelles dans `ja4_logs.http_logs` (`h2_header_table_size`, `h2_enable_push`, `h2_max_concurrent_streams`, `h2_initial_window_size`, `h2_max_frame_size`, `h2_max_header_list_size`, `h2_enable_connect_protocol`, `h2_window_update`, `h2_has_priority`, `h2_pseudo_order`)
- Travail restant : compléter `browser_signatures.py` avec signatures Firefox et Safari complètes, implémenter le rechargement ClickHouse toutes les 24h, intégrer les 5 features `browser_match_*` dérivées dans le vecteur feature global
- Dépendances : ~~capture des frames H2 SETTINGS~~ (réalisé) ; reste le module `browser_matcher.py`
**DNS Shadow Analysis (§5.6)** :
- État actuel : `[todo]` non implémenté
- Travail requis : extension de `ja4sentinel` pour capture UDP/53 + TCP/53, table ClickHouse `dns_resolutions`, corrélation avec table `sessions`
- Travail requis : extension de `ja4ebpf` pour capture UDP/53 + TCP/53, table ClickHouse `dns_resolutions`, corrélation avec table `sessions`
- Contraintes techniques : nécessite accès privilégié au trafic réseau niveau interface (pcap ou eBPF)
- Estimation : 68 semaines de développement + tests de charge
@ -3016,7 +3014,7 @@ L'**explainabilité** est assurée par ExIFFI ([Frizzo et al., 2024](https://arx
Extension du système `browser_confidence` à 6 axes vers une correspondance structurée par famille de navigateur, fondée sur l'analyse passive de 7 dimensions H2 : frame SETTINGS (7 paramètres), WINDOW_UPDATE, ordre des pseudo-headers, frames PRIORITY, cohérence des en-têtes HTTP, structure TLS, et lookup JA4 par dictionnaire.
La capture passive est réalisée par mod_reqin_log via un hook `ap_hook_process_connection` (APR_HOOK_FIRST) qui intercepte le preface HTTP/2 avant `mod_http2` par lecture spéculative. Chaque paramètre SETTINGS est stocké dans une colonne ClickHouse individuelle (`h2_header_table_size`, `h2_enable_push`, `h2_max_concurrent_streams`, `h2_initial_window_size`, `h2_max_frame_size`, `h2_max_header_list_size`, `h2_enable_connect_protocol`) avec -1 pour les paramètres absents, complétés par `h2_window_update`, `h2_has_priority` et `h2_pseudo_order`.
La capture passive est réalisée par ja4ebpf via un uprobe sur `SSL_read` (OpenSSL/BoringSSL). Le Go Magic Bytes dispatcher identifie le preface HTTP/2 dans le flux déchiffré, et le parser H2 extrait les frames SETTINGS, WINDOW_UPDATE et HEADERS sans instrumentation serveur. Chaque paramètre SETTINGS est stocké dans une colonne ClickHouse individuelle (`h2_header_table_size`, `h2_enable_push`, `h2_max_concurrent_streams`, `h2_initial_window_size`, `h2_max_frame_size`, `h2_max_header_list_size`, `h2_enable_connect_protocol`) avec -1 pour les paramètres absents, complétés par `h2_window_update`, `h2_has_priority` et `h2_pseudo_order`.
Cette technique permet de détecter des outils d'évasion qui reproduisent correctement la couche TLS (curl_cffi, httpcloak) mais échouent à reproduire les subtilités H2 — notamment l'ordre des pseudo-headers et la valeur WINDOW_UPDATE.
@ -3058,7 +3056,7 @@ Architecture de données fondée sur ClickHouse avec **AggregatingMergeTree view
| F11 — Futures (non impl.) | dns_shadow_ratio, compression_ratio_invariant (2 features) | 0 | 0 | 2 |
| **Total** | **85** | **70** | **5** | **2** + meta |
**Résumé quantitatif** : ~82 % des features entièrement implémentées (`[impl.]`), ~6 % partiellement implémentées (`[partiel]`, les 5 features `browser_match_*` de browser_matcher), ~2 % non implémentées (`[todo]`, §5.6 et §5.7). Les 3 features H2 brutes (`h2_window_update_value`, `h2_has_priority_frames`, `h2_pseudo_order`) sont passées de `[partiel]` à `[impl.]` suite à l'intégration de la capture HTTP/2 passive dans mod_reqin_log.
**Résumé quantitatif** : ~82 % des features entièrement implémentées (`[impl.]`), ~6 % partiellement implémentées (`[partiel]`, les 5 features `browser_match_*` de browser_matcher), ~2 % non implémentées (`[todo]`, §5.6 et §5.7). Les 3 features H2 brutes (`h2_window_update_value`, `h2_has_priority_frames`, `h2_pseudo_order`) sont passées de `[partiel]` à `[impl.]` suite à l'intégration de la capture HTTP/2 passive dans ja4ebpf via le parser HTTP/2 du flux SSL_read.
### Perspective