30.10.26
kcgi : sécuriser une application web en C14 min de lecture2 710 mots

kcgi : sécuriser une application web en C

Découvrez kcgi, bibliothèque CGI/FastCGI pour C et C++ : installation, architecture sandboxée, limites et tests pour bâtir une application web plus sûre.

kcgibibliothèque CGI CFastCGI en Csécurité application websandbox processus
kcgi : sécuriser une application web en C

kcgi : une bibliothèque C pour des applications web plus sûres

Le langage C n'est pas le premier choix pour un service web. Et pourtant, il reste pertinent dans certains cas : logiciels système, outils compacts, environnements contraints, ou applications où l'on veut maîtriser finement les dépendances et l'exécution. Le vrai point délicat, lui, est ailleurs : une requête HTTP n'est jamais fiable, et l'analyser expose le programme à des données malformées.

C'est justement sur ce terrain que s'appuie kcgi : une bibliothèque open source pour écrire des applications web en C (ou en C++), compatibles avec CGI et FastCGI. Son apport ne se limite pas à renvoyer une réponse HTTP. Elle isole le traitement des entrées réseau du reste du programme, grâce à un mécanisme de sandboxing. Résultat : une erreur sur le parsing peut avoir moins de conséquences. Mais il ne faut pas se raconter d'histoires - ça ne dispense pas d'écrire et de déployer l'application correctement.

Dans la suite : comprendre kcgi, l'installer, écrire une première réponse, choisir entre CGI et FastCGI, puis évaluer les coûts et les limites avant de l'intégrer à un projet.

À quoi sert kcgi ?

kcgi fournit les briques pour recevoir une requête HTTP, en extraire les éléments et renvoyer une réponse depuis un programme C ou C++. La bibliothèque gère CGI et FastCGI : dans les deux cas, l'application est exécutée via un serveur web (ou un composant) qui lui transmet les requêtes.

Le principal intérêt est simple : éviter de réécrire, à chaque projet, toute la plomberie autour de HTTP. kcgi gère notamment les paramètres de requête, les cookies, le corps des requêtes et les formulaires multipart. On y trouve aussi des fonctions pour la compression automatique, l'authentification, la mise en cache des réponses, le diagnostic des requêtes et des sorties en formats comme JSON ou XML.

Mais attention au piège classique : kcgi fournit une infrastructure, pas une sécurité « magique ». Le travail reste le vôtre sur le traitement métier, l'autorisation, la gestion des erreurs et la façon dont les données sont réutilisées ou affichées.

Pourquoi choisir une bibliothèque dédiée ?

Au début, une application web en C peut sembler presque triviale : lire des variables d'environnement, analyser une chaîne, écrire quelques en-têtes et renvoyer du texte. Le problème arrive vite quand il faut couvrir plusieurs méthodes HTTP, gérer les encodages, les cookies, les corps de requête, et les cas invalides. Les erreurs « isolées » finissent par coûter cher : en maintenance, mais aussi parce qu'elles deviennent une surface d'attaque.

Une bibliothèque dédiée apporte une structure commune et des fonctions documentées pour ces opérations. Avec kcgi, le parsing de la requête passe par khttp_parse en CGI. En FastCGI, l'initialisation et le traitement sont séparés entre khttp_fcgi_init et khttp_fcgi_parse.

Pour la référence, on s'appuie sur les pages de manuel, notamment kcgi(3). Sur un projet réel, elles comptent plus qu'un extrait de code : elles précisent les contrats des fonctions, les paramètres et le cycle de vie des requêtes.

Pour quels projets est-ce adapté ?

kcgi vaut le coup si votre équipe travaille déjà en C ou en C++, si votre cible de déploiement est compatible avec CGI ou FastCGI, et si isoler le traitement d'entrées non fiables fait partie de vos exigences. La bibliothèque a été portée sur plusieurs Unix, dont GNU/Linux, les BSD, Solaris et macOS.

En revanche, c'est moins intéressant si votre objectif principal est de livrer rapidement un service web « standard », sans contrainte liée au langage. Dans ce cas, le coût d'exploitation (et le recrutement autour de la pile C) peut dépasser le bénéfice. Le bon critère, ce n'est pas le prestige technique : c'est l'adéquation entre vos compétences, votre modèle d'hébergement, vos besoins de sécurité et la durée de vie du service.

Comment fonctionne son modèle de sécurité ?

Le point central mis en avant par kcgi est le parsing dans un processus enfant sandboxé. L'idée est simple : le processus qui reçoit les données non fiables a des capacités limitées. Ensuite seulement, les données traitées sont transmises au processus parent via une socket.

On peut voir ça comme une variante de la réduction de privilèges : si une faille exploitable apparaît dans le chemin de parsing, elle se retrouve dans un environnement plus restreint que le reste de l'application. Ça n'empêche pas l'erreur d'exister, mais ça limite sa portée.

Le sandboxing dépend de votre système : il s'appuie sur ce que la plateforme sait faire (limites de ressources, restrictions de processus, etc.). Le détail varie donc selon l'OS et votre configuration. Le point important, c'est que votre équipe doit vérifier ce qui est réellement activé en production, plutôt que de prendre le mot « sandbox » comme une garantie universelle.

Séparer le parsing du traitement métier

Le flux logique ressemble à ceci :

  1. Le serveur web transmet une requête CGI ou FastCGI.
  2. kcgi analyse les données HTTP et applique les validations dans le contexte sandboxé.
  3. Les éléments traités sont envoyés au processus parent.
  4. L'application exécute la logique métier et construit la réponse.
  5. La requête est libérée avec khttp_free.

Cette séparation demande un minimum de discipline. Les validations faites dans le processus sandboxé doivent rester prévisibles, sans s'appuyer sur des ressources externes. Si une validation doit ouvrir un fichier, contacter un service réseau ou consulter un état système, ça risque de ne pas coller aux restrictions du sandbox. Dans ce cas, séparez clairement la validation « syntaxique » de la validation « métier » qui dépend de l'environnement.

Par exemple : vérifier qu'un identifiant ne contient que des caractères autorisés, c'est une validation locale. Vérifier ensuite que cet identifiant correspond à un compte actif dans une base de données, c'est autre chose : ça dépend d'un service externe et des règles d'autorisation.

Ce que le sandbox ne règle pas

Le sandboxing ne remplace pas l'échappement des sorties, le contrôle des droits, ni la protection contre les erreurs métier. Même si la valeur est correctement analysée, elle peut rester dangereuse si vous l'insérez sans précaution dans du HTML, une commande ou une requête SQL. De la même façon, une requête valide côté HTTP peut demander une action que l'utilisateur n'a pas le droit de faire.

Donc, il faut garder une approche en couches :

  • Parser les données avec une bibliothèque éprouvée.
  • Valider leur format et leurs limites.
  • Autoriser l'action selon l'identité et le contexte.
  • Échapper/encoder selon la destination.
  • Limiter les privilèges du processus et les dépendances.
  • Tester les erreurs, pas seulement le scénario nominal.

Pour aller plus loin sur ces réflexes, vous pouvez aussi consulter la sécurisation d'une application web et la validation des entrées côté serveur. L'isolation apportée par kcgi complète ces pratiques, elle ne les remplace pas.

Installer et écrire une première application

Avant de coder, vérifiez si kcgi est disponible dans les dépôts de votre système. La documentation cite par exemple pkg_add kcgi sur OpenBSD, pkg install kcgi sur FreeBSD, brew install kcgi avec Homebrew et pacman -S kcgi sur Arch Linux. Les commandes exactes et les versions dépendent des dépôts configurés.

Si aucun paquet ne convient, le projet fournit une archive et des instructions de compilation. Dans ce cas, vérifiez l'archive avec la somme SHA-512 fournie. Pour une version de développement entre deux sorties, le dépôt est sur son site officiel. La compilation dépend surtout de BSD make (bmake sur Linux) et de zlib. Les tests de régression nécessitent aussi libcurl.

Compiler et lier le programme

Une fois la bibliothèque installée, pkg-config vous aide à récupérer les options de compilation et d'édition de liens :

cc `pkg-config --cflags kcgi` -c votreprogramme.c

cc votreprogramme.o `pkg-config --libs kcgi` -o votreprogramme

Le détail peut changer selon votre environnement, mais l'objectif reste le même : éviter de recopier à la main les chemins d'inclusion et les bibliothèques nécessaires. Sur un projet maintenu, gardez ces options dans votre système de build, pas dans des commandes éparpillées.

Certains serveurs web tournent dans un chroot. Dans ce scénario, un binaire dynamique peut ne pas trouver ses bibliothèques partagées dans l'environnement isolé. Deux options : intégrer les bibliothèques dans la racine du service, ou produire un binaire statique si la plateforme et votre politique de distribution le permettent. La liaison statique peut simplifier le déploiement, mais elle complique aussi la gestion des mises à jour. Choisissez selon votre mode d'exploitation, pas « par défaut ».

Le cycle de vie d'une réponse CGI

Voici un exemple minimal inspiré de la documentation. Il déclare une page connue, analyse la requête, écrit les en-têtes HTTP, démarre le corps de réponse, puis libère les ressources :

#include <sys/types.h>

#include <stdarg.h>

#include <stddef.h>

#include <stdint.h>

#include <kcgi.h>

int main(void) {

struct kreq r;

const char *page = "index";

if (khttp_parse(&r, NULL, 0, &page, 1, 0) != KCGI_OK)

return 1;

khttp_head(&r, kresps[KRESP_STATUS], "%s", khttps[KHTTP_200]);

khttp_head(&r, kresps[KRESP_CONTENT_TYPE], "%s",

kmimetypes[KMIME_TEXT_PLAIN]);

khttp_body(&r);

khttp_puts(&r, "Bonjour, monde !");

khttp_free(&r);

return 0;

}

L'exemple est volontairement minimal : il ne valide pas de champs utilisateurs et renvoie toujours une réponse texte. Dans une vraie application, vous devrez gérer les méthodes HTTP, les routes demandées, les erreurs de parsing et le type de contenu. L'ordre compte : les en-têtes doivent être émis avant d'appeler khttp_body.

Le projet fournit aussi des exemples C++, CGI et FastCGI. Pour une intégration réelle, partez de l'exemple correspondant au mode de déploiement choisi, au lieu de transposer mécaniquement ce CGI minimal.

Tester, déployer et évaluer les compromis

kcgi inclut un cadre de tests de régression exécutable via make regress. Le principe est pratique : ça ressemble à un petit serveur local qui transforme un document HTTP en requête CGI minimale, puis la transmet à un client de test kcgi. Les cas internes sont construits avec libcurl. Le port d'écoute est fixe dans ce dispositif : pensez à vérifier qu'il est disponible dans votre environnement d'intégration continue.

Ces tests sont utilisés dans les workflows d'intégration continue du projet, sur plusieurs systèmes pris en charge, avec des options de sanitization à la compilation. Il existe aussi une cible liée à American Fuzzy Lop pour soumettre les parseurs à des entrées générées. Le fuzzing ne remplace pas les tests fonctionnels, mais c'est particulièrement utile pour du code qui manipule des formats réseau et des entrées malformées.

CGI ou FastCGI : choisir le bon mode

En CGI, le serveur web lance un processus pour traiter une requête. C'est simple à intégrer, mais le coût de création et d'arrêt des processus peut vite devenir un facteur limitant sous charge. En FastCGI, un processus (ou un gestionnaire) peut traiter plusieurs requêtes : le coût et le cycle de vie du service changent du tout au tout.

Le bon choix dépend donc de l'architecture d'hébergement. Certains serveurs lancent directement les applications FastCGI ; d'autres passent par un gestionnaire externe. La documentation kcgi mentionne notamment des déploiements avec Apache, nginx et httpd(8) d'OpenBSD. Avec ce dernier, FastCGI peut être associé à kfcgi(8) ou au wrapper slowcgi, selon le montage.

Ne comparez pas CGI et FastCGI uniquement sur le nombre de requêtes par seconde. Regardez aussi la supervision, le redémarrage, l'isolation, la configuration des sockets, la qualité des journaux et la façon dont les secrets sont transmis. Une option « plus rapide » sur le papier peut coûter plus cher à exploiter si l'équipe ne maîtrise pas le cycle de vie.

Le prix de la sécurité et les points de contrôle

Isoler le parsing sandboxé a un coût. kcgi doit créer un processus enfant, appliquer les restrictions de la plateforme, puis transmettre au parent les éléments analysés. En CGI, la création et la récupération de processus peuvent peser. En FastCGI, le transfert des données devient un point à mesurer.

Il n'y a pas de formule magique universelle. Les performances dépendent du système, du serveur web, de la taille des requêtes, de la fréquence des appels et du travail effectué après le parsing. Le mieux est de mesurer sur votre cible de production avec des données représentatives. Un test local sur une machine de développement ne suffit pas pour estimer le comportement sous charge.

Avant de passer en production, vérifiez au minimum :

  • la version de la bibliothèque et la provenance des paquets ou des archives ;
  • la vérification de l'archive si vous compilez depuis les sources ;
  • le serveur web et le mode CGI/FastCGI réellement configurés ;
  • les restrictions effectivement appliquées au processus sandboxé ;
  • le comportement en cas de requête invalide, de timeout ou d'échec du processus ;
  • la journalisation, la supervision et la stratégie de redémarrage ;
  • les résultats des tests de régression et, si pertinent, du fuzzing ;
  • les performances mesurées avec le trafic et les tailles de requêtes attendus.

Au final, la décision est pragmatique : si l'isolation des entrées non fiables répond à un risque concret et que votre équipe sait exploiter la pile, le surcoût peut être justifié. Si vous n'avez ni contrainte C/C++ ni exigences spécifiques de déploiement, une autre approche sera souvent plus simple à maintenir. La sécurité « utile » est celle que vous pouvez vérifier, exploiter et faire évoluer.

Conclusion

kcgi propose une base compacte pour écrire des applications CGI et FastCGI en C ou en C++, avec un choix de conception clairement assumé : isoler le parsing des données non fiables dans un processus sandboxé. Cette architecture peut limiter les conséquences d'un défaut, mais elle ajoute aussi des contraintes de compilation, de déploiement et de performance.

La bonne approche consiste d'abord à vérifier l'adéquation avec votre environnement, à partir d'un exemple minimal, puis à lire les pages de manuel et à tester le cycle complet sur le serveur visé. Ensuite seulement, mesurez les coûts et vérifiez les limites de sécurité réellement mises en place. Pour aller plus loin, consultez la documentation officielle de kcgi et intégrez ses tests à votre chaîne de livraison avant toute mise en production.

Questions frequentes

Oui. kcgi est conçu pour des applications C et C++. Le projet fournit des exemples dédiés, notamment samplepp.cc pour un usage C++ avec CGI. Vérifiez les exemples et les instructions de compilation correspondant à votre chaîne d’outils.
Non. C’est une bibliothèque utilisée par une application web CGI ou FastCGI. Il faut aussi un serveur ou un gestionnaire compatible, par exemple Apache, nginx ou httpd(8) sur OpenBSD, configuré pour transmettre les requêtes à l’application.
Non. Il limite l’environnement du processus chargé d’analyser les entrées, ce qui peut réduire les conséquences d’une vulnérabilité dans ce chemin. Il ne remplace pas les contrôles d’autorisation, la validation métier, l’encodage des sorties, la gestion des dépendances ni les tests de sécurité.
Pour CGI, khttp_parse analyse la requête et doit être appelé avant les autres opérations associées. Pour FastCGI, le cycle est réparti entre khttp_fcgi_init, qui initialise le contexte, et khttp_fcgi_parse, qui reçoit les requêtes. Dans les deux cas, les ressources doivent être libérées avec khttp_free.
Le projet fournit des tests de régression avec make regress et la bibliothèque kcgiregress(3) pour tester une application. Il existe aussi une cible de compilation pour le fuzzing avec American Fuzzy Lop. Complétez ces outils par des tests couvrant vos règles métier, vos erreurs et votre configuration de déploiement.

Articles similaires