Sophos SIEM : vérifier HTTP Ingest et un parser par l’exemple
Cet exemple relie une source JSON synthétique à HTTP Ingest, à un Custom Parser pour le schéma Auth et à une recherche ciblée. Il montre ainsi le parcours entre les guides HTTP Ingest et Custom Parsers. Il ne produit que des connexions fictives de laboratoire ; il n’effectue aucune connexion utilisateur réelle et ne vérifie aucun identifiant.
Préparer le laboratoire et définir la réussite
Il faut un tenant de test avec abonnement Next-Gen SIEM, un rôle Admin ou Super Admin autorisé et un ordinateur approuvé avec Python 3 et accès HTTPS au point d’ingestion attribué. La planification SIEM explique licences et limites de conservation. Un accès XDR existant ne suffit pas à lui seul pour le transport personnalisé et les Custom Parsers.
Le format d’échange du laboratoire est volontairement strict : un message JSON par POST, le format de champs ci-dessous et la source fixe avanet-lab-source. L’aide HTTP décrit un POST HTTPS avec token Bearer, mais ne définit pas à cet endroit de corps de réponse, code de statut ou enveloppe de payload universels pour toutes les sources. Avant le test d’envoi, vérifier le point réellement attribué et ses exigences actuelles. Si le déploiement précis impose un autre corps, l’adapter d’abord à partir de la documentation correspondante ; cette définition n’est pas une spécification universelle de l’API d’ingestion.
Avant de commencer, documenter tenant, responsable, nom d’intégration, nom de parser et heure du test. Le résultat attendu comprend trois preuves séparées :
- La source de laboratoire approuvée a envoyé exactement le message prévu.
- Le parser affecte correctement les valeurs source fictives au schéma Auth.
- Le message est retrouvable dans le bon tenant avec l’heure, la source et l’identifiant de test correspondants.
Un succès HTTP, un connecteur vert ou un script syntaxiquement valide ne suffisent pas à valider ce test. Ni détection ni traitement MDR de cet événement de laboratoire ne sont attendus.
Format de test et définition complète du parser
La source de laboratoire utilise cette unique ligne JSON :
{"product":"avanet-siem-lab","schema_version":1,"event_type":"logon","sensor_id":"avanet-lab-source","user":"pilot-user","src_ip":"192.0.2.25","session_id":"avanet-lab-20261029T101500Z","time":"2026-10-29T10:15:00Z","result":"success"}
192.0.2.25 est une adresse de documentation. pilot-user n’est pas un utilisateur du tenant. La session_id identifie ce exécution fictive du laboratoire, pas la session d’une connexion réelle. Lors du test d’envoi ultérieur, le script génère une heure UTC actuelle et un nouvel identifiant ; l’heure fixe de l’exemple sert uniquement dans l’éditeur du parser.
Sous Security Operations > Integrations > Custom Parsers > Add Custom Parser, créer un nouveau parser nommé AVANET_LAB_JSON_AUTH. Sélectionner Standalone, le format source JSON et le schéma cible Auth. Ne pas écraser ni étendre les parsers globaux existants. La définition complète suivante décrit exclusivement le format de laboratoire montré :
!SCHEMA=scwx.auth
!CONFIRMWITH=PATTERN
!CONFIRMSTRING=^\{"product":"avanet-siem-lab","schema_version":1,"event_type":"logon","sensor_id":"avanet-lab-source","user":"[^"]+","src_ip":"[^"]+","session_id":"[^"]+","time":"[^"]+","result":"(success|failure)"\}$
!TRIMALLOFF
!SAMPLE={"product":"avanet-siem-lab","schema_version":1,"event_type":"logon","sensor_id":"avanet-lab-source","user":"pilot-user","src_ip":"192.0.2.25","session_id":"avanet-lab-20261029T101500Z","time":"2026-10-29T10:15:00Z","result":"success"}
json = JSON(originalData$)
sensorType$ = "AVANET_SIEM_LAB"
sensorId$ = json["$.sensor_id"]
sourceUserName$ = json["$.user"]
sourceAddress$ = json["$.src_ip"]
sessionId$ = json["$.session_id"]
authSystem$ = json["$.product"]
eventTimeUsec$ = DATETIME(json["$.time"], "2006-01-02T15:04:05Z07:00")
authCategory$ = 10
action$ = IF json["$.result"] == "failure" THEN 8 ELSE 1
actionResult$ = IF json["$.result"] == "success" THEN 10 ELSE 20
La Confirm String est volontairement limitée à cette sérialisation compacte exacte, avec ordre fixe des champs. Un JSON joliment indenté ou un ordre différent ne correspondent pas. Pour une source réelle, revoir ce motif de reconnaissance à partir de messages originaux représentatifs ; une recherche large du seul mot « logon » ne serait pas un remplacement équivalent.
Pour ce laboratoire, les champs Auth utilisés et leurs valeurs enum fixes sont associés comme suit :
| Valeur brute | Champ du parser | Normalisation attendue |
|---|---|---|
sensor_id | sensorId$ | sensor_id |
user | sourceUserName$ | source_user_name |
src_ip | sourceAddress$ | source_address |
session_id | sessionId$ | session_id |
UTC-time | eventTimeUsec$ | event_time_usec |
| Connexion de laboratoire | authCategory$ = 10 | ACCOUNT_LOGON |
success | action$ = 1, actionResult$ = 10 | LOGON, SUCCESS |
failure | action$ = 8, actionResult$ = 20 | FAILURE, FAILED |
Ces nombres sont des enums du schéma, pas des niveaux de gravité choisis librement. Le modèle de format temporel Go dans DATETIME() préserve le marqueur UTC ou un décalage de fuseau ISO 8601. Comparer dans l’éditeur valeur brute et temps normalisé en microsecondes. La définition ne renseigne ni tenantId$ ni resourceId$ elle-même ; ne pas remplacer ces valeurs par des identifiants inventés de tenant ou d’événement.
Vérifier dans l’éditeur sans activer le parser
Coller la ligne d’exemple dans Sample Message. Ouvrir Parse Message, puis Source Destination Mapping. Comparer schéma, utilisateur, adresse, heure, résultat et extractor path au tableau. Clarifier tout avertissement concernant un autre parser avant activation.
Ajouter ensuite plusieurs messages individuels comme contre-tests :
- Remplacer
resultparfailure:action=8etaction_result=20sont attendus. - Remplacer
productparother-lab: le message ne doit pas être affecté à ce parser. - Remplacer
resultparunknownou supprimeruser: le message ne doit pas être normalisé comme connexion réussie ; la Confirm String restrictive doit l’exclure. - Insérer une heure invalide : une erreur ou l’absence d’un temps correct bloque l’approbation. Ne pas accepter l’heure d’importation comme réussite apparente.
Run Test vérifie le schéma et les Extractor Paths de tous les samples enregistrés. Sophos recommande différents samples et 12–15 exécutions de test ; contrôler alors le chemin du parser réellement utilisé. Parse Message fournit la Parsed Source Message et le Source Destination Mapping pour le contrôle individuel. Un test n’enregistre pas le parser ; Save et Deploy sont des étapes distinctes. L’enregistrement ne constitue pas une preuve de test. Laisser d’abord un nouveau parser désactivé. Sur les parsers déjà actifs, les modifications prendraient effet dès l’enregistrement ; ce laboratoire utilise donc son nouveau parser dédié. Le guide général des parsers explique activation et retour arrière.
Préparer un envoi HTTP unique
Après approbation dans le tenant de test, créer une intégration séparée AVANET-LAB-HTTP sous Security Operations > Integrations > Marketplace > Custom > HTTP Ingest > Set Up. Enregistrer immédiatement Integration Key et URL dans le Secret Store approuvé ; Sophos ne les affiche qu’une fois. Ne pas encore basculer une source existante.
L’exemple Python suivant envoie exactement un message qu’il génère lui-même. URL et clé sont saisies sans affichage, pas stockées comme arguments de commande, variables shell ou éléments du code source. La validation TLS normale reste activée ; les redirections HTTP ne sont pas suivies afin de ne pas transmettre la clé Bearer à une autre destination. Le script ne comporte volontairement aucune répétition automatique, car celle-ci pourrait générer des événements en double sans comportement confirmé.
import datetime
import getpass
import json
import urllib.error
import urllib.parse
import urllib.request
import uuid
class NoRedirect(urllib.request.HTTPRedirectHandler):
def redirect_request(self, req, fp, code, msg, headers, newurl):
return None
url = getpass.getpass("Integration URL: ").strip()
key = getpass.getpass("Integration Key: ")
parsed = urllib.parse.urlsplit(url)
if parsed.scheme != "https" or not parsed.hostname or parsed.username or parsed.password or parsed.fragment:
raise SystemExit("Nur die freigegebene HTTPS-URL ohne eingebettete Zugangsdaten verwenden.")
now = datetime.datetime.now(datetime.timezone.utc)
time_text = now.strftime("%Y-%m-%dT%H:%M:%SZ")
run_id = "avanet-lab-" + now.strftime("%Y%m%dT%H%M%SZ") + "-" + uuid.uuid4().hex[:8]
event = {
"product": "avanet-siem-lab",
"schema_version": 1,
"event_type": "logon",
"sensor_id": "avanet-lab-source",
"user": "pilot-user",
"src_ip": "192.0.2.25",
"session_id": run_id,
"time": time_text,
"result": "success",
}
request = urllib.request.Request(
url,
data=json.dumps(event, separators=(",", ":")).encode("utf-8"),
headers={"Authorization": "Bearer " + key, "Content-Type": "application/json"},
method="POST",
)
print("Testkennung:", run_id, "UTC:", time_text)
try:
with urllib.request.build_opener(NoRedirect()).open(request, timeout=15) as response:
print("HTTP-Status:", response.status)
except urllib.error.HTTPError as error:
print("HTTP-Fehler:", error.code, "— nicht automatisch erneut senden.")
except urllib.error.URLError:
print("Verbindungs- oder TLS-Fehler — URL, Vertrauenskette und Netzwerkweg prüfen.")
Enregistrer le code dans un fichier de laboratoire local sans valeurs secrètes et le démarrer avec Python 3. L’URL doit provenir exactement de l’intégration de laboratoire approuvée ; le code ne vérifie pas la propriété d’un hôte HTTPS arbitraire. Ne pas inclure clé et URL dans des captures de console ou tickets publics. Le script ne génère aucune donnée client, aucun mot de passe ni aucune donnée de session de production.
Même après une réponse HTTP, aucune ingestion réussie n’est encore confirmée. En cas de timeout, il est incertain que le serveur ait déjà accepté le message. Avant tout nouvel envoi, rechercher donc l’identifiant de test noté. Pour 401/403, clarifier identifiants attribués et état d’approbation sans élargir les droits à l’aveugle. En cas de 4xx lié au format du corps, vérifier l’exigence d’ingestion précise au lieu d’essayer au hasard de nouvelles enveloppes JSON.
Rechercher le message brut et l’événement normalisé
Vérifier d’abord le transport séparément. Sous Data Lake Search > Query Editor, rechercher l’identifiant de test affiché dans une fenêtre étroite :
FROM generic WHERE original_data CONTAINS 'avanet-lab-20261029T101500Z' earliest=-1h
Remplacer la valeur d’exemple par l’identifiant réellement affiché. Dans Original Data, produit, identifiant source, utilisateur, heure et résultat doivent correspondre à la ligne envoyée. Le sensor_id de l’événement générique peut dépendre du parcours de collecte. Le nom d’affichage de l’intégration n’est donc pas automatiquement le bon identifiant de recherche. Ne reprendre la valeur réellement présente que si un filtre supplémentaire sur sensor_id est souhaité.
Après réussite des tests dans l’éditeur, activer consciemment le nouveau parser de laboratoire et envoyer un nouveau message de test. Ne pas supposer que les données brutes déjà collectées seront normalisées rétroactivement à cette occasion. Rechercher l’événement Auth attendu avec les champs de laboratoire définis :
FROM auth WHERE sensor_id = 'avanet-lab-source' AND session_id = 'avanet-lab-20261029T101500Z' earliest=-1h
Là encore, remplacer l’identifiant. Dans le résultat, vérifier Normalized Data : source_user_name=pilot-user, source_address=192.0.2.25, une heure cohérente avec la source, action=1, auth_category=10 et action_result=10, ou leurs noms enum affichés dans l’UI. L’extractor path doit appartenir au parser de laboratoire. Cette liste définit les critères de validation.
Pour un essai d’échec contrôlé dans le générateur, remplacer uniquement result par failure, générer un nouvel identifiant de test et envoyer à nouveau une seule fois. Le schéma doit alors afficher action=8 et action_result=20. Une normalisation réussie supplémentaire pour unknown ou un identifiant de produit étranger serait en revanche un motif d’arrêt.
Isoler les erreurs et retirer le laboratoire
Aucun message brut : vérifier heure d’envoi et identifiant de test, réponse de transport, bon tenant, fenêtre temporelle et source. Ne pas traiter l’absence de résultat comme preuve unique d’un échec de transport ; la recherche générique brute nécessite les paramètres avancés et l’accès à original_data est limité dans le temps.
Message brut présent, aucun résultat Auth : vérifier état du parser, sérialisation exacte, Confirm String, schéma et chemin du parser. Ne pas élargir les parsers de production simplement pour collecter l’événement de laboratoire.
Résultat Auth avec résultat ou heure incorrects : comparer source et mapping séparément. Désactiver le parser et corriger la version sauvegardée du script ; ne pas combler les valeurs par des valeurs par défaut inventées.
Après validation, arrêter le générateur et désactiver uniquement le parser de laboratoire nouvellement créé via Disable. Sa normalisation supplémentaire s’arrête ainsi ; données génériques et événements déjà conservés ne sont pas considérés comme supprimés. Ne retirer l’intégration de laboratoire qu’après clarification du remplacement ou de la révocation de sa clé et après approbation. Le retrait ne doit modifier aucune intégration partagée ni autre source de données.
La maintenance suit le parcours SIEM : documenter ensemble format source et version du parser, valider à nouveau après modification et planifier séparément conservation et traitement des alertes.