Les modèles de recherche offrent un moyen simple d’ajouter une fonctionnalité de recherche appuyée par un index Elasticsearch. Ils sont également assez sécurisés, à moins que vous n’utilisiez accidentellement une syntaxe non sécurisée et que vous n’ouvriez vos données aux attaques par injection.

La fonctionnalité de recherche est passée d’une fonctionnalité intéressante à un produit de base – tout le monde s’attend à ce que la recherche soit là et fonctionne. Dans le même temps, les infrastructures, les modèles de données et les back-ends derrière la barre de recherche conviviale peuvent désormais être incroyablement complexes, nécessitant de nouvelles approches qui vont bien au-delà de l’envoi d’une requête à un serveur de base de données. Elasticsearch a été développé pour répondre à ce besoin et est aujourd’hui le moteur de recherche d’entreprise le plus populaire au monde . Il est donc essentiel de savoir comment l’utiliser correctement pour la sécurité des données, d’autant plus qu’il est très facile de se tromper.

Avant d’aborder quelques exemples d’utilisation non sécurisée, revenons en arrière pour voir comment nous en sommes arrivés là où nous en sommes aujourd’hui avec Elasticsearch.

Un changement de paradigme silencieux dans le développement Web

Avant l’ère du cloud, le développement web était beaucoup moins spécialisé. Bien sûr, nous avions notre juste part de frameworks qui nécessitaient des connaissances spécifiques pour créer une application fonctionnelle, mais leur travail consistait principalement à résumer tout le travail fastidieux lié à la création d’une application Web, comme la gestion des sessions, des cookies ou des utilisateurs. En pratique, vous pouviez traiter ces solutions comme des extensions de langages de programmation existants, donc leur apprentissage consistait à se souvenir de quelques nouvelles fonctions et modèles.

Les dernières années, cependant, ont vu un changement majeur (bien que silencieux). Alors que les frameworks et technologies précédents étaient principalement conçus pour faciliter le travail d’un développeur, les projets plus récents visent de plus en plus à permettre aux programmeurs d’écrire des applications techniquement plus robustes et avancées sous le capot. Cela est particulièrement vrai pour les systèmes hautement distribués où vous avez besoin d’approches complètement différentes pour garantir l’évolutivité, la fiabilité et les performances.

Tout cela n’était pas vraiment surprenant compte tenu du succès et de l’expansion des systèmes basés sur le cloud, en particulier avec les grandes entreprises technologiques qui mettent leurs outils hautement spécialisés à la disposition de tous. L’un des motifs était d’attirer une communauté open source qui s’appuierait sur – et bien sûr améliorerait – les technologies qu’ils utilisaient pour leurs propres produits.

Entrer dans Elasticsearch

Dans un monde distribué, bon nombre de ces nouvelles technologies devaient être radicalement différentes de ce qui était utilisé auparavant, obligeant à changer la façon dont nous écrivons nos applications. Elasticsearch est un bon exemple d’une technologie qui semble familière mais représente une approche complètement différente de la recherche de données. Même s’il existe depuis un certain temps, son utilité pour toutes sortes d’applications d’entreprise n’était pas immédiatement évidente pour un public plus large. Auparavant, vous auriez principalement utilisé une base de données SQL traditionnelle, telle que MySQL – ou Microsoft SQL Server, comme beaucoup de nos lecteurs le savent douloureusement.

Mais Elasticsearch avait plusieurs fonctionnalités qui le rendraient beaucoup plus populaire parmi les développeurs, comme le fait qu’il arbore une API basée sur JSON – une fonctionnalité que quiconque a déjà eu à écrire une requête SQL d’une complexité légèrement supérieure à la moyenne paierait volontiers. une grosse somme d’argent pour. Une autre raison pour laquelle les bonnes vieilles requêtes SQL sont tombées en désuétude est qu’elles ont toujours été une des principales causes de sauvegardes inattendues non autorisées . De toute évidence, il y avait un besoin d’alternatives.

Que sont les modèles de recherche ?

L’alternative dont nous voulons parler aujourd’hui est les modèles de recherche, en particulier les modèles Moustache utilisés dans Elasticsearch (et pris en charge par tous les principaux langages de programmation). Imaginez que vous souhaitiez fournir une fonctionnalité de recherche sur votre site Web, par exemple pour rechercher des articles de blog. Plus précisément, vous souhaitez donner aux utilisateurs la possibilité de filtrer les résultats selon leurs propres critères, tels que l’ID de la publication. Voici un exemple d’un tel modèle :

{
    "script": {
        "lang": "mustache",
        "source": {
            "query": {
                "match": {
                    "postID": {
                        "query": "{{ID}}"
                    }
                }
            }
        }
    }
}

Comme vous pouvez le voir, nous avons spécifié nos critères de recherche dans le modèle et permet une saisie utilisateur variable entre les doubles accolades. Le modèle est commodément écrit au format JSON et spécifie un postID paramètre que nous voulons obtenir de l’utilisateur. La {{ID}} chaîne de modèle sera étendue pour refléter l’entrée réelle de l’utilisateur et automatiquement nettoyée, afin que nous puissions intégrer l’entrée de l’utilisateur dans le modèle en sachant que nous sommes relativement à l’abri de l’injection, c’est-à-dire si le modèle est écrit correctement.

La moustache équivaut à un triple problème

Comme vous pouvez le voir dans l’exemple ci-dessus, un espace réservé simple dans un modèle Moustache utilise des accolades doubles, donc quelque chose comme {{username}}. Lorsque le modèle est traité, tout sera automatiquement nettoyé pour ne pas interférer avec la syntaxe de tout ce dans quoi vous placez l’espace réservé.

Jusqu’ici, tout va bien – mais selon la documentation , ce n’est pas le seul type d’espace réservé :

Toutes les variables sont HTML échappées par défaut. Si vous souhaitez renvoyer du HTML sans échappement, utilisez la triple moustache : {{{name}}}.

En fonction du système de modèles que vous connaissez déjà et de l’utilisation que vous en faites, vous serez peut-être plus habitué à utiliser par défaut une telle syntaxe à trois accolades, en optant pour au lieu {{{username}}} de {{username}}. Et cela fonctionnera aussi bien pour quelque chose comme un nom d’utilisateur standard, donc vous ne remarquerez peut-être pas le problème. La documentation indique que vous renvoyez maintenant du code HTML sans échappement, en utilisant en fait la valeur d’entrée brute dans le modèle avant qu’elle ne soit transmise à Elasticsearch pour évaluation.

Une entrée utilisateur non filtrée est-elle utilisée directement dans les requêtes de données ? Cela ressemble à une vulnérabilité d’injection classique. Explorons.

Un exemple de code vulnérable

Avant de plonger dans une requête vulnérable, définissons les données que nous interrogeons. Disons que nous avons un index appelé kitties contenant des documents avec name et age des champs. Voici l’index, avec seulement deux documents :

{
    ...

    "hits": [
        {
            "_index": "kitties",
            "_id": "2",
            "_score": 1.0,
            "_source": {
                "name": "Mila",
                "age": 3
            }
        },
        {
            "_index": "kitties",
            "_id": "1",
            "_score": 1.0,
            "_source": {
                "name": "Marley",
                "age": 2
            }
        }
    ]

    ...
}

Si nous pouvons trouver quelque part un modèle vulnérable qui utilise la syntaxe de la triple accolade pour rechercher cet index, nous pourrons peut-être renvoyer tous les documents, même si nous ne connaissons pas un seul nom à mettre dans la requête. Un modèle de recherche vulnérable pourrait ressembler à ceci :

POST /_scripts/vuln-search-template HTTP/1.1
Host: example.com
Content-Length: 263

...

{
    "script": {
        "lang": "mustache",
        "source": {
            "query": {
                "match": {
                    "name": {
                        "query": "{{{name}}}"
                    }
                }
            }
        }
    }
}

Vous pouvez voir l’ {{{name}}} espace réservé ici. Avant que la requête ne soit transmise à Elasticsearch, l’espace réservé est remplacé par la valeur de nom fournie. En théorie, le nom dans l’index doit correspondre à l’entrée pour qu’un document soit renvoyé. Si nous transmettons le nom Marley comme ci-dessous, Elasticsearch renverra le document avec le nom et l’âge de ce félin :

POST /kitties/_search/template HTTP/1.1
Host: example.com

...

{
  "id": "vuln-search-template",
  "params": {
    "name": "Marley"
  }
}

Mais maintenant, pour le hic : l’espace réservé utilise la syntaxe de la triple accolade, il n’est donc pas échappé ou épuré. Cela signifie que nous pouvons facilement changer la signification de la requête JSON. Pour commencer, nous pouvons sortir de la chaîne qui contient {{{name}}} juste un guillemet double. En injectant "zero_terms_query":"all" dans la requête, nous pouvons effectivement la transformer en une requête match-all, ce qui nous permet de renvoyer tous les documents (l’équivalent de l’ancienne 'or 1 = 1' astuce pour l’injection SQL ). Voici un exemple d’exploit :

POST /kitties/_search/template
Host: example.com

...

{
  "id": "vuln-search-template",
  "params": {
    "name": "\", \"zero_terms_query\":\"all\"}}}}"
  }
}

En termes pratiques, si un modèle Elasticsearch utilise un espace réservé à trois accolades et que vous connaissez le nom de l’espace réservé, l’envoi d’une requête comme celle ci-dessus pourrait exposer toutes les données de cet index – pas bon.

Doubler la sécurité des modèles de recherche

Alors, où cela nous mène-t-il ? Le problème n’est pas vraiment dans la façon dont les modèles sont utilisés. En fait, les modèles de recherche sont un mécanisme puissant pour envoyer des requêtes répétitives avec des paramètres changeants, comme lors de l’utilisation d’une barre de recherche sur un site Web. Utilisés correctement, ils ajoutent également une couche de sécurité grâce au codage et à la désinfection automatiques des entrées.

La sécurité à emporter ici est que lorsque vous travaillez avec des modèles dans Elasticsearch, vous devez faire très attention à utiliser la bonne syntaxe d’espace réservé. Tout modèle de recherche qui utilise un espace réservé à trois accolades est vulnérable à l’injection et pourrait révéler l’intégralité de votre index de recherche et de vos données aux attaquants, c’est donc une bonne idée d’appliquer la syntaxe à double accolade plus sécurisée – et assurez-vous également que vous n’exécutez pas d’héritage ou code tiers qui utilise la version non sécurisée.