apache 如何限制我网站的API用户?

km0tfn4u  于 2023-08-07  发布在  Apache
关注(0)|答案(8)|浏览(126)

我的网站的合法用户偶尔会用API请求攻击服务器,导致不期望的结果。我想设定一个限制,每5秒不超过一个API调用,或者每分钟不超过n个调用(还没有弄清楚确切的限制)。显然,我可以在数据库中记录每个API调用,并对每个请求进行计算,看看它们是否超过了限制,但每个请求上的所有这些额外开销都将违背目的。我可以使用哪些其他资源密集度较低的方法来设定限制?我正在使用PHP/Apache/Linux,因为它值得。

fruv7luv

fruv7luv1#

好吧,没有办法在不向服务器写入任何数据的情况下完成我要求的任务,但我至少可以消除对每个请求的日志记录。一种方法是使用“漏桶”节流方法,其中它仅跟踪最后一个请求($last_api_request)和时间帧的请求数量/限制的比率($minute_throttle)。漏桶永远不会重置计数器(不像Twitter API的节流阀每小时重置一次),但是如果桶满了(用户达到了限制),他们必须等待n秒,让桶空一点,然后才能发出另一个请求。换句话说,它就像一个滚动限制:如果在该时间帧内存在先前的请求,则它们正在缓慢地从桶中泄漏出来;它只会在你装满水桶的时候限制你。
此代码片段将在每个请求上计算新的$minute_throttle值。我在$minute_throttle中指定了 minute,因为您可以为任何时间段添加限制,例如每小时,每天等。尽管多于一个将很快开始使用户感到困惑。

$minute = 60;
$minute_limit = 100; # users are limited to 100 requests/minute
$last_api_request = $this->get_last_api_request(); # get from the DB; in epoch seconds
$last_api_diff = time() - $last_api_request; # in seconds
$minute_throttle = $this->get_throttle_minute(); # get from the DB
if ( is_null( $minute_limit ) ) {
    $new_minute_throttle = 0;
} else {
    $new_minute_throttle = $minute_throttle - $last_api_diff;
    $new_minute_throttle = $new_minute_throttle < 0 ? 0 : $new_minute_throttle;
    $new_minute_throttle += $minute / $minute_limit;
    $minute_hits_remaining = floor( ( $minute - $new_minute_throttle ) * $minute_limit / $minute  );
    # can output this value with the request if desired:
    $minute_hits_remaining = $minute_hits_remaining >= 0 ? $minute_hits_remaining : 0;
}

if ( $new_minute_throttle > $minute ) {
    $wait = ceil( $new_minute_throttle - $minute );
    usleep( 250000 );
    throw new My_Exception ( 'The one-minute API limit of ' . $minute_limit 
        . ' requests has been exceeded. Please wait ' . $wait . ' seconds before attempting again.' );
}
# Save the values back to the database.
$this->save_last_api_request( time() );
$this->save_throttle_minute( $new_minute_throttle );

字符串

wecizke3

wecizke32#

您可以使用token bucket algorithm控制速率,这与漏桶算法相当。请注意,您必须共享存储桶的状态(即令牌的数量)。因此,您可能需要考虑使用锁定来避免竞态条件。
好消息是:我做的一切都是为了你:bandwidth-throttle/token-bucket

use bandwidthThrottle\tokenBucket\Rate;
use bandwidthThrottle\tokenBucket\TokenBucket;
use bandwidthThrottle\tokenBucket\storage\FileStorage;

$storage = new FileStorage(__DIR__ . "/api.bucket");
$rate    = new Rate(10, Rate::SECOND);
$bucket  = new TokenBucket(10, $rate, $storage);
$bucket->bootstrap(10);

if (!$bucket->consume(1, $seconds)) {
    http_response_code(429);
    header(sprintf("Retry-After: %d", floor($seconds)));
    exit();
}

字符串

tgabmvqs

tgabmvqs3#

最简单的解决方案是每24小时给予每个API密钥有限数量的请求,并在某个已知的固定时间重置它们。
如果他们用尽他们的API请求(即。计数器达到零或极限,这取决于您计数的方向),停止向他们提供数据,直到您重置他们的计数器。
这样的话,他们最大的利益就是不向你提出要求。

vq8itlhq

vq8itlhq4#

我不知道这个线程是否还活着,但我建议将这些统计数据保存在内存缓存中,比如memcached。这将减少将请求记录到数据库的开销,但仍能达到目的。

xmjla07d

xmjla07d5#

你说“所有这些额外的开销在每个请求上都会破坏目的”,但我不确定这是正确的。目的不就是为了防止服务器瘫痪吗?这可能是我实现它的方式,因为它实际上只需要快速读/写。如果担心性能问题,您甚至可以将API服务器检查外包到不同的DB/磁盘。
然而,如果你想要替代方案,你应该看看mod_cband,一个第三方apache模块,旨在帮助带宽限制。尽管主要用于带宽限制,但它也可以基于每秒请求数进行节流。我从来没有使用过它,所以我不知道你会得到什么样的结果。还有另一个名为mod-throttle的模块,但该项目现在似乎已经关闭,并且从未为Apache 1.3系列以上的任何版本发布过。

rseugnpd

rseugnpd6#

除了从头开始实现之外,你还可以看看API基础设施,比如3scale(http://www.3scale.net),它可以进行速率限制以及一系列其他东西(分析等)。这里有一个PHP插件:https://github.com/3scale/3scale_ws_api_for_php
你也可以在API前面贴一些类似Varnish的东西,然后像这样限制API速率。

wswtfjt7

wswtfjt77#

难道这不能通过一次会议来完成吗?
比较microtime()$_SESSION['last_access_microtime']

sdnqo3pr

sdnqo3pr8#

在node js中,有一个名为expess-rate-limiter的包,它正在做你想要完成的事情。
它限制了一段时间内的请求数量。我不知道PHP中是否也有同样的东西。

相关问题