Skip to content

Commit

Permalink
fix(cors): avoid overwriting Access-Control-Expose-Headers response…
Browse files Browse the repository at this point in the history
… header (apache#11136)
  • Loading branch information
VanLiuZhi authored Apr 23, 2024
1 parent e40a9d1 commit 53661ea
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 17 deletions.
12 changes: 6 additions & 6 deletions apisix/plugins/cors.lua
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,9 @@ local schema = {
},
expose_headers = {
description =
"you can use '*' to expose all header when no credentials," ..
"'**' to allow forcefully(it will bring some security risks, be carefully)," ..
"multiple header use ',' to split. default: *.",
type = "string",
default = "*"
"multiple header use ',' to split." ..
"If not specified, no custom headers are exposed.",
type = "string"
},
max_age = {
description =
Expand Down Expand Up @@ -226,7 +224,9 @@ local function set_cors_headers(conf, ctx)
core.response.set_header("Access-Control-Allow-Origin", ctx.cors_allow_origins)
core.response.set_header("Access-Control-Allow-Methods", allow_methods)
core.response.set_header("Access-Control-Max-Age", conf.max_age)
core.response.set_header("Access-Control-Expose-Headers", conf.expose_headers)
if conf.expose_headers ~= nil and conf.expose_headers ~= "" then
core.response.set_header("Access-Control-Expose-Headers", conf.expose_headers)
end
if conf.allow_headers == "**" then
core.response.set_header("Access-Control-Allow-Headers",
core.request.header(ctx, "Access-Control-Request-Headers"))
Expand Down
3 changes: 1 addition & 2 deletions docs/en/latest/plugins/cors.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ The `cors` Plugins lets you enable [CORS](https://developer.mozilla.org/en-US/do
| allow_origins | string | False | "*" | Origins to allow CORS. Use the `scheme://host:port` format. For example, `https://somedomain.com:8081`. If you have multiple origins, use a `,` to list them. If `allow_credential` is set to `false`, you can enable CORS for all origins by using `*`. If `allow_credential` is set to `true`, you can forcefully allow CORS on all origins by using `**` but it will pose some security issues. |
| allow_methods | string | False | "*" | Request methods to enable CORS on. For example `GET`, `POST`. Use `,` to add multiple methods. If `allow_credential` is set to `false`, you can enable CORS for all methods by using `*`. If `allow_credential` is set to `true`, you can forcefully allow CORS on all methods by using `**` but it will pose some security issues. |
| allow_headers | string | False | "*" | Headers in the request allowed when accessing a cross-origin resource. Use `,` to add multiple headers. If `allow_credential` is set to `false`, you can enable CORS for all request headers by using `*`. If `allow_credential` is set to `true`, you can forcefully allow CORS on all request headers by using `**` but it will pose some security issues. |
| expose_headers | string | False | "*" | Headers in the response allowed when accessing a cross-origin resource. Use `,` to add multiple headers. If `allow_credential` is set to `false`, you can enable CORS for all response headers by using `*`. If `allow_credential` is set to `true`, you can forcefully allow CORS on all response headers by using `**` but it will pose some security issues. |
| expose_headers | string | False | | Headers in the response allowed when accessing a cross-origin resource. Use `,` to add multiple headers. If `allow_credential` is set to `false`, you can enable CORS for all response headers by using `*`. If not specified, the plugin will not modify the `Access-Control-Expose-Headers header`. See [Access-Control-Expose-Headers - MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers) for more details. |
| max_age | integer | False | 5 | Maximum time in seconds the result is cached. If the time is within this limit, the browser will check the cached result. Set to `-1` to disable caching. Note that the maximum value is browser dependent. See [Access-Control-Max-Age](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age#Directives) for more details. |
| allow_credential | boolean | False | false | When set to `true`, allows requests to include credentials like cookies. According to CORS specification, if you set this to `true`, you cannot use '*' to allow all for the other attributes. |
| allow_origins_by_regex | array | False | nil | Regex to match origins that allow CORS. For example, `[".*\.test.com$"]` can match all subdomains of `test.com`. When set to specified range, only domains in this range will be allowed, no matter what `allow_origins` is. |
Expand Down Expand Up @@ -119,7 +119,6 @@ curl http://127.0.0.1:9080/hello -v
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Methods: *
< Access-Control-Allow-Headers: *
< Access-Control-Expose-Headers: *
< Access-Control-Max-Age: 5
...
```
Expand Down
3 changes: 1 addition & 2 deletions docs/zh/latest/plugins/cors.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ description: 本文介绍了 Apache APISIX cors 插件的基本信息及使用
| allow_origins | string || "*" | 允许跨域访问的 Origin,格式为 `scheme://host:port`,示例如 `https://somedomain.com:8081`。如果你有多个 Origin,请使用 `,` 分隔。当 `allow_credential``false` 时,可以使用 `*` 来表示允许所有 Origin 通过。你也可以在启用了 `allow_credential` 后使用 `**` 强制允许所有 Origin 均通过,但请注意这样存在安全隐患。 |
| allow_methods | string || "*" | 允许跨域访问的 Method,比如:`GET``POST` 等。如果你有多个 Method,请使用 `,` 分割。当 `allow_credential``false` 时,可以使用 `*` 来表示允许所有 Method 通过。你也可以在启用了 `allow_credential` 后使用 `**` 强制允许所有 Method 都通过,但请注意这样存在安全隐患。 |
| allow_headers | string || "*" | 允许跨域访问时请求方携带哪些非 `CORS 规范` 以外的 Header。如果你有多个 Header,请使用 `,` 分割。当 `allow_credential``false` 时,可以使用 `*` 来表示允许所有 Header 通过。你也可以在启用了 `allow_credential` 后使用 `**` 强制允许所有 Header 都通过,但请注意这样存在安全隐患。 |
| expose_headers | string || "*" | 允许跨域访问时响应方携带哪些非 `CORS 规范` 以外的 Header。如果你有多个 Header,请使用 `,` 分割。当 `allow_credential``false` 时,可以使用 `*` 来表示允许任意 Header。你也可以在启用了 `allow_credential` 后使用 `**` 强制允许任意 Header,但请注意这样存在安全隐患|
| expose_headers | string || | 允许跨域访问时响应方携带哪些非 CORS 规范 以外的 Header。如果你有多个 Header,请使用 , 分割。当 allow_credential 为 false 时,可以使用 * 来表示允许任意 Header。如果不设置,插件不会修改 `Access-Control-Expose-Headers` 头,详情请参考 [Access-Control-Expose-Headers - MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers)|
| max_age | integer || 5 | 浏览器缓存 CORS 结果的最大时间,单位为秒。在这个时间范围内,浏览器会复用上一次的检查结果,`-1` 表示不缓存。请注意各个浏览器允许的最大时间不同,详情请参考 [Access-Control-Max-Age - MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age#directives)|
| allow_credential | boolean || false | 是否允许跨域访问的请求方携带凭据(如 Cookie 等)。根据 CORS 规范,如果设置该选项为 `true`,那么将不能在其他属性中使用 `*`|
| allow_origins_by_regex | array || nil | 使用正则表达式数组来匹配允许跨域访问的 Origin,如 `[".*\.test.com$"]` 可以匹配任何 `test.com` 的子域名。如果 `allow_origins_by_regex` 属性已经指定,则会忽略 `allow_origins` 属性。 |
Expand Down Expand Up @@ -104,7 +104,6 @@ curl http://127.0.0.1:9080/hello -v
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Methods: *
< Access-Control-Allow-Headers: *
< Access-Control-Expose-Headers: *
< Access-Control-Max-Age: 5
...
```
Expand Down
2 changes: 1 addition & 1 deletion t/plugin/cors.t
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ Access-Control-Allow-Origin: *
Vary:
Access-Control-Allow-Methods: *
Access-Control-Allow-Headers: *
Access-Control-Expose-Headers: *
Access-Control-Expose-Headers:
Access-Control-Max-Age: 5
Access-Control-Allow-Credentials:

Expand Down
12 changes: 6 additions & 6 deletions t/plugin/cors3.t
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ Access-Control-Allow-Origin: https://test.com
Vary: Via, Origin
Access-Control-Allow-Methods: *
Access-Control-Allow-Headers: *
Access-Control-Expose-Headers: *
Access-Control-Expose-Headers:
Access-Control-Max-Age: 5
Access-Control-Allow-Credentials:
Expand All @@ -204,7 +204,7 @@ Access-Control-Allow-Origin: https://domain.com
Vary: Via, Origin
Access-Control-Allow-Methods: *
Access-Control-Allow-Headers: *
Access-Control-Expose-Headers: *
Access-Control-Expose-Headers:
Access-Control-Max-Age: 5
Access-Control-Allow-Credentials:
Expand Down Expand Up @@ -276,7 +276,7 @@ Access-Control-Allow-Origin: https://domain.com
Vary: Via, Origin
Access-Control-Allow-Methods: *
Access-Control-Allow-Headers: *
Access-Control-Expose-Headers: *
Access-Control-Expose-Headers:
Access-Control-Max-Age: 5
Access-Control-Allow-Credentials:
Expand All @@ -295,7 +295,7 @@ Access-Control-Allow-Origin: https://sub.domain.com
Vary: Via, Origin
Access-Control-Allow-Methods: *
Access-Control-Allow-Headers: *
Access-Control-Expose-Headers: *
Access-Control-Expose-Headers:
Access-Control-Max-Age: 5
Access-Control-Allow-Credentials:
Expand Down Expand Up @@ -348,7 +348,7 @@ Access-Control-Allow-Origin: http://foo.example.org
Vary: Origin
Access-Control-Allow-Methods: *
Access-Control-Allow-Headers: *
Access-Control-Expose-Headers: *
Access-Control-Expose-Headers:
Access-Control-Max-Age: 5
Access-Control-Allow-Credentials:
Expand Down Expand Up @@ -417,6 +417,6 @@ hello world
Access-Control-Allow-Origin: https://domain.com
Access-Control-Allow-Methods: *
Access-Control-Allow-Headers: *
Access-Control-Expose-Headers: *
Access-Control-Expose-Headers:
Access-Control-Max-Age: 5
Access-Control-Allow-Credentials:
110 changes: 110 additions & 0 deletions t/plugin/cors4.t
Original file line number Diff line number Diff line change
Expand Up @@ -639,3 +639,113 @@ Access-Control-Allow-Headers: request-h
Access-Control-Expose-Headers: expose-h
Access-Control-Max-Age: 10
Timing-Allow-Origin: http://testurl.domain.com
=== TEST 26: set route ( expose_headers not specified )
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"cors": {
"allow_credential": true,
"allow_headers": "**",
"allow_methods": "**",
"allow_origins": "**",
"expose_headers": "",
"max_age": 3500
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 27: remove Access-Control-Expose-Headers match
--- request
GET /hello HTTP/1.1
--- more_headers
Origin: http://sub.domain.com
--- response_headers
Access-Control-Allow-Origin: http://sub.domain.com
Access-Control-Allow-Methods: GET,POST,PUT,DELETE,PATCH,HEAD,OPTIONS,CONNECT,TRACE
Access-Control-Expose-Headers:
Access-Control-Allow-Headers:
Access-Control-Max-Age: 3500
Access-Control-Allow-Credentials: true
=== TEST 28: set route ( expose_headers set value )
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local code, body = t('/apisix/admin/routes/1',
ngx.HTTP_PUT,
[[{
"plugins": {
"cors": {
"allow_credential": true,
"allow_headers": "**",
"allow_methods": "**",
"allow_origins": "**",
"expose_headers": "ex-headr1,ex-headr2",
"max_age": 3500
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/hello"
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- request
GET /t
--- response_body
passed
=== TEST 29: Access-Control-Expose-Headers match
--- request
GET /hello HTTP/1.1
--- more_headers
Origin: http://sub.domain.com
--- response_headers
Access-Control-Allow-Origin: http://sub.domain.com
Access-Control-Allow-Methods: GET,POST,PUT,DELETE,PATCH,HEAD,OPTIONS,CONNECT,TRACE
Access-Control-Expose-Headers: ex-headr1,ex-headr2
Access-Control-Allow-Headers:
Access-Control-Max-Age: 3500
Access-Control-Allow-Credentials: true

0 comments on commit 53661ea

Please sign in to comment.