Antimodèle : accéder de façon incorrecte aux en-têtes HTTP à valeurs multiples dans un proxy d'API

Vous consultez la documentation d'Apigee Edge.
Consultez la documentation Apigee X.
en savoir plus

Les en-têtes HTTP sont des paires nom/valeur qui permettent aux applications clientes et aux services de backend de transmettre respectivement des informations supplémentaires sur les requêtes et les réponses. Voici quelques exemples simples :

  • L'en-tête de requête d'autorisation transmet les identifiants de l'utilisateur au serveur :
    Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l
  • L'en-tête Content-Type indique le type de contenu de la requête/réponse envoyé :
    Content-Type: application/json

Les en-têtes HTTP peuvent être associés à une ou plusieurs valeurs en fonction des définitions des champs d'en-tête. Un en-tête à valeurs multiples contient des valeurs séparées par une virgule. Voici quelques exemples d'en-têtes incluant plusieurs valeurs :

  • Cache-Control: no-cache, no-store, must-revalidate
  • Accept: text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8
  • X-Forwarded-For: 10.125.5.30, 10.125.9.125

Apigee Edge permet aux développeurs d'accéder facilement aux en-têtes à l'aide de variables de flux dans l'une des stratégies Edge ou des flux conditionnels. Voici la liste des variables pouvant être utilisées pour accéder à un en-tête de requête ou de réponse spécifique dans Edge:

Variables de flux :

  • message.header.header-name
  • request.header.header-name
  • response.header.header-name
  • message.header.header-name.N
  • request.header.header-name.N
  • response.header.header-name.N

Objets JavaScript :

  • context.proxyRequest.headers.header-name
  • context.targetRequest.headers.header-name
  • context.proxyResponse.headers.header-name
  • context.targetResponse.headers.header-name

Voici un exemple de règle AssignMessage indiquant comment lire la valeur d'un en-tête de requête et la stocker dans une variable :

<AssignMessage continueOnError="false" enabled="true" name="assign-message-default">
  <AssignVariable>
    <Name>reqUserAgent</Name>
    <Ref>request.header.User-Agent</Ref>
  </AssignVariable>
</AssignMessage>

Antimodèle

L'accès aux valeurs des en-têtes HTTP dans les règles Edge de manière à ne renvoyer que la première valeur est incorrect et peut entraîner des problèmes si les en-têtes HTTP spécifiques ont plusieurs valeurs.

Les sections suivantes présentent des exemples d'accès aux en-têtes.

Exemple 1 : Lire un en-tête Accept à valeurs multiples à l'aide du code JavaScript

Notez que l'en-tête Accept contient plusieurs valeurs, comme indiqué ci-dessous :

Accept: text/html, application/xhtml+xml, application/xml

Voici le code JavaScript permettant de lire la valeur de l'en-tête Accept :

// Read the values from Accept header
var acceptHeaderValues = context.getVariable("request.header.Accept");

Le code JavaScript ci-dessus ne renvoie que la première valeur de l'en-tête Accept, par exemple text/html.

Exemple 2 : Lire un en-tête Access-Control-Allow-Headers à valeurs multiples dans une règle AssignMessage ou RaiseFault

Notez que l'en-tête Access-Control-Allow-Headers contient plusieurs valeurs, comme indiqué ci-dessous :

Access-Control-Allow-Headers: content-type, authorization

La partie du code de la règle AssignMessage ou RaiseFault permettant de définir l'en-tête Access-Control-Allow-Headers est présentée ci-dessous :

<Set>
  <Headers>
    <Header name="Access-Control-Allow-Headers">{request.header.Access-Control-Request-Headers}</Header>
  </Headers>
</Set>

Le code ci-dessus ne définit l'en-tête Access-Control-Allow-Headers qu'avec la première valeur de l'en-tête de requête Access-Control-Allow-Headers, content-type dans cet exemple.

Impact

  1. Dans les deux exemples ci-dessus, notez que seule la première valeur des en-têtes à valeurs multiples est renvoyée. Si ces valeurs sont ensuite utilisées par une autre règle du flux de proxy d'API ou par le service de backend pour appliquer une fonction ou une logique, cela peut entraîner un résultat inattendu.
  2. Lorsque les valeurs des en-têtes de requête sont accessibles et transmises au serveur cible, les requêtes API peuvent être traitées par le backend de manière inappropriée et générer des résultats incorrects.
  3. Si l'application cliente dépend de valeurs d'en-tête spécifiques de la réponse Edge, elle peut également être traitée de manière incorrecte et donner des résultats incorrects.

Bonnes pratiques

  1. Utilisez les variables de flux intégrées appropriées : request.header.header_name.values.count, request.header.header_name.N, response.header.header_name.values.count et response.header.header_name.N.

    Effectuez ensuite une itération pour extraire toutes les valeurs d'un en-tête spécifique dans les règles d'appel JavaScript ou Java.

    Exemple : Exemple de code JavaScript permettant de lire un en-tête à valeurs multiples

    for (var i = 1; i <=context.getVariable('request.header.Accept.values.count'); i++)
    {
      print(context.getVariable('request.header.Accept.' + i));
    }
    

    Par exemple, application/xml;q=0.9, */*;q=0.8 apparaît sous la forme d'une valeur avec le code ci-dessus.

    Si les valeurs d'en-tête doivent être fractionnées en utilisant un point-virgule comme délimiteur, utilisez string.split(";") pour les scinder.

  2. Utilisez la fonction substring() dans la variable de flux request.header.header_name.values de la règle RaiseFault ou AssignMessage pour lire toutes les valeurs d'un en-tête spécifique.

    Exemple : Exemple de règle RaiseFault ou AssignMessage permettant de lire un en-tête à valeurs multiples

    <Set>
      <Headers>
       <Header name="Access-Control-Allow-Headers">{substring(request.header.Access-Control-Request-Headers.values,1,-1)}</Header>
      </Headers>
    </Set>
    

Documentation complémentaire