is using access-control-allow-origin enough to prevent misuse of an api? - ruby-on-rails

I am making an api backend that makes use of another api,for example Twitter. (Please note the actual api isn't twitter but I am using them as an example).
Let's say that Twitter has a limit on the number of calls that can be made to their api and above this limit, it starts to charge my credit card. This is why it is very important to me that no one misuses my api.
I want to prevent people from looking at my frontend code and seeing which endpoint it hits, because if a malicious person were to do this, I would very quickly go over the limit and have to pay $$$.
My frontend code uses a get call to mybackend.com/twitter/api
Is it enough to simply add an Access-Control-Allow-Origin header to my backend?
headers['Access-Control-Allow-Origin'] = 'myfrontend.com'
The reason I am asking this is because I noticed that typing mybackend.com/twitter/api directly into the browser worked, which is not what I would expect if I had access-control-allow-origin set to a specific website.
Am I doing something wrong? How do I prevent someone from simply writing a script to hit my backend since it is clear that just typing it into the url of my browser works, despite me having an access-control-allow-origin header.

There are two possible solutions for your problem. You can try to implement a request signature for your API, to know exactly the source of it on your backend. You can take a look on how this works here.
The second option, and for me, a one witch fits your problem better, is to set up a Denial of service approach on your server Load Balancer to prevent multiple requests from a same origin, and so, don't let those kind of malicious requests hit your backend.

Related

Real use of same origin policy

I just got to know about the same origin policy in WebAPI. Enabling CORS helps to call a web service which is present in different domain.
My understanding is NOT enabling CORS will only ensure that the webservice cannot be called from browser. But if I cannot call it from browser I still can call it using different ways e.g. fiddler.
So I was wondering what's the use of this functionality. Can you please throw some light? Apologies if its a trivial or a stupid question.
Thanks and Regards,
Abhijit
It's not at all a stupid question, it's a very important aspect when you're dealing with web services with different origin.
To get an idea of what CORS (Cross-Origin Resource Sharing) is, we have to start with the so called Same-Origin Policy which is a security concept for the web. Sounds sophisticated, but only makes sure a web browser permits scripts, contained in a web page to access data on another web page, but only if both web pages have the same origin. In other words, requests for data must come from the same scheme, hostname, and port. If http://player.example tries to request data from http://content.example, the request will usually fail.
After taking a second look it becomes clear that this prevents the unauthorized leakage of data to a third-party server. Without this policy, a script could read, use and forward data hosted on any web page. Such cross-domain activity might be used to exploit cookies and authentication data. Therefore, this security mechanism is definitely needed.
If you want to store content on a different origin than the one the player requests, there is a solution – CORS. In the context of XMLHttpRequests, it defines a set of headers that allow the browser and server to communicate which requests are permitted/prohibited. It is a recommended standard of the W3C. In practice, for a CORS request, the server only needs to add the following header to its response:
Access-Control-Allow-Origin: *
For more information on settings (e.g. GET/POST, custom headers, authentication, etc.) and examples, refer to http://enable-cors.org.
For a detail read, use this https://developer.mozilla.org/en/docs/Web/HTTP/Access_control_CORS

Locking an API to App-Use only

I've written a rails back-end for the mobile app I'm working on and it occured to me that even though I'm using token authentication, anyone could write a malicious script that continually registers users / continually makes requests in attempts to fill the database / attack the server.
I guess there are two questions here:
1) What modifications would I need to make in order to ONLY allow API access from my mobile app
2) How can I protect my API urls?
Thanks :)
There are multiple things you can do to protect your API :
The simplest thing you can start with is verifying the user-agent header in your request. That usually gives you a good indicator of what the initiating device is.
That being said, it isn't always accurate and its definitely fakeable.
If you control the client side of the mobile app as well, you could encrypt the requests/responses with a cypher or key system which requires a key that only your mobile-app knows. Look at openssl for that... using a public/private key pair.
Token authentication is a good idea. I would actually look at oAuth or similar systems for authentication and keep your session timers short.
On top of that, you can probably add some rate control in order to limit consecutive calls from the same IP in a given timespan.
Finally, I would look at something like "fail2ban" or similar to automatically ban brute-force type attacks.

API requests with Net::HTTP very slow in production

I am making Google API request through application using RestClient library to get address.
Sample request code-
require 'rest-client'
require 'json'
gmaps_api_href = "https://maps.googleapis.com/maps/api/geocode/json?latlng=18.56227673,73.76804232&language=ar"
response = RestClient.get gmaps_api_href
result = JSON.parse(response)['results']
This request works fine on my local machine and it completes within 1-2secs. But on production instance it takes 20secs to finish one request.
Due to some security measures, we can not access production instance directly. So I am unable to find pin point for this delay.
After doing trial and error, we found that
If we make request using CURL, it takes 1 sec on server
If we make request using Net::HTTP, it takes 20sec to complete same as we were observed for RestClient.
If we make request using WebRequest in small .net app, that request complete within 1 secs.
Its difficult for me to get difference between above observations.
Please let me know why it is so? and what changes I have to do to make it work in my Rails App?
Are you using a Google API key? Your example does not show use of an API key. if not, I'd guess you are getting rate-limited by Google. On your server, you've probably already deployed a version of this app, which made lots of requests to Google without an API key in the fairly recent past, and Google noticed and it's rate-limiting software may be slowing down your requests made from that server. While your local machine hasn't in the past made an enormous amount of requests to the google api, so is not being rate-limited by google's servers.
It's possible Google's rate-limiting is paying some attention (for now!) to User-Agent, and the different user-agent sent by Curl somehow evades Google's rate-limiting that was triggered by the requests sent by RestClient with it's User-Agent (and RestClient may use net-http under the hood, and have the same User-Agent as it).
While one would hope that if you were rate-limited you'd get a "429 Too Many Requests" error response instead of just a slow response, it's possible RestClient hides this from you (I haven't used RestClient), and I've also seen some unpredictable behavior from Google rate-limiting defenses, especially when not using an API key on a service that requires one for all but a few sample requests. I have seen things similar to what you report in that case.
My guess is you're being rate limited because you are not using an API key. Get and use an API key from Google. Google still has rate limits when you are using an API key, but they are clearly advertised (for free? 2500 per-day, and no more than 10 per second. more if you pay) and should give more clear and predictable error messages when exceeded. That's part of why Google requires the api key, so they can reliably rate-limit you in clear ways.
https://developers.google.com/maps/documentation/geocoding/usage-limits
https://developers.google.com/maps/documentation/geocoding/intro#BYB

Questions about authentication

I'm drawing an architectural blank on good ideas of how to handle token authentication.
We have phone apps that generate REST requests to our backend API (rails).
Right now varnish is in front of our API and it's working great, however there's a gaping hole in how we handle auth: we dont.
I'm not looking to get flagged for asking for someone to solve it, I'm just asking from a high level how some have.
The phones create their device in the app via POST and get a unique token. They submit that token in all their other GET requests via Authorization: OAuth {token}. Our rails API handles this fine, but since the GETs are cached through varnish, we've hamstring'd it.
Due to performance we want to not cache each response per phone. The responses across the phones are all the same. If I were to add the token header to the hash in vcl_hash, that means that if 50 phones were to request /a/1, then we'd have 50 of the same items in cache, and the backend would get 50 requests. We'd like to avoid that.
I'm at a blank on how to authenticate the clients on a group level of some method.
Not sure if helpful:
Varnish 3.0.7 is what we have. Not against 4, just havent.
Every client goes through varnish, however we only care about User-Agent being android/ios. That part is done, anything else just goes straight to the API.
Given the previous point, it's safe to assume that all clients that we would hash/cache would have the same authorizations. It's purely the auth token issue. ie. All clients with a token we would just check to make sure it's valid and give them the cached resource. There will never be different resources across the clients using tokens.
If I'm understanding correctly, I see a couple potential approaches.
1) You can set up a backend that does nothing but validate the user - have Varnish validate anything that has not been restarted, and only after validation return the cached resource. Here's a good blog post that gives some VCL to get you started.
2) This is more speculative on my part - you can use ESI (Edge Side Includes) in Varnish to do the Auth. What I'm not sure about is if there's a way to kill the request or pass a failing status code from within an ESI fragment. If not, you'd end up returning the content even if the auth failed. Messy.

Change HTTP POST request to GET request for mobile client app

We have existed API like
/api/activiation_code
each time, the activiation_code will be different, then server will create a token for this call and return it, usually each call will have different activiation_code which return different token.
Since this API need server to create something so it is designed as POST.
Can we design this API as HTTP GET ?
What is the pro and cons ?
You could design the API to support GET requests, but I would not recommend this. If your API is accessible via a website, a user could accidentally activate an account multiple times since the URL will be stored in the browser's history. Additionally, web crawlers could potentially supply values to your API through the URL if you support GET requests.
POST requests are much better because the information is included in the body of the request, not the URL. Thus, it is much less likely that something will go wrong accidentally.

Resources