如何保护“公众”?垃圾邮件 REST 服务的一部分?
我有一个相当完整的 REST 服务,并将与 iOS 应用程序一起使用。它是使用 Ruby/Sinatra 构建的,但我认为这在这里并不重要。
我正在对各种端点使用基于 SSL 的 HTTP 基本身份验证,并且该部分运行良好。
问题是: 如何阻止垃圾邮件发送者等调用不受 HTTP 基本身份验证保护的 REST 服务部分?
示例:用户注册
假设 REST 调用是(POST) .../register_account 在正文中传递 JSON 对象。
由于显而易见的原因,此调用不能期望链接到用户帐户的用户名/密码。
想法是:
1)应用程序有自己的“用户名”/密码,一些调用会检查应用程序凭据。 问题:root 设备等可能会发现这些凭据。
2) 应用程序通过 HTTP 标头将秘密令牌传递给这些调用的 REST 服务。 问题:与(1)相同,
有没有常用的技术来防止此类垃圾电话?我想也许可以在其中引入 iPhone 的设备 ID,但尚未确定具体的方法。
谢谢
I have a REST service that's reasonably complete and will be used with an iOS app. It's built using Ruby/Sinatra but I don't think that really matters here.
I'm using HTTP Basic Authentication over SSL for various endpoints and that part is working very well.
Question is:
How do I stop spammers etc from calling parts of the REST service that aren't protected via HTTP Basic Authentication?
Example: User Registration
Let's assume the REST call is (POST) .../register_account passing a JSON object in the body.
For obvious reasons, this call cannot expect a username/password linked to a user account.
Ideas are:
1) The app has its own 'username' / password and some calls would check for app-credentials.
Problem: Rooting the device etc could unearth those credentials.
2) The app passes a secret token via a HTTP header to the REST Service for those calls.
Problem: Same as (1)
Are there any techniques commonly used out there to prevent such spam calls? I'm thinking maybe introduce the iPhone's device id in the mix but haven't identified a definite approach yet.
Thanks
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
虽然特定于应用程序的代码对于防范垃圾邮件的第一道防线来说是个好主意,但您仍然应该对您关心的任何服务实施一些速率限制。
例如,如果您在 REST 服务上使用会话,您可以轻松地对单个会话处理的调用数量进行速率限制。会话根本不需要进行身份验证,仅用于在发出请求时识别单个客户端。如果他们尝试在没有打开会话的情况下进行连接,则只需简单地重定向回所请求的服务即可,并且几乎所有 Web 框架或堆栈都内置了此功能。
您还可以对其他属性(例如 IP 或用户)进行速率限制。代理指纹,但这些方法不如基于会话的方法可靠。
While the app-specific code is a good idea for a first line of defense against spam, you should still implement some rate-limiting on any services you are concerned about.
For example, if you use sessions on your REST services, you can easily rate-limit the number of calls you process from a single session. The session doesn't have to be authenticated at all and is only used to identify a single client while they are making requests. A simple redirect back to the requested service if they try to connect without an open session is all that's needed, and virtually all web frameworks or stacks have this built in.
You can also rate-limit on other properties, such as IP or user-agent fingerprint, but those are less reliable than a session-based method.
一般来说,一种常见的方法是 API 密钥,它与您上面描述的秘密令牌相同。您可以将其硬编码到您的应用程序中,并使其他人很难对其进行逆向工程(隐藏它,从存储在应用程序中不同位置的各个部分构建它,等等)。您是正确的,因为坚定的攻击者将能够恢复密钥(如果您的应用程序可以这样做,则有权访问您的应用程序的其他人也可以)...但是您可以使其变得更加困难,希望它不会不值得花费时间和精力这样做。
您还可以考虑部署相互验证的 SSL,以便您的服务器将仅接受来自您的应用程序的传入连接,并且您的应用程序将仅与您的服务器进行通信。
这是高级方法。创建自签名服务器 SSL 证书并部署在您的 Web 服务器上。然后创建一个自签名客户端并将其作为资源部署在您的应用程序中。将服务器配置为需要客户端 SSL 身份验证并仅接受您生成的客户端证书。将客户端配置为使用该客户端证书来标识自身,并且仅接受您在服务器上安装的该部分的一个服务器端证书。
如果您的应用程序以外的某人/某物尝试连接到您的服务器,则不会创建 SSL 连接,因为服务器将拒绝不提供您已包含在应用程序中的客户端证书的传入 SSL 连接。
In general, a common approach is the API Key, which is the same as the secret-token you describe above. You can hardcode this into your application and make it difficult for someone to reverse engineer it (hide it, build it up from various parts stored at different places within your application, etc). You are correct in that a determined attacker will be able to recover the key (if your app can do so, someone else with access to your app can as well)...but you can make it more difficult where, hopefully, it wouldn't be worth the time and effort to do so.
You could also look at deploying mutually-authenticated SSL, so that your server will only accept incoming connections from your app and your app will only communicate with your server.
Here's the high-level approach. Create a self-signed server SSL certificate and deploy on your web server. Then create a self-signed client and deploy that within your application as a resource. Configure the server to require client-side SSL authentication and to only accept the client certificate you generated. Configure the client to use that client-side certificate to identify itself and only accept the one server-side certificate you installed on your server for that part of it.
If someone/something other than your app attempts to connect to your server, the SSL connection will not be created, as the server will reject incoming SSL connections that do not present the client certificate that you have included in your app.
这确实很旧,但你可以做点什么。我会创建一个基于时间的秘密令牌。您可以随请求一起发送的几秒钟后就会过期的内容。由于您的 iOS 应用程序源代码不公开,因此您需要对其保密。您需要确保您的时间在应用程序和服务器之间同步。您可以将时间从移动应用程序发送到服务器并计算偏移量(如果有)。这将阻止您的应用程序以外的任何其他程序在您通过身份验证之前与您的 API 进行通信。
该秘密基于手机独有的东西,只有您知道那是什么。服务器端也必须知道这种唯一性。
This is truly old, but there is something you can do. I would create a time-based secret token. Something that expires in seconds that you can send along with the request. Since your iOS app source code isn't public, it's just up to you to keep it secret. You need to ensure that your time is synced between the app and the server. You can send the time from the mobile app to the server and calculate an offset (if there is one). This will prevent anything other than your app from talking to your API before you're authenticated.
Base the secret on something that is unique to the phone and only you would know what that is. That uniqueness would also have to be known on the server side.
您可以使用
request.ip
跟踪IP地址并围绕它编写一些逻辑。You could track ip addresses using
request.ip
and write some logic around that.