尝试 Deno 并探索安全/权限系统很愉快。我有一个连接到 redis 的简单 Web 应用程序,我正在配置 docker-compose 设置。
容器网络中的主机名很简单:
redis
。当使用 url redis://redis:6379
连接到 redis 容器时,deno 应用程序报告错误:
error: Uncaught (in promise) Error: getaddrinfo ENOTFOUND redis
我已经缩小了问题范围,这似乎是由于我使用限制性
allow-net
语法来专门允许通过主机。就我而言,我想通过 redis
主机名。
CMD ["run", "--allow-net=redis:6379,[::]:8000", "--allow-env", "--allow-read", "main.ts"]
如果我将其更改为
CMD ["run", "--allow-net", "--allow-env", "--allow-read", "main.ts"]
并允许任意连接,redis连接成功。使用限制性主机名语法时,Deno 允许的 redis 协议是否存在问题,或者这里发生了其他问题?
当您指定 --allow-net=redis:6379 时,Deno 会严格将网络访问限制为端口 6379 上的主机 redis。但是,DNS 解析(将主机名 redis 转换为其 IP 地址的过程)需要以下网络访问权限:在这种情况下不被授予。结果,Deno 无法解析主机名,导致错误:
error: Uncaught (in promise) Error: getaddrinfo ENOTFOUND redis
要解决此问题,您需要通过在 --allow-net 标志中指定不带端口的主机名来允许 Deno 对主机名执行 DNS 解析。修改您的命令如下:
CMD ["run", "--allow-net=redis,[::]:8000", "--allow-env", "--allow-read", "main.ts"]
通过包含不带端口的 redis,您将允许 Deno 解析主机名并连接到该主机上的任何端口。如果你想严格限制redis的访问端口6379,你可以同时指定主机名和带有端口的主机:
CMD ["run", "--allow-net=redis,redis:6379,[::]:8000", "--allow-env", "--allow-read", "main.ts"]
说明:
不带端口的主机名:将 redis(不带端口)添加到 --allow-net 允许 Deno 通过允许 DNS 查询所需的网络访问来解析主机名。 特定端口访问:包括 redis:6379 确保在解析主机名后,Deno 可以专门连接到 redis 主机上的端口 6379。 DNS 解析需要权限:Deno 的安全模型需要所有网络访问的显式权限,包括 DNS 查找。 为什么会发生这种情况?
当您指定具有端口的主机(例如 redis:6379)时,Deno 只会将网络访问限制到该特定端点。它不包括 DNS 解析或该主机上任何其他端口的权限。 DNS 解析需要网络访问 DNS 服务器,除非您允许,否则不允许这样做。
参考 Deno 手册:
当 --allow-net 标志与主机名一起使用时,Deno 允许对该主机名进行网络访问。如果指定了端口,Deno 仅允许网络访问指定主机名上的该端口。
补充说明:
安全考虑:虽然指定不带端口的redis会打开该主机上的所有端口,但在redis指向受控容器的Docker环境中,这通常是可以接受的。 主机名的通配符端口:如果您需要更严格地限制端口,您可能需要调整网络设置或接受 DNS 解析需要更广泛的权限。 更新命令示例:
CMD ["run", "--allow-net=redis,redis:6379,[::]:8000", "--allow-env", "--allow-read", "main.ts"]
或者,如果您愿意允许 Redis 上的所有端口:
CMD ["run", "--allow-net=redis,[::]:8000", "--allow-env", "--allow-read", "main.ts"]
通过更新 --allow-net 标志以包含不带端口的主机名,您可以允许 Deno 执行 DNS 解析,这应该可以解决 ENOTFOUND 错误并允许您的应用程序成功连接到 Redis。