HAProxy CORS OPTIONS标头拦截设置

Bri*_*ian 13 ajax haproxy cors preflight

通过我的NGinx设置,我能够拦截来自ajax预检的OPTIONS请求,并使用正确的CORS标头和200响应进行响应,以便请求可以继续进行.我正在尝试将我的前端代理合并到HAProxy中,并且在解决这个难题时遇到了一些问题.

我的特殊问题是,当有服务器能够正确响应OPTIONS请求时,我能够添加正确的CORS选项,但是当发出预检请求时,一些后端无法处理/响应405错误.我的haproxy.cfg包含以下用于添加标题的行:

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 }
Run Code Online (Sandbox Code Playgroud)

解决方案:

当您从客户端的请求设置所有正确的标头时,如何在不将请求传递给Web服务器的情况下使用HAProxy发送响应,但不是动态的,这不是理想的解决方案.

任何帮助,将不胜感激!

小智 5

你可以使用Lua,但你需要USE_LUA通过检查来确保构建HAproxy haproxy -vv.

这是一个示例配置,我自己没有尝试过,但它会让你知道你可以做什么:

# 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)
Run Code Online (Sandbox Code Playgroud)


Flo*_*aus 5

基于anine.io出色回答,我提出了以下解决方案,该解决方案可以定义允许的来源列表,并且还Acccess-Control-Allow-Origin为所有HTTP请求添加缺少的标头。anine.io的回答仅显示了CORS的预检,但未考虑正常的请求。

在全局部分中haproxy.cfg加载cors.lua文件(必要时修改路径)

global
    lua-load /usr/local/etc/haproxy/cors.lua
Run Code Online (Sandbox Code Playgroud)

将CORS配置添加到您的前端定义

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 }
Run Code Online (Sandbox Code Playgroud)

创建一个名为的文件cors.lua,并将其存储在上面指定的路径下。该文件包含CORS的预检信息,如果没有充分的理由,请不要限制Method或Headers,因为您必须在中的CORS配置中定义的ACL中包括有关方法或标头的任何限制haproxy.conf注:目前的浏览器不支持通配符*Access-Control-Allow-Methods头。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", "*")
    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)
Run Code Online (Sandbox Code Playgroud)

创建一个名为的文件cors-origins.lst,并将其存储在CORS配置中您在上面指定的路径下。该文件应包含正则表达式(或仅包含简单字符串)。如果客户端发送了Origin标头,则将针对这些正则表达式进行验证,并且只有当它们匹配时,cors.lua才会返回CORS Preflight from (对于HTTP OPTIONS请求),或者将Access-Control-Allow-Origin带有客户端请求标头的值添加到响应。的内容示例cors-origins.lst可能是

example.com
localhost.*
.*\.mydomain\.com:[8080|8443]
Run Code Online (Sandbox Code Playgroud)

使用http://test-cors.org/测试配置。对于GET请求,应该没有CORS Preflight。对于除GET以外的请求,客户端应首先执行CORS Preflight请求(例如HTTP OPTIONS调用),以检查是否允许使用预期的方法,标头和授权。

有关CORS的更多详细信息,请参见HTTP访问控制(CORS)