验证调用 API 的服务器的主机名

Posted

技术标签:

【中文标题】验证调用 API 的服务器的主机名【英文标题】:Verify hostname of the server who invoked the API 【发布时间】:2020-11-25 14:12:11 【问题描述】:

我有一个与多个运行 AWS Flask 服务器的 EC2 连接的 AWS ELB。我不确定 AWS ELB 是否将完整的请求传递给 EC2。我知道我们可以在 ELB 级别进行限制,但我只想对一个端点施加限制,并验证在 Flask 中调用端点的服务器的主机名。有可能吗?

【问题讨论】:

假设应用程序负载均衡器,您可以启用proxy protocol。但这仅提供客户端的IP,而不是其DNS。 IP 也可从x-forwarded-for 标头获得。 有没有办法验证SSL证书? 也许这不适合您的用例,但您可以考虑使用 ALB / WAF 在负载均衡器级别实施限制。 ELB 级别的限制......在我看来,ELB 不是实施任何类型限制的正确位置。在我看来,限制是权限的同义词。我宁愿设计一个基于 IAM(也许还有 API Gateway)的解决方案。如果想保持简单,您是否考虑在请求中添加参数/正文以及另一端所需的数据/信息的选项? HTTP 不能满足您的需要/期望。 @SanjaySharma aws.amazon.com/premiumsupport/knowledge-center/… 这样的东西怎么样?如果您的“另一台服务器”是 EC2 实例,这将很容易。只需将实例部署到特定的 IP 范围。如果不在 EC2 中,那么您可以在 APIGateway 实例上启用 AWS 安全性。然后创建一个角色/用户,并 ALLOW execute-api:Invoke for you Resource 仅当使用该特定角色/用户调用时。有意义吗? 【参考方案1】:

您可以尝试以下方法:

import socket
from flask import request


@app.route("/your_route", methods=["GET"])
def your_route():
    hostname, aliaslist, ipaddrlist = socket.gethostbyaddr(request.remote_addr)

请注意,依赖 remote_addr 是不可靠的,但是由于这与主题无关,我将参考使用 ProxyFix 的 answer:

有关socket.gethostbyaddr()的更多信息,请查看:socket.gethostbyaddr()

【讨论】:

您确定主机名不会被 ELB 屏蔽吗? @SanjaySharma 据此,您应该能够获取/设置别名,答案中提供了如何检索别名。 docs.aws.amazon.com/Route53/latest/DeveloperGuide/…【参考方案2】:

我建议您在这种情况下使用装饰器模式,即您添加一个新的配置选项 IP_LIST,其中包含某种用逗号分隔的地址集。

IP_LIST = "127.0.0.1,127.0.0.2,..."

然后添加一个新的装饰器函数,并用装饰器装饰任何端点。

def ip_verified(fn):
    """
    A custom decorator that checks if a client IP is in the list, otherwise block access.
    """

    @wraps(fn)
    def decorated_view(*args, **kwargs):
        ip_list_str = current_app.config['IP_LIST']
        ip_list = ip_list_str.split(",") if ip_list_str else []

        if request.headers.getlist("X-Forwarded-For"):
            remote_ip = request.headers.getlist("X-Forwarded-For")[0]
        else:
            remote_ip = request.remote_addr

        if remote_ip not in ip_list:
            return "Not sufficient privileges", 403

        return fn(*args, **kwargs)

    return decorated_view

@app.route("/your_route", methods=["GET"])
@ip_verified
def your_route():
    ...

【讨论】:

【参考方案3】:

一种选择是使用Network Load Balancer,它保留发出请求的客户端的IP 地址。您甚至可以让 NLB 像 ELB 一样执行the TLS termination。 NLB 不会更改网络请求中的数据,除非您选择使用 TLS 终止。

【讨论】:

以上是关于验证调用 API 的服务器的主机名的主要内容,如果未能解决你的问题,请参考以下文章

WEB API 2 自托管主机名问题

根据 Google Play 商店在应用程序中正确的主机名验证器

调用zabbx的api接口获取IP地址和主机名

调用zabbx的api接口获取IP地址和主机名

Spring saml 与 IDP 服务器的集成使名称的 SSL 对等点主机名验证失败:null

zabbix api 获取所有主机名