How secure is it to call "secret" URLs in an iOS app? - iphone

We want to use a web service in our app which obviously requires to call a URL. It's not HTTPS, just plain old HTTP, using NSURLConnection.
The problem is: This web service is VERY expensive and every thousand calls costs us real money. The fear is that someone could figure out which URL we call and then misuse that, letting the costs explode. There is no way for us to track if a call to that web service was legitimate.
We're calculating based on how many apps we sell, multiplied by an assumption of how often that app will be used per user in average. We have some good statistics on which we base our assumptions.
Are there known ways of figuring out which URL an app is calling on the Internet to retrieve information?

You could easily use a network sniffer while the phone is on WiFi to figure out this information. It sounds like it is actually critical that you use SSL with some sort of secure token in the URL.
If this is not an option perhaps you can provide your own proxy service that would use SSL and security tokens? Proxy also grants the ability to throttle requests and block users known to be malicious. Throttling puts an upper bound on the expense each user can incur within a given time interval. Another benefit of a proxy is that it allows one to gather statistics and measure the costs incurred by different users facilitating malicious user detection and business planning. Proxy could also save you some money if the service behind it is stateless by adding a cache that would remove a lot of expensive calls.

If the Web service is not encrypted, it would be trivial to use a proxy to intercept the Web requests made by the phone. If the expensive Web service does not offer at least some form of basic authentication, I would seriously reconsider including its URL in a public app.

Using plain URLs is a sure way of letting script kiddies run you out of business. If there is no way for you to track if a call to the expensive web service was legitimate, set up your own web service that fronts the real web service to make sure that your own web service can verify the legitimacy of the call before forwarding the request to the real web service.

Yes, there's plenty of ways to do this. For one example, hook up the iPhone to a wifi network, in which the router has a transparent proxy. Examine the proxy's logs. You'll see all URLs. Depends how determined your users are, but this is rather easy.

Ignoring the fact that people who jailbreak their devices could possibly look at your application, I believe it is possible to examine traffic like any other device (laptop, tablet, etc.) if someone was sniffing traffic over a WiFi hotspot using applications such as WireShark. However, I doubt there would be much risk of this over a cellular 3G network.

Good question.
As many have said, yes, it's easy to figure out the urls your app requests.
Note about HTTPS:
But since you are using HTTPS you are okay because over HTTPs the domain will be obscured to the IP address, and people cannot see the URL query string parameters. For example, if your URL was https://somewebsite.com?uid=mylogin&pass=mypass, they definitely won't be able to see "uid=mylogin&pass=mypass", and they probably can only see the IP address, not the domain name itself. (see https://serverfault.com/questions/186445/can-an-attacker-sniff-data-in-a-url-over-https)
Sidenote:
Might be safe to assume that Apple performs some sort of HTTP request diagnostics when they review your app -- which would make sense because it's in their best interest to try and figure out what your app does from many angles.

Related

Restrict REST API to Mobile App Only - Proposed Method

I read a lot that you can't restrict your Public REST API to only your mobile application, but I have an idea and I want opinions on it:
Variable App Key Method
Mobile App
Get IP address of current connection
Use a secret algorithm to generate a hashed AppKey from IP address.
Send the AppKey with each API request
Server Side
Check the IP address of incoming request
Generate AuthKey from that IP address using same secret algorithm.
Compare AuthKey with AppKey, if they match then you know that your
Application is talking to you, because only the application knows
the secret algorithm.
When IP address changes:
On mobile App regenerate the AppKey using the new IP address
Server side will always generate same key because it depends
on IP address of the request
The main advantage of this is that the AppKey will always change, which is better than hardcoding 1 application key inside the code, which can be easily stolen by reading request headers. And even if you stole the AppKey from a user you must be using the same IP address where that key was generated.
Any thoughts?
The "secret" algorithm would have to be in the app... given to everybody. It is not secret at all. Security by obscurity is bad anyway, you should not have supposedly secret algorithms, because it's hopeless to keep them confidential. In this case the algorithm is trivially revealed.
Also refer to Schneier's law. :)
Edit:
So theoretically, this can never be secure, because any algorithm you put into the app needs to run on the client, and hence can be analysed and decompiled. But one can argue that it doesn't need to be theoretically secure, it is ok if it's "secure enough", ie. the risk is low enough, because for example the effort needed to get to the algorithm is too much.
But then consider the two possible options:
This is a really cool API that everybody totally wants to build a client for, or there is at least one such party. In this case, no effort is too much, and the algorithm will be "broken", that is, it will be decompiled and implemented in a different client.
People don't care all that much about this API, it is not very important for anybody else to build a client. In this case they probably won't build a client anyway, and much simpler methods can be used to prevent other clients from popping up with a reasonable success.
But obviously, it's your choice, an approach similar to what you describied does raise the bar somewhat - just don't expect it to be actually secure, because it will not be.

Simplest server to server authentication

I have microservice on a new server/vps that will only ever be called via REST by monolith app to perform some heavy lifting and then post the operation results back to the monolith in few minutes.
How should I protect these two endpoints? I think my main goal, for now, is just preventing someone that found servers address to be able to do anything.
Almost every solution I google seems like overkill/premature optimization.
Is it sufficient that I generate random long token once on each machine and then just pass it to headers and check it's presence on the other end?
Do I even need to SSL this? As far as I understand we need SSL encryption for clients that are trying to send sensitive data via wireless or unsafe shared networks.
What are the chances(is it even possible?) that somebody is gonna eavesdrop between two digitalocean vps's sending data via http? Did it ever happen before ?
Q: Is it sufficient that I generate random long token once on each machine and then just pass it to headers and check it's presence on the other end?
A: Generally microservices are behind a GateKeeper/Gateway(nginx,haproxy) so you can expose the endpoints you want. In your case I would recommend to create a private network between the two vps's and expose your microservice on that internal IP.
Q: Do I even need to SSL this? As far as I understand we need SSL encryption for clients that are trying to send sensitive data via wireless or unsafe shared networks.
A: No. If you use internal networks and don't expose to the public then there is no need for SSL/TLS. If you would do something with Tier 3/4 then you would need encryption for cross datacenter communication.
Q: What are the chances(is it even possible?) that somebody is gonna eavesdrop between two digitalocean vps's sending data via http? Did it ever happen before ?
A: There are bots that scan for open ports on servers/computers and try to penetrate them with exploits. In all cases always use a firewall like UFW/firewalld.
So let's say you have two servers with these microservices using the internal private network from your favorite provider:
VPS1 (ip = 10.0.1.50)
FooBarService:1337
BarFooService:7331
VPS2 (ip = 10.0.1.51)
AnotherMicroService:9999
Now both VPS's can access each other's services by simply calling the ip + port.
Good luck.
There's a few simple solutions you could use to authenticate both servers back and forth. The one I would recommend if you want to keep it simple, as you say, is Basic Auth. As long as you're utilizing that over an SSL/HTTPS connection, it suffices as a super simple way to authenticate each end.
You state it is your main goal to protect these endpoints, but then ask if SSL/HTTP is even needed. If these servers are vulnerable to the web in any way, then I would say yes, your endpoints need to be protected, and if you're transmitting sensitive data, then you need to be sending it through a secure stream.
If you believe the data you're sending is not very sensitive, and is likely that no one that knows these two endpoints will even know how to properly manipulate your data by sending fake requests, then sure, you don't need any of this, but then you assume the risk and responsibility for if and when it ever is exposed. Basic Auth is super easy, and with LetsEncrypt it's incredibly easy to obtain an SSL certificate for free. It's good experience, so may as well try it out and protect these endpoints and ensure that they're safe.

Authenticating lots of clients for a REST API

We have a large number of small devices deployed in the wild that communicate with a central server via a REST API. It will send a status update on a regular basis with some sensor data and will also ask the server if there are any software updates that need to be applied. If there are, it will download it etc.
I'd like some way to prevent my server API from being used by unauthorised clients. Here are the solutions that I have and the issues which I anticipate. This question is somewhat open ended but it is mostly a question of best practices for, what I think is, a common situation.
Keep a single username/password on the server and then use basic auth over https. This is simple but if I change it, I'd have to somehow change the credentials on all of my devices (which number in the low thousands). This is hard to do reliably. There's also a problem with how the devices are going to get the update without first changing their creds.
The second is to create a username/password for every device. Then I can update individual ones and manage them but there's a lot of state on the server and I'm worried about having this much data on the server.
Some kind of automatic key based system whereby the devices can ask for an expirable key and then use that for all transactions. If the key expires or is invalidated, that device can't connect anymore. This would necessitate some kind of id for the device which I'm not sure how to handle.
So, how would I do this?
Update
In our setup, we have assigned hostnames for each of the devices we're going to deploy created beforehand. Once the devices switch on, they will contact the server with their hostnames and thereby register themselves. The MAC address and other information is passed as part of the initial registration handshake.
So, the "unique identifer" which was mentioned in the answer (and comment) by Noksi is the hostname. This can be easily spoofed (since the hostnames have a pattern). However, when the devices first come online, we can get the mac and, after that, only refresh the token if the request comes from the same mac. This opens up the possibility of a fake registration happening the first time though.
If there is some way to uniquely identify each device (similar to a MAC address) then that would be the key. Keep a registry of the devices and each device would register with the server. the server would provide the device with a token and associate it (the token) with the registered device. the device uses that token to make requests. tokens can be made to expire and renewed as needed or can be black listed if needed. This seems to be similar to option 3 in the proposed options.

How to know if a message is sent from an iPhone to the server?

I have written an iPhone application communicating with a server. The app sends a message to the server and prints the result.
Now I have a question: Is there a way to know if the message sent to the server came from an iPhone?
I am asking this because I want to prevent attackers from sending messages from somewhere else and flooding the server.
If you use in-app purchases, then there is a full authentication chain that validates device X purchased the app. You're server can track this and then only give full responses to previously authenticated devices.
This approach also keeps pirated apps pretty much out of the picture.
This approach wouldn't stop a concerted DDOS attack, but your server can at least ignore non-valid clients and thus reduce its workload significantly. Since your server is ignoring invalid requests here, it also makes it less appealing to potential non-device users and the illicit user would probably only attack you if they disliked you, as opposed to them just bogging down your server for its free web services.
If you don't use in app purchases, you could set up your own authentication process and give a token to the device and have your server remember said tokens, and then later only serve valid responses for requests that had the said token (appropriately hashed and salted). This approach would not stop pirated apps from using your service, but would effectively stop non-devices from using your web service (again, except for concerted hacking efforts).
An even simpler approach is to have an obfuscated request format that would take a concerted effort to reverse engineer.
In all of these approaches, you might have to monitor your server for unusual activity and then taking appropriate steps.
I would encourage you to match your efforts to the expected risk. You can spend days, months, even years, properly securing an app, make sure the cost is worth the reward.
You could do some form of authentication, encryption or fingerprinting, eg. using SHA, MD5, etc. That way you could make it difficult (but not impossible) for an attacker to abuse your server.
You can't tell it's from an iPhone until you have received and examined the connection on the server. If you do that, you have already opened the possibility of a DOS (Denial of service) attack due to connection exhaustion.

Is there some way to determine the client to my HTTP SOAP API currently?

I know that user agent can be faked easily when connecting through HTTP. I want to ensure access to my SOAP API only from iPhone devices. We don't know how many users will be using this when it is released but it might be a lot and we can't handle traffic from outside of the devices. Any other means to prevent this?
It's not clear to me why limiting just to iPhones would be the way to go since I guess what you're really worried about is volume per user on the API (iPhone or not) and number of users. Spoofing the client is pretty easy so a better way to would be either to issue keys/ids on signup and then limit volume on each key or by IP address. Using keys also means you'll have a better ID on your users which might be useful in the long run. IP addresses could be problematic with mobile clients but at least you can do some basic load limiting.
Unless you control both sides, there's no way to determine the type of the other party reliably over HTTP.
No. (Outside of asking them if they're on an iPhone of course.)