from fastapi import FastAPI
from fastapi.middleware.trustedhost import TrustedHostMiddleware
app = FastAPI()
# Define a list of trusted hosts
trusted_hosts = [
"my_ip_address"
]
# Add TrustedHostMiddleware to the app with the list of trusted hosts
app.add_middleware(TrustedHostMiddleware, allowed_hosts=trusted_hosts)
当我在本地计算机上开发应用程序并尝试访问
/docs
时,我必须将“127.0.0.1”设置为我的可信主机。这很好用。但现在我已经将应用程序放在服务器上,当我尝试使用计算机的 Ip 访问“/docs”时,我被拒绝了。
我在几个网站上检查了我的IP,我还检查了request.client.host以确认IP。但我无法访问“/docs”。
我可以访问路线的唯一方法是,如果我设置
trusted_hosts = ["*"]
但这没有意义。
还有人遇到类似问题吗?
TrustedHostMiddleware
(另请参阅相关 Starlette 文档)“强制所有传入请求都具有正确设置的 Host
标头,以防止 HTTP 主机标头攻击”。
Host
标头不是客户端的IP地址,而是主机名,例如localhost
、example.com
、*.example.com
等(没有包括端口号)。因此,当使用 TrustedHostMiddleware
时,FastAPI 只是检查 Host
标头(如果存在)——顺便说一下,攻击者很容易在 HTTP 请求中欺骗它,使其看起来像请求来自不同的域(例如,您的服务器允许的域)——它不会检查客户端的 IP 地址。例如,如果您编辑系统上的 /etc/hosts
文件以将主机名分配给
127.0.0.1
,例如
example.test
(有关如何执行此操作,请参阅此答案 的解决方案 1),然后尝试访问API 通过在浏览器地址栏中输入
example.test:8000
,
Host
标头将为
example.test
而不是
localhost
。下面给出了工作示例。工作示例
from fastapi import FastAPI, Request
from fastapi.middleware.trustedhost import TrustedHostMiddleware
app = FastAPI()
app.add_middleware(
TrustedHostMiddleware, allowed_hosts=["localhost", "example.test"]
)
@app.get("/")
async def main(request: Request):
print(request.headers['host'])
return {"message": "Hello World"}
仅将 API 访问限制为特定 IP 地址this 类似的方法,其中维护 safe_clients
列表,并根据该列表检查每个请求的 IP 地址。工作示例
from fastapi import FastAPI, Request, status
from fastapi.responses import JSONResponse
app = FastAPI()
ALLOWED_IPS = ["127.0.0.1"]
@app.middleware('http')
async def trusted_ips_middleware(request: Request, call_next):
ip = str(request.client.host)
print(ip)
if ip not in ALLOWED_IPS:
return JSONResponse(content="403 - Forbidden: Access is denied", status_code=403)
return await call_next(request)
@app.get("/")
async def main():
return {"message": "Hello World"}