How to protect the 'public' part of a REST

2019-02-01 23:34发布

问题:

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

回答1:

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.



回答2:

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.



回答3:

You could track ip addresses using request.ip and write some logic around that.