Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add referer-restriction plugin #2352

Merged
merged 3 commits into from
Oct 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ A/B testing, canary release, blue-green deployment, limit rate, defense against
- **Security**
- Authentications: [key-auth](doc/plugins/key-auth.md), [JWT](doc/plugins/jwt-auth.md), [basic-auth](doc/plugins/basic-auth.md), [wolf-rbac](doc/plugins/wolf-rbac.md)
- [IP Whitelist/Blacklist](doc/plugins/ip-restriction.md)
- [Referer Whitelist/Blacklist](doc/plugins/referer-restriction.md)
- [IdP](doc/plugins/openid-connect.md): Support external authentication services, such as Auth0, okta, etc., users can use this to connect to OAuth 2.0 and other authentication methods.
- [Limit-req](doc/plugins/limit-req.md)
- [Limit-count](doc/plugins/limit-count.md)
Expand Down
1 change: 1 addition & 0 deletions README_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ A/B 测试、金丝雀发布(灰度发布)、蓝绿部署、限流限速、抵
- **安全防护**
- 多种身份认证方式: [key-auth](doc/zh-cn/plugins/key-auth.md), [JWT](doc/zh-cn/plugins/jwt-auth.md), [basic-auth](doc/zh-cn/plugins/basic-auth.md), [wolf-rbac](doc/zh-cn/plugins/wolf-rbac.md)。
- [IP 黑白名单](doc/zh-cn/plugins/ip-restriction.md)
- [Referer 白名单](doc/zh-cn/plugins/referer-restriction.md)
- [IdP 支持](doc/plugins/openid-connect.md): 支持外部的身份认证服务,比如 Auth0,Okta,Authing 等,用户可以借此来对接 Oauth2.0 等认证方式。
- [限制速率](doc/zh-cn/plugins/limit-req.md)
- [限制请求数](doc/zh-cn/plugins/limit-count.md)
Expand Down
124 changes: 124 additions & 0 deletions apisix/plugins/referer-restriction.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
--
-- Licensed to the Apache Software Foundation (ASF) under one or more
-- contributor license agreements. See the NOTICE file distributed with
-- this work for additional information regarding copyright ownership.
-- The ASF licenses this file to You under the Apache License, Version 2.0
-- (the "License"); you may not use this file except in compliance with
-- the License. You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
local ipairs = ipairs
local core = require("apisix.core")
local http = require "resty.http"
local lrucache = core.lrucache.new({
ttl = 300, count = 512
})


local schema = {
type = "object",
properties = {
bypass_missing = {
type = "boolean",
default = false,
},
whitelist = {
type = "array",
items = core.schema.host_def,
minItems = 1
},
},
required = {"whitelist"},
additionalProperties = false,
}


local plugin_name = "referer-restriction"


local _M = {
version = 0.1,
priority = 2990,
name = plugin_name,
schema = schema,
}


function _M.check_schema(conf)
return core.schema.check(schema, conf)
end


local function match_host(matcher, host)
if matcher.map[host] then
return true
end
for _, h in ipairs(matcher.suffixes) do
if core.string.has_suffix(host, h) then
return true
end
end
return false
end


local function create_host_matcher(hosts)
local hosts_suffix = {}
local hosts_map = {}

for _, h in ipairs(hosts) do
if h:byte(1) == 42 then -- start with '*'
core.table.insert(hosts_suffix, h:sub(2))
else
hosts_map[h] = true
end
end

return {
suffixes = hosts_suffix,
map = hosts_map,
}
end


function _M.access(conf, ctx)
local block = false
local referer = ctx.var.http_referer
if referer then
-- parse_uri doesn't support IPv6 literal, it is OK since we only
-- expect hostname in the whitelist.
-- See https://github.com/ledgetech/lua-resty-http/pull/104
local uri = http.parse_uri(nil, referer)
if not uri then
-- malformed Referer
referer = nil
else
-- take host part only
referer = uri[2]
end
end


if not referer then
block = not conf.bypass_missing

elseif conf.whitelist then
local matcher = lrucache(conf.whitelist, nil,
create_host_matcher, conf.whitelist)
block = not match_host(matcher, referer)
end

if block then
return 403, { message = "Your referer host is not allowed" }
end
end


return _M
1 change: 1 addition & 0 deletions conf/config-default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ plugins: # plugin list
- jwt-auth
- zipkin
- ip-restriction
- referer-restriction
- grpc-transcode
- serverless-pre-function
- serverless-post-function
Expand Down
1 change: 1 addition & 0 deletions doc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ Plugins
* [cors](plugins/cors.md): Enable CORS(Cross-origin resource sharing) for your API.
* [uri-blocker](plugins/uri-blocker.md): Block client request by URI.
* [ip-restriction](plugins/ip-restriction.md): IP whitelist/blacklist.
* [referer-restriction](plugins/referer-restriction.md): Referer whitelist.

**Traffic**
* [limit-req](plugins/limit-req.md): Request rate limiting and adjustment based on the "leaky bucket" method.
Expand Down
1 change: 1 addition & 0 deletions doc/_sidebar.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
- [Limit Request](plugins/limit-req.md)
- [CORS](plugins/cors.md)
- [IP Restriction](plugins/ip-restriction.md)
- [Referer Restriction](plugins/referer-restriction.md)
- [Keycloak Authorization](plugins/authz-keycloak.md)
- [RBAC Wolf](plugins/wolf-rbac.md)

Expand Down
116 changes: 116 additions & 0 deletions doc/plugins/referer-restriction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-->

- [中文](../zh-cn/plugins/referer-restriction.md)

# Summary
- [**Name**](#name)
- [**Attributes**](#attributes)
- [**How To Enable**](#how-to-enable)
- [**Test Plugin**](#test-plugin)
- [**Disable Plugin**](#disable-plugin)


## Name

The `referer-restriction` can restrict access to a Service or a Route by
whitelisting request header Referers.

## Attributes

| Name | Type | Requirement | Default | Valid | Description |
| --------- | ------------- | ----------- | ------- | ----- | ---------------------------------------- |
| whitelist | array[string] | required | | | List of hostname to whitelist. The hostname can be started with `*` as a wildcard |
| bypass_missing | boolean | optional | false | | Whether to bypass the check when the Referer header is missing or malformed |

## How To Enable

Creates a route or service object, and enable plugin `referer-restriction`.

```shell
curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"uri": "/index.html",
"upstream": {
"type": "roundrobin",
"nodes": {
"127.0.0.1:1980": 1
}
},
"plugins": {
"referer-restriction": {
"bypass_missing": true,
"whitelist": [
"xx.com",
"*.xx.com"
]
}
}
}'
```

## Test Plugin

Request with `Referer: http://xx.com/x`:

```shell
$ curl http://127.0.0.1:9080/index.html -H 'Referer: http://xx.com/x'
HTTP/1.1 200 OK
...
```

Request with `Referer: http://yy.com/x`:

```shell
$ curl http://127.0.0.1:9080/index.html -H 'Referer: http://yy.com/x'
HTTP/1.1 403 Forbidden
...
{"message":"Your referer host is not allowed"}
```

Request without `Referer`:

```shell
$ curl http://127.0.0.1:9080/index.html
HTTP/1.1 200 OK
...
```

## Disable Plugin

When you want to disable the `referer-restriction` plugin, it is very simple,
you can delete the corresponding json configuration in the plugin configuration,
no need to restart the service, it will take effect immediately:

```shell
$ curl http://127.0.0.1:2379/v2/keys/apisix/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d value='
{
"uri": "/index.html",
"plugins": {},
"upstream": {
"type": "roundrobin",
"nodes": {
"39.97.63.215:80": 1
}
}
}'
```

The `referer-restriction` plugin has been disabled now. It works for other plugins.

1 change: 1 addition & 0 deletions doc/zh-cn/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
* [grpc-transcode](plugins/grpc-transcode.md):REST <--> gRPC 转码。
* [serverless](plugins/serverless.md):允许在 APISIX 中的不同阶段动态运行 Lua 代码。
* [ip-restriction](plugins/ip-restriction.md): IP 黑白名单。
* [referer-restriction](plugins/referer-restriction.md): Referer 白名单。
* [openid-connect](plugins/openid-connect.md)
* [redirect](plugins/redirect.md): URI 重定向。
* [response-rewrite](plugins/response-rewrite.md): 支持自定义修改返回内容的 `status code`、`body`、`headers`。
Expand Down
Loading