【问题标题】:Allow only a single specific IP address on Nginx under reverse proxy反向代理下仅允许 Nginx 上的单个特定 IP 地址
【发布时间】:2018-08-26 21:51:34
【问题描述】:

我有一个在 localhost 上运行的 api。为了允许外部访问特定域路径下的 API,我设置了反向代理。这部分工作正常。现在我正在尝试过滤访问并只允许单个 IP 连接到 API,换句话说,拒绝除特定 IP 之外的所有 IP 连接。

通过下面的配置,所有 IP 都被成功阻止,但它也阻止了我想要允许的一个 IP。我已经研究并尝试了几个修复程序,我怀疑我需要在反向代理下获取 real_IP,但还没有设法使其适用于我的具体情况。感谢所有帮助。这是我在可用站点中的 nginx 配置文件的代码:

server {

    root /var/www/html;
    index index.html index.htm index.nginx-debian.html;
    server_name foo.com www.foo.com;

    location / {

        allow XX.XX.XX.XX;
        #allow 127.0.0.1;
        deny  all;

        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;

    }


    listen [::]:443 ssl; # managed by Certbot
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/foo.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/foo.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}

XX.XX.XX.XX 是我想要允许的 ip,它实际上是服务器的实际 IP。但我不认为这有什么不同。我也尝试在“位置/{}”范围内添加以下内容,但没有运气:

set_real_ip_from XX.XX.XX.XX;
real_ip_header    X-Forwarded-For;
real_ip_recursive on;

【问题讨论】:

  • 使用 ufw 并拒绝或允许 IP 地址。或为了灵活修复您的代码以检查数据库中允许的 IP 地址
  • @numb3r 感谢您的回答。我有其他 API、APP 和几个与此服务器关联的域。因此,我需要阻止此 API 的 IP,但不希望将限制应用于我设置的其他服务的其他路径。这最终都在同一个IP地址下。 ufw可以进行这样的配置吗?如果可以,你能举个例子吗?谢谢
  • ufw 不解析主机名,因此它不能根据请求的主机名进行智能防火墙。
  • 看来您的 ip 解析有问题。因为我刚刚测试了你的例子。它按预期工作。让我们启用访问日志并查看它在请求中获取的 ip。在终端 tail -f /var/log/nginx/access.log 中运行,然后在另一个终端或浏览器中尝试执行请求。或禁用允许拒绝规则,只需添加 app.use((req, res, next) => {console.log(req.ip); next();}); 并捕获该真实 IP
  • 如果您想告诉服务器在对foo.com 的请求中使用环回接口,然后在/etc/hosts 中添加这样的行:127.0.0.1 foo.com www.foo.com,这将告诉您的服务器不请求 DNS 服务器解析该主机名这将导致来自外部的请求。

标签: nginx


【解决方案1】:

我认为将控制权放在网络服务器级别并不是一个好主意。

授予访问权限是更多防火墙任务。

但在某些情况下,当您希望动态授予对已注册主机的访问权限而无需重新启动或配置某些东西时 - 最好在应用程序级别制作保护方法。


现在我可以推荐以下之一:

1) 把防火墙放在app或者nginx前面。你可以使用ufw

2) 将访问控制置于应用级别。如果是nodejs app写中间件:

middlewares/allowByIp.js

'use strict';

cons db = require('../database'); // mongoose models abstraction

const AllowedHosts = db.model('AllowedHost');

module.exports = async (req, res, next) => {

  const isAllowed = await AllowedHosts.findOne({ip: req.ip});
  if (!isAllowed) {
    res.status(403).send('Forbidden');
  }

  next();
};

或:

'use strict';

cons allowedHosts = [... ip listing ...]; // take care of graceful restarting of Your app when You'll modify this array

module.exports = async (req, res, next) => {

  const isAllowed = allowedHosts.includes(req.ip);
  if (!isAllowed) {
    res.status(403).send('Forbidden');
  }

  next();
};

app.js

const express = require('express');
const app = express();

const ipFirewall = require('middlewares/allowByIp');
app.use(ipFirewall);

...

app.listen(3000);


我已经检查了您的 nginx 示例,它按预期工作。

所以我怀疑 nginx 获得了不同的 ip。检查/var/log/nginx/access.log 获取您的 nginx 在源部分请求目标时获得的真实 IP 地址。

但是,如果您想在内部限制访问,告诉服务器在对foo.com 的请求中使用环回接口,然后在/etc/hosts 文件中添加这样的行:

127.0.0.1   foo.com www.foo.com

它会告诉您的服务器不要请求 DNS 服务器来解析该主机名,这将提供全局 IP 并根据来自外部的请求产生结果。

【讨论】:

    猜你喜欢
    • 2015-09-11
    • 2021-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多