API Security

Broken Object Level Authorization : explication complète

BOLA décortiqué : définition, pourquoi c'est le numéro 1 OWASP API Top 10, cas réels, variantes, mitigations par framework, tests, pièges récurrents.

Naim Aouaichia
19 min de lecture
  • API Security
  • BOLA
  • OWASP API Top 10
  • Authorization
  • IDOR
  • AppSec
  • Pentest

BOLA - Broken Object Level Authorization est la vulnérabilité numéro 1 du OWASP API Security Top 10 depuis 2019. Elle consiste à autoriser l'accès à un objet (facture, commande, profil, document) sur la seule base de son identifiant, sans vérifier que l'utilisateur authentifié est légitimement autorisé sur cet objet précis. Résultat : chaque incident majeur API récent contient une BOLA quelque part dans la chaîne. Ce guide explique la mécanique, présente les cas réels, détaille les variantes méconnues, et donne les mitigations par framework avec code.

1. Définition précise

1.1 Formulation OWASP

"Broken Object Level Authorization occurs when an API endpoint that receives an object identifier (directly from the user input or implicitly) returns data for an object or performs an action on an object without verifying that the authenticated user is permitted to access or modify that specific object."

Décomposition :

  • Un endpoint reçoit un identifiant d'objet (dans l'URL, le body, une query string).
  • L'endpoint récupère l'objet par cet identifiant.
  • L'endpoint vérifie que l'utilisateur est authentifié.
  • L'endpoint ne vérifie pas que l'utilisateur est autorisé sur cet objet spécifique.

L'utilisateur est bien celui qu'il prétend être, mais accède à un objet qui ne lui appartient pas.

1.2 BOLA vs IDOR

IDOR (Insecure Direct Object Reference) est le terme historique utilisé par OWASP dans le Top 10 web. BOLA est le terme adopté pour la version API. Les deux décrivent essentiellement le même phénomène, avec BOLA plus récent et plus spécifique aux API.

Dans la pratique : IDOR = vocabulaire pentester généraliste, BOLA = vocabulaire API security moderne. Inter-changeables dans la majorité des contextes.

1.3 Pourquoi c'est le #1

Chiffres observés :

  • Plus de 40 % des API testées en pentest contiennent au moins un BOLA (Salt Security 2023).
  • 30 % des incidents API publics 2020-2024 recensés par Salt Labs et Traceable impliquent un BOLA primaire ou comme étape clé.
  • Les exploits sont triviaux : changer un ID dans l'URL, aucune compétence technique avancée requise.
  • Les impacts sont massifs : un seul endpoint vulnérable permet l'énumération complète des données.

2. La mécanique - comment ça arrive

2.1 Le pattern ORM qui piège

Code vulnérable typique :

@app.get("/api/invoices/{invoice_id}")
async def get_invoice(
    invoice_id: int,
    current_user: User = Depends(get_current_user)
):
    invoice = Invoice.objects.get(id=invoice_id)
    return invoice

Ce code :

  • Vérifie l'authentification via Depends(get_current_user).
  • Charge l'invoice par ID.
  • Retourne l'invoice sans vérifier le propriétaire.

Alice authentifiée peut accéder à toute invoice, y compris celles de Bob, Charlie, et des 500 000 autres clients.

2.2 Pourquoi ce pattern est si courant

Trois raisons :

  1. Les frameworks simplifient l'authentification (middleware, decorators). Les développeurs considèrent que "authentifié = vérifié" par habitude.
  2. La logique d'autorisation est métier, donc repose sur chaque développeur pour être implémentée. Il n'y a pas de framework standard "vérifier l'ownership".
  3. Les tests unitaires testent le path heureux : Alice accède à sa facture, la réponse est 200. BOLA = Alice accède à la facture de Bob, la réponse est aussi 200 mais personne ne teste ce scénario.

2.3 Les patterns d'URL BOLA-risqués

  • GET /api/users/{id} : voir profil.
  • GET /api/users/{id}/orders : voir commandes d'un user.
  • GET /api/organizations/{org_id}/members : liste membres d'une org.
  • PUT /api/documents/{doc_id} : modifier document.
  • DELETE /api/posts/{post_id} : supprimer post.
  • GET /api/bookings/{booking_ref} : voir réservation par référence.

Tout endpoint avec un {id} ou une référence exposée dans l'URL est suspect jusqu'à preuve du contraire.

3. Cas réels marquants

3.1 USPS - 60 millions de records (2018)

L'API interne sur usps.com exposait un endpoint de package tracking qui acceptait n'importe quel ID utilisateur. Un utilisateur USPS authentifié pouvait récupérer l'ensemble des données personnelles de tous les autres utilisateurs via modification d'ID. Révélé en 2018 par Brian Krebs, correction immédiate après signalement. 60 millions de records accessibles sans aucune compétence technique.

3.2 Peloton - 3 millions de profils (2021)

Un endpoint API retournait les données de profil d'un utilisateur même sans authentification, si on connaissait l'ID. 3 millions de profils avec âge, sexe, poids, ville, historique d'entraînement exfiltrables via script simple. Broken Authentication + BOLA combinés.

3.3 Parler - dump complet (2021)

Après l'interdiction de Parler post-6 janvier, un chercheur a découvert que l'API exposait les posts par ID séquentiel sans vérification d'accès. Un script Python de quelques lignes a téléchargé 70 TB de contenu, y compris les posts supprimés et les metadata EXIF des photos (géolocalisation).

3.4 Facebook (plusieurs incidents 2019-2022)

Plusieurs bugs BOLA chez Facebook :

  • Bug phone number search (2019) : recherche par numéro de téléphone exposait le user ID associé. Combiné avec une autre API, énumération de 533 millions de profils.
  • Admin groups takeover (2021) : API interne permettait de promouvoir son compte comme admin d'un groupe arbitraire sans vérification.

3.5 Optus (Australie, 2022) - 10 millions

API "publique" chez l'opérateur télécom australien, accessible sans auth, qui retournait des données clients via ID. Un attaquant a exfiltré 10 millions de records (40 % de la population australienne). L'existence même de l'endpoint était un oubli de gouvernance (Improper Inventory + BOLA).

3.6 Dell (mai 2024) - 49 millions

Enregistrement de faux comptes partenaires Dell, accès à l'API partenaires sans rate limiting adapté, énumération séquentielle des IDs customer → 49 millions de records exfiltrés en plusieurs semaines.

3.7 Schéma récurrent

Aucun cas ci-dessus n'implique de 0-day, d'exploit sophistiqué ou de tool avancé. Juste une URL avec un ID, un outil comme curl/Python requests, et un attaquant patient.

C'est ce qui rend BOLA si dangereux : barrière d'entrée basse, impact massif, détection difficile.

4. Les variantes de BOLA

4.1 BOLA horizontal classique

Utilisateur A accède aux données de l'utilisateur B de même rôle. Le cas de base : /api/users/{id} avec user_id différent.

4.2 BOLA via nested resources

GET /api/users/{user_id}/orders/{order_id}

L'application vérifie peut-être user_id contre le token, mais n'ajoute pas que order_id appartient à ce user. Un attaquant peut faire :

GET /api/users/MY_ID/orders/VICTIM_ORDER_ID

L'URL semble légitime (mon user_id), mais l'order n'est pas à moi. Si le serveur ne filtre pas order.user_id == MY_ID, BOLA.

4.3 BOLA via query parameters

GET /api/documents?folder_id=123&include_shared=false

Si l'application retourne les documents du folder_id 123 sans vérifier que le folder appartient à l'utilisateur, BOLA via query param.

4.4 BOLA via search/filter abuse

GET /api/invoices?filter[customer_id]=78901

Les APIs de filtering/search sont particulièrement vulnérables : le développeur pense "le user va filtrer sur ses propres customer_id", l'attaquant met le customer_id de quelqu'un d'autre.

4.5 BOLA via batch/bulk endpoints

POST /api/documents/bulk-delete
Body: {"ids": [1001, 1002, 1003, ...]}

L'application boucle sur les IDs et les supprime. Si la vérification d'ownership n'est pas faite par ID dans la boucle, un attaquant peut supprimer les documents d'autres utilisateurs en les listant dans le batch.

4.6 BOLA via nested updates

PUT /api/orders/{order_id}
Body: {
  "status": "cancelled",
  "customer_id": 456
}

L'application accepte le body complet et update. Si elle update customer_id (vulnérabilité BOPLA combinée) ou si elle ne vérifie pas que le order_id appartient au current user, BOLA.

4.7 BOLA via rewind / history

Endpoints historiques :

GET /api/documents/{doc_id}/versions/{version}

L'application vérifie peut-être les permissions sur le document actuel mais pas sur les versions anciennes. Un attaquant accède à une version antérieure où le contenu sensible était encore présent.

4.8 BOLA via export endpoints

GET /api/reports/{report_id}/export?format=csv

Les endpoints d'export oubliés dans la matrice de permissions alors que les endpoints de lecture sont protégés.

4.9 BOLA via API interne utilisée par admins

Une API interne que l'équipe admin utilise finit exposée "car le frontend en a besoin". Le contrôle d'admin dépend du frontend qui masque les boutons. L'attaquant appelle l'API directement avec son user standard.

4.10 BOLA dans GraphQL

GraphQL n'échappe pas :

query GetUserDocuments($userId: ID!) {
  user(id: $userId) {
    documents {
      id
      title
      content
    }
  }
}

Si le resolver user ne vérifie pas que userId correspond au current user, BOLA. Les architectures GraphQL sont particulièrement concernées car le schéma central masque la multitude d'endpoints vulnérables.

5. Mitigations détaillées

5.1 Filter by user dans la requête

Pattern recommandé : intégrer la contrainte utilisateur directement dans la requête DB, pas en vérification post-chargement.

Python / SQLAlchemy :

@app.get("/api/invoices/{invoice_id}")
async def get_invoice(
    invoice_id: int,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    invoice = db.query(Invoice).filter(
        Invoice.id == invoice_id,
        Invoice.customer_id == current_user.id
    ).first()
    if not invoice:
        raise HTTPException(status_code=404, detail="Not found")
    return invoice

Bénéfices :

  • Si l'invoice n'existe pas ou n'appartient pas à l'user : même 404.
  • Pas de fuite d'existence.
  • La logique d'autorisation est dans la requête, difficile à oublier en refactor.

5.2 Check explicite post-chargement

Moins idéal mais acceptable si l'ORM rend le filter difficile :

invoice = Invoice.objects.get(id=invoice_id)
if invoice.customer_id != current_user.id:
    raise HTTPException(status_code=404, detail="Not found")
return invoice

Toujours retourner 404, pas 403, pour ne pas révéler l'existence.

5.3 Row-Level Security (RLS) au niveau DB

Défense en profondeur : même en cas d'oubli côté code, la DB refuse.

ALTER TABLE invoices ENABLE ROW LEVEL SECURITY;
 
CREATE POLICY user_invoices ON invoices
  FOR ALL TO api_service
  USING (customer_id = current_setting('app.current_user_id')::int);

L'application exécute SET app.current_user_id = <user_id> en début de transaction. Même une requête SQL malveillante (via injection) respecte la policy.

Supporté par : PostgreSQL (mature), SQL Server, Oracle. MySQL nécessite workaround avec vues.

5.4 Middleware d'autorisation générique

Créer un middleware qui vérifie l'ownership basé sur métadata :

@require_ownership(resource_type=Invoice, id_param="invoice_id", owner_field="customer_id")
@app.get("/api/invoices/{invoice_id}")
async def get_invoice(invoice_id: int):
    invoice = Invoice.objects.get(id=invoice_id)
    return invoice

Le decorator require_ownership charge l'objet, vérifie le propriétaire, et échoue sinon. Appliqué systématiquement, il bloque les oublis.

5.5 Policy engine externalisé

OPA ou Cedar pour externaliser la logique :

package authz.api
 
default allow = false
 
# Lecture de son propre invoice
allow if {
  input.action == "read"
  input.resource.type == "invoice"
  input.user.id == input.resource.customer_id
}
 
# Lecture par admin
allow if {
  input.action == "read"
  input.resource.type == "invoice"
  "admin" in input.user.roles
}
 
# Lecture par manager de l'organisation
allow if {
  input.action == "read"
  input.resource.type == "invoice"
  input.user.org_id == input.resource.organization_id
  "manager" in input.user.roles
}

L'API demande à OPA "ce user peut-il faire cette action sur cet objet ?" à chaque requête.

Voir autorisation d'API : les bases pour approfondissement.

5.6 UUIDs vs integers

Utiliser des UUIDs au lieu d'integer auto-increment pour les IDs exposés :

  • Empêche l'énumération triviale (pas de /invoices/1, /invoices/2, ...).
  • Ne remplace pas la vérification d'ownership.

UUID = défense en profondeur, pas mitigation primaire. Un attaquant qui connaît un UUID (fuité, partagé via lien, scrapé d'un header HTTP) peut toujours accéder si l'authz est absente.

5.7 Séparation Read vs Write endpoints

Endpoints de lecture publics (liste de catalogues, articles) vs endpoints de lecture privés (données utilisateur). Séparer les préfixes :

  • /api/public/* : lecture publique, auth optionnelle.
  • /api/users/me/* : données du user courant uniquement (jamais de {user_id}).
  • /api/admin/* : admin only.

Cette ségrégation rend les oublis plus visibles.

6. Tests BOLA en CI

6.1 Test unitaire par endpoint

Pour chaque endpoint avec ID, tests :

def test_get_invoice_as_owner(client, owner_token, invoice_owned):
    response = client.get(
        f"/api/invoices/{invoice_owned.id}",
        headers={"Authorization": f"Bearer {owner_token}"}
    )
    assert response.status_code == 200
 
def test_get_invoice_as_other_user(client, other_token, invoice_owned):
    response = client.get(
        f"/api/invoices/{invoice_owned.id}",
        headers={"Authorization": f"Bearer {other_token}"}
    )
    assert response.status_code == 404  # pas 403 : on ne révèle pas l'existence
 
def test_get_invoice_as_admin(client, admin_token, invoice_owned):
    response = client.get(
        f"/api/invoices/{invoice_owned.id}",
        headers={"Authorization": f"Bearer {admin_token}"}
    )
    assert response.status_code == 200
 
def test_get_invoice_unauthenticated(client, invoice_owned):
    response = client.get(f"/api/invoices/{invoice_owned.id}")
    assert response.status_code == 401

6.2 Tests automatisés multi-endpoints

Framework de test qui, pour chaque endpoint avec {id} dans la route, tente automatiquement :

  1. Accès avec token A, ID d'objet appartenant à A → attend 200.
  2. Accès avec token A, ID d'objet appartenant à B → attend 404/403.
  3. Accès avec token B, ID d'objet appartenant à A → attend 404/403.

Outils :

  • Burp Suite + extension Autorize : pour tests interactifs, rejoue chaque requête avec session alternative et compare les réponses.
  • Akto : open source, scan automatique avec 2+ users.
  • APIsec : plateforme commerciale dédiée.
  • 42Crunch API Testing : scan CI basé sur OpenAPI.

6.3 Tests à l'échelle

Pour les grandes applications, lister programmatiquement tous les endpoints (via OpenAPI) et tester BOLA automatiquement :

def test_all_id_endpoints_prevent_bola(openapi_spec):
    for path, methods in openapi_spec["paths"].items():
        if "{" in path:  # endpoint avec path param
            for method in methods:
                # tester avec user A sur ressource user B
                assert_bola_blocked(method, path)

6.4 Red team dédié BOLA

Au-delà des tests automatisés, exercice red team annuel :

  • Scénario : un user authentifié cherche à extraire le maximum de données d'autres users.
  • Temps : 2-5 jours.
  • Livrable : liste des endpoints vulnérables + chemins d'exploitation + volume de données accessibles.

Révèle les BOLA que les tests automatisés ratent (logic abuse, chaines d'appels).

7. Pièges récurrents

7.1 Middleware d'authentification confondu avec autorisation

# Middleware global
app.use(authenticate)  # vérifie le token
 
# Endpoint - AUCUN check d'ownership
@app.get("/api/invoices/{id}")
def get_invoice(id: int):
    return Invoice.objects.get(id=id)

Authentification OK, autorisation inexistante. BOLA immédiat.

7.2 Vérification de l'user_id depuis le body

@app.put("/api/users/{user_id}")
def update_user(user_id: int, body: dict):
    if user_id == body.get("user_id"):
        return update(user_id, body)
    raise HTTPException(403)

L'attaquant envoie user_id=456 dans l'URL et user_id: 456 dans le body même s'il est user 123. Le check compare les inputs entre eux, pas avec le token.

Règle : toujours comparer avec current_user.id issu du token JWT, jamais avec de l'input utilisateur.

7.3 Confiance dans l'UI pour masquer les endpoints

"Le user standard n'a pas le bouton dans l'UI pour voir les invoices des autres, donc c'est protégé." Faux. L'attaquant appelle l'API directement via curl/Postman/script, l'UI est inexistante pour lui.

7.4 Vérification après chargement avec timing fuite

invoice = Invoice.objects.get(id=invoice_id)  # log "loaded invoice X"
if invoice.customer_id != current_user.id:
    raise HTTPException(403)

Même si la vérification est là, le simple chargement fuite l'existence via :

  • Timing de réponse différent (existe vs n'existe pas).
  • Logs qui montrent l'existence.
  • Métriques applicatives.

Mitigation : filter dès la requête DB, timing constant.

7.5 Endpoint admin réutilisé par frontend

Un endpoint /api/admin/users/{id}/details utilisé à la fois par l'interface admin et, par commodité, par le frontend user qui "a besoin des mêmes données". Le check admin est retiré pour que le frontend user y accède. BOLA + BFLA combinés.

Mitigation : créer deux endpoints distincts, /api/admin/users/{id} (admin only) et /api/users/me (user only).

7.6 Refactor qui casse les ownership checks

Lors d'un refactor pour réutiliser du code :

def _get_invoice_internal(invoice_id):
    # réutilisable
    return Invoice.objects.get(id=invoice_id)
 
def get_invoice_for_user(invoice_id, user):
    invoice = _get_invoice_internal(invoice_id)
    if invoice.customer_id != user.id:
        raise HTTPException(403)
    return invoice
 
def get_invoice_for_admin(invoice_id, admin):
    return _get_invoice_internal(invoice_id)
 
# Nouvel endpoint qui appelle _get_invoice_internal directement par oubli
@app.get("/api/invoices/{invoice_id}/export")
def export_invoice(invoice_id: int, user: User = Depends(get_current_user)):
    return export(_get_invoice_internal(invoice_id))

Le nouvel endpoint oublie le check user. Mitigation : rendre _get_invoice_internal privé, exiger que tous les callers passent par une méthode avec check explicite.

7.7 BOLA caché dans une relation ORM

invoice = Invoice.objects.filter(id=invoice_id, customer_id=current_user.id).first()
# OK
return invoice.related_documents.all()

L'invoice est bien vérifiée, mais related_documents peut contenir des documents partagés avec d'autres clients (mal modélisés). Vérification requise aussi sur la relation.

7.8 BOLA via réponse d'un endpoint admin

Endpoint admin légitime /api/admin/logs retourne des logs contenant IDs, emails, IPs d'autres users. Un admin compromis ou malveillant peut extraire des infos sur tous les users via un endpoint légitime.

Mitigation : audit trail des accès admin aux logs, minimization des données loguées, PAM pour accès admin (voir sécurité des comptes privilégiés).

8. BOLA dans GraphQL - spécificités

8.1 Le risque démultiplié

GraphQL regroupe toutes les API sous un endpoint unique. Une vulnérabilité BOLA peut toucher plusieurs resolvers en même temps.

8.2 Pattern vulnérable

const resolvers = {
  Query: {
    user: async (_, { id }, context) => {
      return context.db.user.findUnique({ where: { id } });
    },
    documents: async (_, { userId }, context) => {
      return context.db.document.findMany({ where: { userId } });
    }
  }
};

Aucune vérification que id ou userId correspond au current user.

8.3 Mitigation GraphQL

Autorisation par resolver, pas global :

const resolvers = {
  Query: {
    user: async (_, { id }, context) => {
      if (id !== context.user.id && !context.user.isAdmin) {
        throw new ForbiddenError("Not authorized");
      }
      return context.db.user.findUnique({ where: { id } });
    }
  }
};

Solutions librairies :

  • graphql-shield : middleware d'autorisation déclaratif.
  • @graphql-auth/ packages*.
  • Nexus plugin authorize.

8.4 Audit GraphQL

  • Introspection désactivée en prod (ne pas faciliter la cartographie attaquant).
  • Query depth limit.
  • Query complexity analysis.
  • Tests BOLA par resolver.

9. Mesurer son exposition BOLA

9.1 Métriques pertinentes

  • Nombre d'endpoints avec {id} dans la route vs nombre d'endpoints avec ownership check documenté.
  • Couverture des tests d'autorisation : X endpoints testés avec 2+ users / Y endpoints totaux.
  • Temps entre introduction d'un endpoint et test BOLA en CI : idéalement même PR.
  • Nombre de BOLA découverts par red team / pentest : décroissant.

9.2 Audit initial d'une application existante

  1. Lister tous les endpoints (via OpenAPI ou crawling).
  2. Filtrer ceux avec path parameters ({id}, {slug}, etc.) ou resource IDs dans body/query.
  3. Pour chaque, exécuter un test BOLA manuel ou semi-automatique.
  4. Documenter les findings par criticité.
  5. Prioriser la remediation par criticité des données.

9.3 Approche graduelle

  • Mois 1 : inventaire, tests des 20 endpoints les plus critiques.
  • Mois 2-3 : remediation des findings critiques.
  • Mois 4+ : automatisation des tests BOLA en CI sur tous les endpoints.

10. Plan de remediation d'une application avec BOLA avéré

10.1 Court terme (semaines)

  • Patch immédiat de l'endpoint exposé avec filter-by-user.
  • Notification des personnes impactées si data exposure confirmée.
  • Logs review pour voir si exploitation passée.
  • Déclaration CNIL si données personnelles impactées (72h max en RGPD).

10.2 Moyen terme (mois)

  • Audit des autres endpoints similaires.
  • Middleware de check d'ownership déployé comme pattern standard.
  • Tests BOLA en CI pour tous les endpoints critiques.
  • Formation équipe sur BOLA et patterns de mitigation.

10.3 Long terme

  • Policy engine (OPA, Cedar) pour unifier la logique d'autorisation.
  • Row-Level Security pour défense en profondeur.
  • API security platform avec détection comportementale.
  • Red team exercises réguliers pour valider.

11. Compliance et BOLA

11.1 RGPD

Une fuite de données personnelles via BOLA déclenche les obligations RGPD :

  • Notification CNIL sous 72h.
  • Notification aux personnes concernées si risque élevé.
  • Amende jusqu'à 4 % du CA mondial ou 20 M EUR.

Cas connu : Dedalus (groupe hospitalier français) amende 1,5 M EUR CNIL 2022 pour fuite de données santé notamment liée à des défauts de contrôle d'accès.

11.2 Autres réglementations

  • HIPAA (santé US) : audit trail obligatoire, access controls stricts.
  • PCI-DSS : cardholder data access control strict.
  • NIS 2 (EU) : obligations d'incident reporting.
  • DORA (EU finance, 2025+) : contrôles stricts sur accès aux données.

Un programme de tests BOLA est démontré en audit par :

  • Logs de tests automatisés CI.
  • Rapports de pentests annuels.
  • Documentation des mitigations (policies OPA, code review).
  • Preuves d'incident response.

12. Verdict et posture Zeroday

BOLA est la vulnérabilité d'API #1 non pas parce qu'elle est la plus technique, mais parce qu'elle est la plus banale et la plus répandue. Aucun scanner générique ne la détecte fiablement, aucun WAF ne la bloque, et elle s'introduit à chaque nouvel endpoint si la discipline d'autorisation n'est pas intégrée au workflow de dev.

Pour un développeur : la compétence à développer est réflexe d'ownership check sur chaque endpoint. Un handler qui reçoit un ID doit, en toute circonstance, intégrer la vérification dans la requête DB ou juste après. Pas d'exception.

Pour un AppSec : la mission est d'industrialiser les tests BOLA (CI automatisé avec 2 users, Autorize Burp dans les pentests, OPA pour la logique, red team trimestriel). Le but : rendre quasi impossible l'introduction silencieuse d'un BOLA en prod.

Pour un pentester : maîtriser le test BOLA systématique (pas juste sur les endpoints "intéressants" mais sur tous avec path param) est la signature d'un pentest API sérieux. C'est aussi le finding le plus payant quand il est trouvé : impact massif, exploitation triviale, report client mémorable.

Pour approfondir : OWASP API Security Top 10 expliqué pour situer BOLA dans le paysage, autorisation d'API : les bases pour la théorie authorization et les policy engines, broken access control pour le pattern générique dont BOLA est une déclinaison API, pourquoi les API sont attaquées pour le contexte stratégique.

Écrit par

Naim Aouaichia

Expert cybersécurité et fondateur de Zeroday Cyber Academy

Expert cybersécurité avec un master spécialisé et un parcours hybride : développement, DevOps, DevSecOps, SOC, GRC. Fondateur de Hash24Security et Zeroday Cyber Academy. Formateur et créateur de contenu technique sur la cybersécurité appliquée, la sécurité des LLM et le DevSecOps.