L'inspection profonde de paquets ou en anglais , abrégée IPP ou DPI est une technique d'analyse des flux passant dans des équipements réseau au-delà de l'entête. L'équipement recherche des informations dans la charge utile des paquets plutôt que dans les entêtes (à l'inverse des approches classiques). Des signatures sont le plus souvent recherchées pour détecter des types de flux et agir en conséquence. Il existe plusieurs domaines d'applications : priorisation ou ralentissement de flux particuliers, censure, détection d'intrusion. L'inspection est mise en œuvre par des gouvernements, des fournisseurs d'accès à Internet (FAI) et des organisations à ces fins.
L'inspection peut fortement ralentir le trafic là où elle est utilisée, cela est dû à la grande puissance de calcul nécessaire pour gérer un trafic important. Pour pallier ce problème, plusieurs solutions sont proposées tant au niveau logiciel que matériel. L'IPP soulève aussi des questions quant au respect de la vie privée. En effet, les différents acteurs analysent le contenu du trafic, et ce avec différents objectifs.
Technologie L'IPP amène de gros problèmes de ralentissement du trafic. Une grande quantité de calcul et de mémoire est nécessaire pour traiter efficacement des grandes quantités de paquets. Plusieurs solutions sont apportées, au niveau logiciel et matériel.
Algorithmique Les outils d'IPP recherchent des signatures d'applications connues en utilisant des ensembles d'expressions régulières. Les expressions régulières utilisées par des systèmes de détection d'intrusion consistent généralement en un ensemble de patterns contenant: de simples chaines de caractère, des plages de caractères, jokers, des sous-patterns se répétant indéfiniment ou un certain nombre de fois. Ces expressions sont transcrites en automates et nécessitent de grandes quantités de mémoire et de puissance de calcul. Les optimisations possibles sont donc la diminution de l'empreinte mémoire et de la puissance de calcul nécessaire ou la répartition de celle-ci.
Automates Les expressions régulières peuvent être traduites en automates de deux types : des automates finis déterministes (AFD) et des automates finis non déterministes (AFND). Leurs différences résident dans le fait que dans un automate déterministe, un symbole ne déclenche qu'une seule transition depuis un état. Dans un automate non déterministe, un même symbole peut déclencher plusieurs transitions vers un état. Le schéma ci-contre représente un automate déterministe pour l'expression abcd. thumb|AFD représentant l'expression régulière « abcd ». Les automates déterministes présentent plusieurs avantages. Premièrement, une chaîne de caractères ne fera qu'un passage dedans. Chaque symbole ne déclenchant qu'un changement d'état, les accès à la mémoire sont donc déterministes. Ensuite une expression régulière peut être traduite en automate fini avec un nombre minimum d'états. Cependant ceux-ci ont tendance à augmenter fortement en agrégeant des ensembles d'expressions. Le schéma ci-contre représente un automate non déterministe pour l'expression a*ba* Les automates non déterministes quant à eux demandent moins d'espace mémoire mais une plus grande puissance de calcul ainsi que des accès mémoires variables . Tout automate non déterministe peut être transformé en déterministe souvent au prix d'une explosion des états. vignette|AFND représentant l'expression « a*ba* ». Le tableau suivant représente la complexité et le coût en mémoire pour un automate fini déterministe et non déterministe pour une expression régulière de taille n. Complexité Coût en mémoire Non déterministe O(n²) O(n) Déterministe O(1) O(Σn) Des patterns imbriqués dans des expressions provoquent des retours en boucle dans les automates correspondant. Pour exemple, La règle Snort User-Agent\x3A[^\r\n]*ZC-Bridge, recherche une occurrence du sous pattern «ZC-Bridge» seulement si «User-Agent\x3A» a été précédemment rencontré et qu'il n'y a pas eu de retour à la ligne entre. Ces patterns affectent les transitions dans les automates déterministes mais pas dans le nombre d'états. Les automates finis qui correspondent à des ensembles de règles de systèmes de détection d'intrusion ont une grande redondance de changements d'état.
Cependant quand on combine plusieurs expressions il y a une forte augmentation du nombre d'états. Surtout si une expression contient une condition .*correspondant à n'importe quel caractère un nombre arbitraire de fois. En effet si on considère deux expressions R1 et R2, R2 contenant une condition .*. En combinant les deux sous la forme .*(R1|R2), l'automate correspondant à R1 sera répliqué dans la condition .* de R2. En combinant les expressions on aura donc une augmentation linéaire du nombre d'états en fonction du nombre de conditions .* . Les contraintes de nombres de caractères de type ab.{3}cd causent quant à elle une augmentation exponentielle du nombre d'état. La situation empire encore en les combinant avec des .*. Bien que les automates finis ont l'avantage de trouver une certaine séquence en un temps linéaire, quand ils subissent une explosion d'états ils ne sont, bien souvent, pas représentables.
Une solution pour éviter cette explosion est de construire l'automate déterministe découlant d'un automate non déterministe et d'interrompre lorsqu'une augmentation d'états apparait. Dans le cas précédent c'est dans la condition .* de R2 que l'on peut retrouver ça. L'automate alors créé est dit hybride, il possède plusieurs propriétés intéressantes : l'état de départ est déterministe ; les parties non déterministes ne seront évaluées qu'en arrivant en bordure ; en revenant de la partie non déterministe, il n'y aura pas de rétroactivation de la partie déterministe. Grâce à cette technique, on arrive donc à représenter la majeure partie de l'automate de façon déterministe, réduisant les accès mémoire. Cependant l'empreinte mémoire de l'automate créé peut être réduite avec plusieurs méthodes de compression selon la partie (déterministe ou pas).
La première solution consiste à simplement modifier l'expression régulière selon deux façons: Il est possible de transformer ^A+[A-Z]{j}" en "^A[A-Z]{j} . La taille de l'automate résultant en est grandement réduite. Pour exemple l'expression ^SEARCH\s+[^\n]{1024} (utilisée par Snort) génère un automate de taille quadratique du a des plages de caractères qui se chevauchent (\s et ^\n) En la transformant en ^SEARCH\s[\n]{1024}; Utiliser des classes d'exclusions. Pour exemple l'expression .*AUTH\s[^\n]{100} peut être transformée en ([^A]|A[^U]|AU[^T]|AUT[^H]|AUTH[^\s]|AUTH\s[^\n]{0,99}\n)*AUTH\s[^\n]{100}. La règle énumère premièrement tous les mauvais cas et quand l'automate atteint la partie suivante, il y aura d'office une correspondance.
La fusion d'états est une deuxième solution. Deux états ayant une transition sur des états communs peuvent être fusionnés. Et cela même si certaines transitions diffèrent. Pour le fonctionnement de ce système il faut ajouter un label aux entrées des états afin de différencier quel est le nœud d'origine et ainsi en déduire les données d'entrées de l'état suivant. De plus des états fusionnés peuvent amener d'autres possibilités de rassemblement.
Les automates déterministes finis à retard d'entrée sont une autre réponse aux problèmes de quantité de mémoire malheureusement ils viennent avec un compromis au niveau des accès à celle-ci. Cette technique définit un principe de transition par défaut, il ne peut y en avoir qu'une seule par nœud, il faut donc la choisir avec soin . Dans l'exemple suivant, si on ajoute une transition par défaut de u vers v on peut supprimer la transition de u vers w sans changer le comportement de l'automate. vignette|Automate fini déterministe à retard d'entrée.
Il est encore possible d'optimiser ces derniers avec les automates finis à retard d'entrée avec label de contenu. Les numéros d'états sont alors remplacés par des labels de contenu. Dans une implémentation classique, les états sont identifiés par un nombre référençant une entrée dans une table contenant les informations du nœud. Ici, une partie du contenu de la table est donc stockée dans le label de l'état . Cette dernière technique de compression peut être appliquée sur des automates déterministes et peut être adaptée pour les non déterministes.
Toutes ces optimisations permettent de réduire l'empreinte mémoire (bande passante et quantité) ainsi que la puissance de calcul nécessaire pour des automates. Ceux-ci seront utilisés dans des logiciels (Snort, Bro/Zeek...) ou bien dans du matériel dédié.
Context Based DPI
L'inspection de paquet profonde basée sur le contexte ou context based deep packet inspection (CDPI) est une forme d'IPP qui ne se contente pas juste d'analyser les paquets les uns à la suite des autres. Il a pour objectif d'analyser le flux de paquet pour en extraire des informations. Cela permet de s'affranchir de l'analyse de l'information du paquet elle-même tout en obtenant l'information générale.
Exemple d'utilisation du context bases deep packet inspection : la détection de la première phase d'échange de clés d'IPsec. L'analyse d'un paquet seul via le DPI classique ne permet pas de connaitre le protocole utilisé. Or, l'utilisation du CDPI permet non seulement de repérer la phase d'échange de clé d'IPsec, mais aussi de savoir si les messages sont légitimes ou une imitation. De plus, on peut afficher l'intégralité de la première phase d'échange. De ce fait, le CDPI peut être une bonne approche pour s'assurer de l'intégrité et de la validité de la phase d'échange de clés.
MapReduce L'émergence de réseaux à haute vitesse tel que 20/40 Gbit/s Ethernet et au-delà requiert une analyse rapide d'un large volume de trafic réseau. Bien que la plupart des FAI agrègent le trafic de multiples routeurs vers un gros serveur avec beaucoup de stockage. Des compromis sont faits pour être capables de gérer du trafic à l'échelle d'un pays : agrégation des flux, résumé des paquets, etc. Le tout au prix de grosses latences. De plus la tolérance aux pannes est très faible et le passage à l’échelle compliqué. On se rend donc bien vite compte que cette tâche est au-delà des capacités d'une seule machine . L'analyse à la volée de liens à haute vitesse demande un compromis entre précision, temps, consommation de ressources et coût. Ce n'est pas une tâche triviale pour une seule machine car la correspondance de patterns dans l'IPP est généralement implémentée en espace utilisateur et requiert beaucoup de puissance processeur. Cela provoque un haut niveau de perte de paquets.
C'est alors qu'est venue l'idée d'utiliser MapReduce un nouveau paradigme de programmation qui permet de répartir le traitement sur plusieurs machines augmentant ainsi la puissance de calcul disponible, cette façon de faire amène aussi un haut niveau d'abstraction et une bonne tolérance aux pannes. La bibliothèque Hadoop créée par Yahoo! en est une implémentation, elle regroupe deux éléments essentiels : la répartition du calcul sur des groupes de machines et la répartition du stockage via HDFS. Les calculs sont divisés en trois phases : mapping, shuffle et reduce. La première consiste à définir des couples de clefs/valeurs. Après celle-ci on regroupe les clefs similaires (Shuffle) et on finit par réduire de plusieurs façons possibles : somme, moyenne, comptage... Tous ces travaux peuvent s'exécuter sur des machines différentes. On voit donc que le logiciel est bien adapté pour l'analyse de grandes quantités de trafic à la volée de façon distribuée.