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

标签 php linux apache throttling

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

最佳答案

好的,如果没有 任何 写入服务器,就无法完成我所要求的操作,但我至少可以消除记录每个请求的情况。一种方法是使用“漏桶” throttle 方法,它只跟踪最后一个请求 ($last_api_request) 和时间范围内请求数/限制的比率 ($minute_throttle)。漏桶永远不会重置它的计数器(不像 Twitter API 的 throttle 每小时重置一次),但如果桶变满(用户达到限制),他们必须等待 n 秒让桶清空在他们可以提出另一个请求之前。换句话说,它就像一个滚动限制:如果在时间范围内有以前的请求,它们正在慢慢地漏出桶外;只有当你填满水桶时,它才会限制你。

此代码段将为每个请求计算一个新的 $minute_throttle 值。我在 $minute_throttle 中指定了 分钟,因为您可以为任何时间段添加 throttle ,例如每小时、每天等......尽管很快就会开始制作多个 throttle 这让用户感到困惑。

$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 );

关于php - 如何限制我网站的 API 用户?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1375501/

相关文章:

php - 删除具有相似名称的数据库重复项

c - 纯c中的文本文件到字符串数组?

java - 如何停止/解决 Java 应用程序在 Linux 窗口管理器中窃取焦点

php - Linux 上 Apache 的文件权限错误

java - Apache Tomcat 上的两个 MySQL 数据源配置

php - 仅使用 SamAccountName 和密码从 PHP 使用 LDAP 验证用户?

php - 分解 PHP 分页链接

php - 产品预订脚本 PHP

node.js - 我运行了一个 npm run build,将它放在 nodejs express.static 上,pm2 启动应用程序但无法获取 '/'

apache - 服务器或脚本问题