Introduction : Pourquoi les API sans serveur exigent un nouveau jeu d'esprits de sécurité

En abstractionnant la gestion de l'infrastructure, les équipes peuvent se concentrer sur le code tandis que les fournisseurs comme AWS Lambda, Azure Functions et Google Cloud Functions gèrent l'échelle, le patching et le temps de disponibilité. Cependant, ce changement introduit également un ensemble distinct de défis de sécurité. Les défenses traditionnelles basées sur le périmètre ne s'appliquent plus; la surface d'attaque s'étend pour inclure des services tiers, des sources d'événements et des autorisations à grain fin.

Cet article explore les menaces les plus courantes auxquelles font face les API sans serveur et fournit des pratiques exemplaires réalisables et prêtes à être mises en œuvre pour les atténuer. Que vous migrez les paramètres existants ou en construisiez de nouveaux, ces stratégies vous aideront à protéger vos données, à maintenir la disponibilité et à rester conforme aux normes de l'industrie.

Comprendre les menaces communes aux API sans serveur

Les API sans serveur sont vulnérables aux mêmes grandes catégories d'attaque que les API traditionnelles – injection, authentification cassée, exposition aux données – mais les détails de mise en œuvre diffèrent en raison de la nature éphémère des fonctions, de l'utilisation de déclencheurs déclenchés par des événements et de la dépendance à l'égard des services gérés.

Attaques d'injection : plus que SQL

Dans les fonctions sans serveur, le danger est amplifié car les fonctions acceptent souvent les entrées de plusieurs sources : requêtes HTTP, flux de bases de données, messages de file d'attente, événements de stockage d'objets, etc. Si une fonction ne valide pas ou ne s'infecte pas cette entrée, un attaquant peut injecter du code malveillant ou des commandes. Par exemple, une API qui accepte un ID utilisateur et l'utilise directement dans une requête de base de données sans paramétrage pourrait être exploitée pour l'injection NoSQL dans les bases de données relationnelles de MongoDB ou SQL. De même, l'injection de commande peut se produire si l'entrée de l'utilisateur est passée à des commandes système comme dans Python ou dans Node.js.

Un autre vecteur émergent est event injection.Les attaquants peuvent créer des événements malformés (p. ex. un faux événement S3 ou un message de file d'attente manipulé) qui provoquent le comportement inattendu de la fonction ou des fuites de données.

Accès non autorisé et authentification interrompue

Les API sans serveur reposent souvent sur les clés API, les jetons OAuth 2.0 ou la logique d'authentification personnalisée. Une authentification mise en œuvre avec faiblesse permet aux attaquants d'imiter les utilisateurs légitimes ou d'obtenir des privilèges élevés. Un piège commun repose uniquement sur une clé API envoyée dans un en-tête ou un paramètre de requête sans vérifier que la clé est toujours valide ou appartient à un utilisateur actif. De plus, les fonctions peuvent exposer par inadvertance des paramètres qui ne nécessitent pas d'authentification du tout en raison de passerelles API mal configurées. Par exemple, un développeur peut ajouter une nouvelle fonction pour gérer les contrôles de santé internes et oublier de la restreindre derrière un réseau privé ou une authentification, la laissant accessible au public.

Les environnements sans serveur compliquent également l'autorisation parce que la limite entre -user-south et -fonction est floue. Un attaquant qui compromet une fonction pourrait être en mesure d'invoquer d'autres fonctions dans le même compte si les rôles de l'IAM sont trop permissifs. Ceci est connu sous le nom d'escalade des privilèges de fonction-à-fonction.

Données Fuite et exposition

D'abord, les fonctions logent souvent les paramètres d'entrée et les réponses pour le débogage, si ces journaux sont envoyés à un service central de logarithme avec un large accès, les secrets ou PII peuvent être exposés. Deuxièmement, les messages d'erreur retournés au client peuvent contenir des traces de pile qui révèlent des schémas internes de base de données, des chaînes de connexion ou des identifiants de ressources du cloud. Troisièmement, parce que les fonctions sans serveur sont apatrides, les développeurs stockent fréquemment des données temporaires dans des variables d'environnement ou un stockage temporaire (p. ex. dans AWS Lambda). Si ces valeurs ne sont pas nettoyées ou partagées entre les invocations, les données d'une demande peuvent s'échapper à une autre.

Un autre vecteur subtil : fuite de données sur les canaux latéraux par le biais du timing de la réponse. Un attaquant peut mesurer le temps qu'une fonction prend pour répondre et déduire si un nom d'utilisateur existe dans une base de données, permettant une attaque de dénombrement de force brute.

Refus de service (DoS) et épuisement des ressources

En cas de panne de réseau ou de capacité de serveur, un attaquant peut exploiter le modèle pay-per-use pour provoquer un déni de service financier. En inondant une API avec des requêtes valides mais coûteuses en calcul, il exécute la facture de cloud de la victime pendant que le trafic légitime est tronqué ou abandonné. De plus, de nombreuses plateformes sans serveur ont des limites de convergence (par exemple, 1000 exécutions simultanées par région dans AWS Lambda par défaut).

DoS peut également cibler les dépendances en aval. Si une fonction appelle une API tierce (par exemple, une passerelle de paiement) sans temps d'arrêt ou disjoncteurs appropriés, un service externe lent peut faire accrocher la fonction, en prenant du temps d'exécution et en épuisant le budget de temps d'arrêt de la fonction.

Permissions mal configurées et rôles de MAI surprivilégiés

Les développeurs attachent souvent une politique générale (par exemple, ou ) à une fonction pour la rendre efficace lors du développement, puis oublient de la resserrer dans la production. Un attaquant qui exploite une vulnérabilité à l'injection dans une telle fonction peut alors exécuter toute action que le rôle permet – lire, écrire ou supprimer des données sur plusieurs services AWS. C'est souvent la façon dont des ruptures de données se produisent dans des architectures sans serveur. Une fonction vulnérable unique peut devenir un point pivot pour le mouvement latéral sur les ressources en nuage.

Au-delà de l'IAM, les erreurs de configuration peuvent se produire dans les passerelles API, les paramètres VPC et les services de logarithme. Par exemple, un seau S3 utilisé pour stocker les journaux de fonctions peut être lisible publiquement, ou une étape API Gateway peut avoir des paramètres CORS trop laxiques, permettant ainsi le vol de données cross-origin.

Meilleures pratiques pour sécuriser les API sans serveur

L'atténuation des menaces ci-dessus nécessite une défense en couches qui couvre le développement, le déploiement et le temps d'exécution.

1. Mettre en œuvre une authentification et une autorisation robustes

Pour les API sans serveur, utilisez des protocoles standard comme Oauth 2.0 avec OpenID Connect ou Amazon Cognito[ / Auth0. Évitez de rouler votre propre logique d'authentification sauf si cela est absolument nécessaire. Pour les API machine-à-machine, ne délivrez les clés API longue durée que lorsque la rotation est mise en œuvre et préférez les jetons à courte durée de vie obtenus via un flux sécurisé d'identification client OAuth.

L'autorisation devrait respecter le principe du moins de privilèges à tous les niveaux :

  • Utilisez le contrôle d'accès basé sur les rôles (RBAC) pour cartographier les rôles des utilisateurs vers des paramètres d'API spécifiques ou des permissions de fonction.
  • Mettre en œuvre le contrôle d'accès basé sur les attributs (ABAC)[ pour les décisions à grains fins fondées sur des balises de ressources ou des attributs utilisateurs.
  • Au niveau du cloud, limitez chaque fonction au rôle IAM aux actions et ressources dont il a besoin. Par exemple, si une fonction n'a besoin que de lire à partir d'une table DynamoDB, son rôle devrait permettre sur cette table ARN – rien de plus.

Envisager d'utiliser API Gateway Lambda authors (anciennement les autorisants personnalisés) pour centraliser la validation des jetons et la génération de politiques.

2. Valider et sanitiser toutes les entrées, partout

Traitez chaque entrée comme non fiable, quelle que soit sa source. Ceci inclut les paramètres de requête HTTP, les corps de requête, les en-têtes, les paramètres de chemin et les événements d'autres services (SNS, SQS, S3, etc.). Utilisez une bibliothèque de validation robuste comme Joi (Node.js), Cerberus (Python), ou des validateurs de schéma spécifiques à la langue. Ne concaténez jamais l'entrée de l'utilisateur directement dans les requêtes SQL, les requêtes NoSQL, les commandes shell ou l'évaluation de code dynamique.

Pour les fonctions animées par un événement, validez la structure des événements entrants. Par exemple, si votre fonction traite les notifications d'événements S3, vérifiez que l'événement contient les champs attendus et que le nom du seau correspond à un motif autorisé. Un attaquant pourrait envoyer un faux événement S3 via un paramètre HTTP qui déclenche la fonction.

Si votre API retourne des données fournies par l'utilisateur, échappez-la correctement pour éviter les scripts transsites (XSS) ou d'autres attaques d'injection qui ciblent les consommateurs en aval.

3. Mettre en oeuvre des alertes de limitation des taux, de tolération et de budget

La limitation des taux est essentielle pour prévenir les attaques DoS et les abus de compte. Configurer API Gateway ou une passerelle API tierce pour limiter les requêtes par client (par clé API ou IP) sur une fenêtre coulissante. Pour les fonctions sans serveur qui sont appelées directement (par exemple, via AWS Lambda URL de la fonction), envisager d'utiliser Concurrence réservable pour limiter le nombre d'exécutions simultanées qu'une fonction peut consommer.

Au-delà du grottling, mettez en place des alarmes de facturation et d'utilisation dans votre fournisseur de cloud. Par exemple, créez une alarme CloudWatch qui déclenche lorsque les invocations de Lambda dépassent un certain nombre en une heure ou lorsque les coûts augmentent. Une surtension inattendue des invocations est souvent le premier signe d'une attaque.

4. Chiffrer les données en transit et au repos

Toujours faire appliquer HTTPS pour tous les paramètres de l'API. Utilisez TLS 1.2 ou plus et assurez-vous que les certificats sont valides et correctement configurés. Pour la communication interne entre les fonctions et les bases de données (par exemple, Lambda à RDS), activez le chiffrement en transit avec TLS ou utilisez un VPC avec des sous-réseaux privés et le chiffrement à la couche de transport.

Pour les données sensibles comme les identifiants d'utilisateur ou PII, implémentez le chiffrement au niveau de l'application avant d'écrire au stockage de sorte que même les administrateurs de cloud ne peuvent pas lire le texte clair. AWS Well-Architected for Serverless fournit des conseils détaillés sur le chiffrement.

5. Utiliser les secrets Gestion et hygiène variable de l'environnement

N'utilisez jamais de clés d'API de code dur, de mots de passe de base de données ou d'autres secrets dans le code de fonction ou les fichiers de configuration. Utilisez plutôt un gestionnaire de secrets dédié comme AWS Secrets Manager[, Azure Key Vault[ ou HashiCorp Vault. Récupérez les secrets à l'exécution (de préférence en cache pour éviter les latences répétées) ou injectez-les via des variables d'environnement au moment du déploiement à partir d'une source sécurisée.

Évitez de stocker des secrets dans des variables d'environnement en texte simple qui sont visibles dans la console de cloud ou les journaux CI/CD. Si vous devez utiliser des variables d'environnement, activez le chiffrement pour elles (par exemple, AWS Lambda ne chiffre pas nativement les variables d'environnement à moins d'utiliser l'intégration ou KMS).

6. Surveiller, enregistrer et alerter de façon proactive

La logation et la surveillance centralisées sont essentielles pour détecter les anomalies rapidement. Activer la logation détaillée pour API Gateway (logs d'exécution avec des données de requête/réponse) et pour chaque fonction via des journaux CloudWatch ou l'équivalent. Utilisez la logation structurée pour faciliter l'analyse et les journaux de requête. Cependant, attention à ne pas enregistrer les données sensibles – log de log de nettoyage ou de filtrer des champs comme les mots de passe, les jetons et les informations personnellement identifiables.

Mettre en place des alertes pour les motifs suspects :

  • Erreurs d'épike en 4xx ou 5xx
  • Augmentation inhabituelle des invocations de fonctions à partir d'une seule PI
  • Accès aux ressources que la fonction ne devrait normalement pas atteindre
  • Durée d'exécution élevée ou délais répétés

Envisagez d'utiliser un outil de gestion d'informations et d'événements de sécurité natif du cloud comme AWS GuardDuty pour la détection de menaces spécifiques à un serveur sans serveur, ou une alternative open-source comme Wazuh. AWS GuardDuty pour Lambda peut détecter des fonctions compromises qui tentent de communiquer avec des IP malveillants connus.

7. Dépendances de la fonction sécuritaire et chaîne d'approvisionnement

Les fonctions sans serveur dépendent souvent de paquets tiers (npm, PyPI, NuGet). Ils peuvent introduire des vulnérabilités. Analysez régulièrement vos dépendances en utilisant des outils comme Snyk, [OWASP Dependency-Check[, ou votre fournisseur de cloud , scanner de vulnérabilité.

Envisager d'utiliser couches ou times d'exécutions personnalisées pour contrôler l'environnement d'exécution. Par exemple, les couches AWS Lambda vous permettent d'inclure des bibliothèques sans les regrouper dans le paquet de déploiement, mais la couche elle-même doit être scannée. Implémenter un pipeline CI/CD qui échoue si une dépendance a une vulnérabilité critique connue. OWASP Top Ten est un bon point de départ pour les risques de sécurité de la chaîne d'approvisionnement.

8. Appliquer la défense en profondeur pour les architectures animées par des événements

Les API sans serveur reposent souvent sur des événements asynchrones : fonctions déclenchées par les files d'attente SQS, les sujets SNS, les Streams DynamoDB ou EventBridge. Chaque source d'événements introduit des vecteurs d'attaque potentiels.

  • SQS: Si une fonction consomme depuis une file d'attente, un attaquant pourrait injecter des messages malveillants. Valider les corps de messages et utiliser des files d'attentes de lettres mortes pour isoler les messages malformés pour une analyse ultérieure.
  • DynamoDB Streams: Assurez-vous que seules les applications autorisées peuvent écrire dans le flux; sinon, un attaquant pourrait insérer des événements de changement faux.
  • EventBridge: Restreindre les comptes et les services qui peuvent publier des événements dans votre bus événementiel. Utilisez les modèles d'événements pour filtrer les événements indésirables.

Pour chaque chemin dirigé par un événement, implémentez la validation d'entrée et appliquez les mêmes vérifications d'authentification et d'autorisation que pour les paramètres HTTP.

9. Durcir l'exécution de la fonction et réduire la surface d'attaque

Les fonctions sans serveur doivent être aussi maigres que possible. Supprimez les permissions inutilisées, désactivez les paquets inutiles et évitez d'intégrer des identifiants de longue durée. Utilisez le stockage éphémère () avec précaution : effacez les fichiers temporaires après chaque invocation et ne gardez jamais de secrets là.

Envisagez de déployer des fonctions à l'intérieur d'un VPC s'ils ont besoin d'accéder à des ressources privées, mais soyez conscient que les fonctions internes de VPC perdent accès à des paramètres publics à moins de configurer une passerelle NAT. Sinon, utilisez Les paramètres VPC (AWS PrivateLink) pour accéder à des services comme S3 ou DynamoDB sans traverser l'internet public.

10. Effectuer des vérifications régulières de sécurité et des essais de pénétration

La sécurité n'est pas une configuration unique. Prévoir des examens périodiques des politiques de l'IAM, des configurations de la passerelle API et des journaux de fonctions. Utilisez des outils comme CloudSpOIT, ScoutSuite, ou Prowler[ pour vérifier votre environnement cloud pour détecter les erreurs de configuration.

Par exemple, utilisez Checkov[ ou tfsec[ pour analyser l'infrastructure comme code (Terraform, CloudFormation) pour détecter les motifs non sécurisés, tels que les rôles IAM avec des permissions de wildcard ou des fonctions sans chiffrement.

Conclusion

La sécurisation des API sans serveur ne consiste pas à mettre en place un outil ou un paramètre unique, mais à adopter une approche continue et approfondie de la défense. En comprenant les menaces uniques – l'injection par des événements, les rôles de MAI surprivilégés, le DoS financier et les fuites de données via des journaux – vous pouvez concevoir votre API pour résister aux attaques à chaque couche.

Rappelez-vous que sans serveur change la responsabilité de sécurité : le fournisseur de cloud sécurise l'infrastructure, mais vous devez sécuriser votre code, vos données et vos autorisations.Regardez régulièrement votre architecture en fonction des cadres comme AWS Well-Architected Security Pilier[ ou OWASP Serverless Security Cheat Sheet[. Avec vigilance et automatisation, vous pouvez profiter des avantages de sans serveur – évolutivité, rentabilité et vitesse – sans compromettre la sécurité.