HAProxy CORS OPTIONS header intercept setup
avec ma configuration NGinx j'ai été capable d'intercepter les requêtes D'OPTIONS depuis ajax avant le vol et de répondre avec les en-têtes CORS corrects et une réponse de 200 pour que la requête puisse continuer. J'essaie de consolider mes mandataires frontend en HAProxy et j'ai du mal à faire fonctionner cette pièce du puzzle.
mon problème particulier est que même si je suis capable d'ajouter les bonnes options CORS lorsqu'il y a un serveur capable de répondre correctement à une requête D'OPTIONS, quelques-uns des les endos ne peuvent pas traiter / répondre avec une erreur 405 lorsque la demande avant le vol est émise. Mon haproxy.cfg inclus les lignes suivantes pour ajouter les en-têtes:
capture request header origin len 128
http-response add-header Access-Control-Allow-Origin %[capture.req.hdr(0)] if { capture.req.hdr(0) -m found }
rspadd Access-Control-Allow-Credentials: true if { capture.req.hdr(0) -m found }
rspadd Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Origin, User-Agent, If-Modified-Since, Cache-Control, Accept if { capture.req.hdr(0) -m found }
rspadd Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS if { capture.req.hdr(0) -m found }
rspadd Access-Control-Max-Age: 1728000 if { capture.req.hdr(0) -m found }
La solution:
Comment envoyer une réponse avec HAProxy sans passer la demande aux serveurs web fonctionne lorsque vous définissez tous les en-têtes corrects à partir de la demande d'un client, mais n'est pas dynamique, ce qui n'est pas une solution idéale.
Toute aide serait apprécié!
3 réponses
Vous pouvez utiliser Lua, mais vous devez vous assurer que HAproxy est construit avec USE_LUA
en cochant haproxy -vv
.
il s'agit d'une configuration d'exemple, Je ne l'ai pas essayé moi-même, mais elle vous donnera une idée de ce que vous pouvez faire:
# haproxy.cfg
global
lua-load cors.lua
frontend foo
...
http-request use-service lua.cors-response if METH_OPTIONS { req.hdr(origin) -m found } { ... }
# cors.lua
core.register_service("cors-response", "http", function(applet)
applet:set_status(200)
applet:add_header("Content-Length", "0")
applet:add_header("Access-Control-Allow-Origin", applet.headers["origin"][0])
applet:add_header("Access-Control-Allow-Credentials", "true")
applet:add_header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Origin, User-Agent, If-Modified-Since, Cache-Control, Accept")
applet:add_header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
applet:add_header("Access-Control-Max-Age", "1728000")
applet:start_response()
end)
basé sur le grande réponse de anine.io j'ai trouvé la solution suivante qui permet de définir une liste de permis origines et il ajoute également l'absence de Acccess-Control-Allow-Origin
en-tête pour toutes les requêtes HTTP. La réponse d'anine.io n'a montré que le CORS avant le vol, mais n'a pas tenu compte des demandes normales.
haproxy.cfg
charge cors.lua
fichier (adapter le chemin si nécessaire) dans la section globale
global
lua-load /usr/local/etc/haproxy/cors.lua
ajouter la configuration CORS à votre frontend définition
frontend http-in
# CORS configuration
# capture origin HTTP header
capture request header origin len 128
# add Access-Control-Allow-Origin HTTP header to response if origin matches the list of allowed URLs
http-response add-header Access-Control-Allow-Origin %[capture.req.hdr(0)] if !METH_OPTIONS { capture.req.hdr(0) -m reg -f /usr/local/etc/haproxy/cors-origins.lst }
# if a preflight request is made, use CORS preflight backend
http-request use-service lua.cors-response if METH_OPTIONS { capture.req.hdr(0) -m reg -f /usr/local/etc/haproxy/cors-origins.lst }
Créer un fichier appelé cors.lua
et le stocker sous le chemin que vous avez spécifié ci-dessus. Le fichier contient le CORS preflight et s'il n'y a pas de bonne raison, ne restreignez pas les méthodes ou les en-têtes car vous devrez inclure toutes les restrictions concernant les méthodes ou les en-têtes dans les ACLs définis dans la configuration de CORS en haproxy.conf
. Remarque: actuellement, les navigateurs ne supportent pas les caractères génériques *
pour les Access-Control-Allow-Methods
en-tête.cors.lua
le fichier doit contenir les éléments suivants contenu
core.register_service("cors-response", "http", function(applet)
applet:set_status(200)
applet:add_header("Content-Length", "0")
applet:add_header("Access-Control-Allow-Origin", applet.headers["origin"][0])
applet:add_header("Access-Control-Allow-Credentials", "true")
applet:add_header("Access-Control-Allow-Headers", "*")
applet:add_header("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, PATCH, OPTIONS")
applet:add_header("Access-Control-Max-Age", "1728000")
applet:start_response()
end)
Créer un fichier appelé cors-origins.lst
et stockez-le sous le chemin que vous avez spécifié ci-dessus dans la configuration de CORS. Le fichier doit contenir des expressions régulières (ou simplement des chaînes simples). Si le client envoie un en-tête Origin, il sera validé par rapport à ces expressions régulières et seulement si elles correspondent, le CORS Préflight de cors.lua
seront retournés (pour HTTP OPTIONS
demandes) ou Access-Control-Allow-Origin
avec la valeur de l'en-tête d'origine du client la demande sera ajouté à la réponse. Un exemple de contenu de cors-origins.lst
peut être
example.com
localhost.*
.*\.mydomain\.com:[8080|8443]
tester la configuration avec http://test-cors.org/. Pour les requêtes GET, il ne doit pas y avoir de vol CORS. Pour les requêtes autres que GET, le client doit d'abord effectuer une requête CORS Preflight (par exemple un appel D'OPTIONS HTTP) pour vérifier si la méthode, les en-têtes et l'autorisation sont autorisés.
Voir contrôle D'accès HTTP (CORS) pour plus de détails concernant CORS.
je veux lancer ma propre réponse dans le ring ici. Nous avons connu une certaine douleur, pour arriver à une configuration de travail. Les autres réponses à cette question ont été très utiles, mais n'ont pas fourni une configuration entièrement fonctionnelle pour nous.
nous voulions autoriser n'importe quelle origine. Si vous avez besoin d'origines à liste blanche, voir le réponse de @Florian Feldhaus pour une astuce regex utile. Au lieu d'utiliser une liste blanche, on renvoie l'en-tête location:
http-request set-header Access-Control-Allow-Origin %[capture.req.hdr(0)] if { capture.req.hdr(0) -m found }
nous avons aussi eu besoin de définir explicitement Access-Control-Allow-Headers
et Access-Control-Expose-Headers
. le support du navigateur pour les caractères génériques dans ces en-têtes n'est pas encore tout à fait présent.
alors voici ce que fait notre configuration:
- traite les demandes avant vol en utilisant c'scro.lua script
- traite les requêtes normales en utilisant
http-response set-header
ajouter Access-Control-Allow-* les en-têtes - ajuster
tune.maxrewrite
pour s'adapter à nos en-têtes CORS (qui sont > 1 KB)
Les étapes 1) et 2) sont expliqués dans les autres réponses ici, mais l'étape 3) nous a fallu beaucoup de temps pour comprendre. J'ai documenté la configuration complète et le voyage qui nous a menés là-bas en ce post. Le post contient des liens pour l'essentiel sur github.