我正在为网站创建一个PHP API,我想限制对我们服务器上注册的域的API访问(以防止滥用API)。所以,这是我现在的方法,而且它在纸面上应该看起来很不错。
- API设置为
api.example.com
。
- 想要使用API的用户向我们注册,添加他的域并获取API密钥。
- API的用户将使用他的API密钥加密他的请求数据(通过
mcrypt
并通过发送它 cURL
至 api.example.com
。
- 我的服务器检查此API请求来自哪个域 并将该域与数据库中的API密钥相匹配。如果有API密钥,API会通过解密请求
mcrypt
使用该密钥然后使用相同的方法加密并发送结果。
我坚持第4步。最初,我打算使用HTTP_REFERER来检查它,但是因为cURL默认情况下不会发送一个,并且它很容易在用户端代码中伪造(据我记得CURLOPT_REFERER),我被困在这里。
有没有方法可以知道此API请求来自哪个域?我看到它可以用一些流行的API来完成,比如reCAPTCHA。由于共享主机(它们具有相同的IP),检查_SERVER [“REMOTE_HOST”]实际上不是一个选项,因此这将无法防止滥用(无论如何主要来自共享服务器)。
有没有这样的方法来检查它?谢谢!
@Shafee有一个好主意,只需要一些调整。我们专注于API调用的可见部分,即API密钥。这在URL中可见并告诉API 谁 正在请求数据。而不是试图阻止其他人窃取此密钥并使用他们截获的域运行他们自己的cURL调用,我们 能够 '只需添加'混合的另一个关键,这个拦截器不可见。我不是说停止检查请求来自何处,它仍然是在脚本早期发出无效请求的好方法,但是使用第二个密钥,您保证只有请求数据的人才知道如何获取数据(你相信他们不会把它交给任何人)。
因此,当用户注册密钥时,您实际上是在为用户分配两个不同的密钥。
API_KEY - 将您连接到您的域的公钥。系统会查找提供的域和密钥,以便查找下一个密钥。
MCRYPT_KEY - 这是用于通过Mcrypt实际加密数据的密钥。由于它是加密数据,因此只有请求者和服务器才知道它是什么。您使用密钥加密数据并将带有API密钥的加密输入发送到服务器,服务器找到通过已提供的API密钥和域(和IP)解密该输入所需的密钥。如果他们没有使用正确的密钥加密数据,那么使用正确的密钥进行解密将返回乱码和 json_decode()
call将返回NULL,允许脚本只返回'invalid_input'响应。
最终使用这种方法,我们甚至需要检查请求来自哪里(域/ IP)?使用这种方法实际上归结为API用户没有向其他用户泄露他们的API / MCRYPT密钥对,类似于不泄露您的用户名/密码。即便如此,任何网站都可以轻松注册以获取自己的密钥对并使用API。另外需要注意的是,除非最终用户使用正确的用户名和密码登录,否则API甚至不会返回对其服务器有用的任何内容,因此他们的结尾将已经拥有该信息。我们的服务器真正返回的唯一新功能是成功验证用户后的电子邮件地址。话虽如此,我们甚至需要使用cURL吗?我们不能简单地使用 file_get_contents('http://api.example.com/{$API_KEY}/{$MCRYPT_DATA}')
?我意识到我在回答中提出了更多问题......
你可以改变请求来自哪个ip,你可以做一个ptr搜索来获取该ip的域名,但是知道ip地址有多个域名,你最终会错误的,所以我推荐客户端在请求中发送他的域名,也许是HTTP_REFERER,并且你做了一个dns检查该域是否指向ip要求它,但是注意一个域,比如google.com,可以指向多个ip 。
(知识产权可能会被伪装成一些好的黑客技能,但据我所知)
如何引入第二个变量就像让我们说的那样 app id
。当用户注册其域时,将此id与域关联。用户需要提交 app id
每个请求都没有加密以及加密的api调用。那你就可以抬头了 app id
得到的 app secret
并尝试解密?
为了最好地防止滥用您的API,请限制请求的速度,或限制他们可以提出的请求数量。如果某人是愚蠢的并且共享他们的API密钥,他们将只限制他们自己的API使用,使那些打算滥用API获取他们自己的密钥的人更经济。
另外,如果有人决定使用您的API实现桌面应用程序,该怎么办?当然,他们不会要求他们的用户向他们发送他们的IP地址,以便他们可以将他们列入白名单?
此外,您可以组合限制速度/限制请求,并根据请求数限制速度,例如,如果您传递一定数量的数据,Verizon将如何限制其3G网络的速度。