【问题标题】:Hiding API URLs and Prevent Brute Force Attacks隐藏 API URL 并防止暴力攻击
【发布时间】:2016-03-22 18:48:50
【问题描述】:
我刚刚在 node 中构建了一个 API。
我在我的 Angular 应用程序中调用此 API 来执行登录和注册等基本操作,例如:
self.register = function(username, password) {
return $http.post(API + '/auth/register', {
username: username,
password: password
})
}
所以我的问题是,任何人都可以看到该 API URL,所以是什么阻止他们“抨击”它以在那里创建用户。 (注意 API 在我的 JS 文件中是一个常量)。
登录也是如此,如何阻止某人暴力尝试数百万个用户名和密码组合。
你会推荐什么来保护这个?
谢谢。
【问题讨论】:
标签:
angularjs
node.js
api
security
【解决方案1】:
您可以使用一些 DDoS 保护,例如将 nginx 代理放在您的 nodejs API 前面并使用例如limit_req模块:http://nginx.org/en/docs/http/ngx_http_limit_req_module.html
对于蛮力,您可以实施一些锁定逻辑,在错误数量之后会阻止帐户一段时间,例如15-30 分钟甚至需要管理员操作。
对于需要登录的 API,您可以使用令牌保护。应在调用身份验证 API 时颁发令牌,并通过 HTTP 仅安全 cookie 进行设置作为响应。然后,您可以在 API 请求标头中传递此令牌,并且在 nodejs 中每个受保护的 API 执行之前检查它是否有效,如果不是则拒绝调用。
【解决方案2】:
+1 惊吓龙。
如果您生活在云端,则有一个更好的基于云的替代方案来使用 nginx - 使用云 WAF(Web 应用程序防火墙)作为您的 DDoS 缓解层。例如查看 Incapsula 和 CloudFlare。
如果 DDoS 对您来说是一个严重的问题,并且您愿意为防御它付费,那么我肯定会将这一问题留给专家。
【解决方案3】:
您基本上是在询问注册滥用和登录保护:
- 如何缓解帐户创建自动化?
- 如何减少用户/密码猜测?
谢天谢地,这些问题大多已解决。
为避免注册“抨击”,您需要中断自动化。这可以通过各种方法来实现,从宽松到严格:
- 如果 API 仅供特定应用/浏览器访问,您可以过滤掉所有其他访问者
- 按会话/IP 进行速率限制注册
- 需要通过验证码
- 验证电子邮件地址
- 要求提供私人敏感详细信息作为身份证明(例如电话号码、信用卡)
这样做的好处是,1-3 是可以轻松卸载到现代Web Application Firewall 的任务,无需任何额外的服务器端编码或额外负载。
对于“登录保护”,除了上述1-3种方法外,还有两种推荐:
Two-Factor Authentication (2FA) - 这基本上意味着除了他的“常规”密码外,用户还需要输入另一个身份验证令牌。此令牌可以由 TOTP(参见 Google Authenticator)生成,也可以由服务器通过短信、电子邮件、电话等方式发送的代码生成。
API Keys - 这被认为更安全,因为 API 密钥通常是非常长的唯一字符串,具有非常好的熵(与用户/密码组合相比)。有关 API 密钥的更多信息here。
在我走之前,有一个小评论:我看到一些以前的 cmets 提到 DDoS,我不能强调这一点 - 你不能靠自己来缓解 DDoS。但那是针对不同的线程。
祝你好运!
【解决方案4】:
最好通过 IP 限制反向代理、负载均衡器或任何其他入口点的速率。
如果你想在 nodejs 中做,我推荐rate-limiter-flexible
const { RateLimiterRedis } = require('rate-limiter-flexible');
const Redis = require('ioredis');
const redisClient = new Redis({
options: {
enableOfflineQueue: false
}
});
const opts = {
redis: redisClient,
points: 5, // 5 points
duration: 15 * 60, // Per 15 minutes
blockDuration: 15 * 60, // block for 15 minutes if more than points consumed
};
const rateLimiter = new RateLimiterRedis(opts);
self.register = async function(username, password) {
let blocked = false;
try {
await rateLimiter.consume(clientIP, 1);
} catch() {
blocked = true;
}
if (blocked) {
return false;
}
return $http.post(API + '/auth/register', {
username: username,
password: password
})
}