I have a mobile app (currently IOS and soon Android) which talks to a web service. There is no login and the data is not private. Basically, the app POSTs a marker (lon, lat) and GETs the nearest 25 markers to display on a map.
It's a very trivial app and I cannot imagine anyone putting great effort into abusing the web service. However, I can see there is fun for someone in POSTing many markers. What most concerns me is someone running a script that pushes many requests (using expensive bandwidth and making nonsense of my app data).
I am slowly reaching the conclusion this cannot be secure. The best answer is "do not do this". Do not provide a web service without authentication. Not many services are so open. Google's You Tube API is open but most are not. Unfortunately, I have no choice. So after days of looking at this here's my thinking. Be aware I am very far from a security expert and I am confident my approach could be improved upon. But it might point you in the right direction. Hopefully, someone more experienced might chime in and correct/improve upon this. I found this article and comments particularly helpful.
Message Level Security
I will secure the msgs with a hash encryption. The clients and web service all retain a copy of a shared secret which is used as a salt to create a hash from the URL and all the POST arguments. The hash is passed as an additional argument and the hash is rebuilt and compared at the other end (using the shared key as a salt). This is pretty good until you understand that any mobile client code can be reverse engineered in minutes. At which point this line of defense is utterly useless.
Client Measures
The client includes rate limiting of messages as a measure to restrict the number of messages sent by honest users. Yet again this is useless against an attacker who jailbreaks the mobile device.
Server Side Security
So the server side must have as much additional security measures as possible, to stand alone on the assumption that your client (and shared secret) is compromised. Here is what I have:
One msg arg is a UTC time which is used to limit replay attacks. This should prevent an attacker from firing the same msg at the server repeatedly.
The server performs rate limiting by IP. Yes, IPs are easily spoofed and proxy switching is childs play but everything helps when you have so little.
Of course, the server strictly validates all arguments, uses parametised queries and doesn't return exceptions.
Transport Level Security
Unfortunately, I am fairly confident that issuing individual client SSL certs is not possible without a registration process. And because I am using the msg hash check (and my data is not private) I am not entirely sure what SSL brings to the table. However, I will probably use SSL (with one app wide cert) because it adds another level of security that is easily and cheaply deployed (albeit at a cost of additional connection time for every msg).
The Gaping Great Big Hole In My Approach
I am warned that should the app become popular that someone will compromise the shared secret on the client. Just because they can and they will probably post it on the internet. So really it all comes down to the server side. Unfortunately, I have no way to identify and block an attacker. This I would dearly love.
A Final Plea
After days of research this is all I have. But I want more. I would particularly appreciate any ideas to beef up the server side. So, I have put all my SO points up as a bounty. Yes sir, all 97 points!
Security is critical to web services. However, neither XML-RPC nor SOAP specifications make any explicit security or authentication requirements.
The key Web services security requirements are authentication, authorization, data protection, and nonrepudiation.
Authorization (also known as access control) is granting access to specific resources based on an authenticated user's entitlements. Entitlements are defined by one or several attributes.
Actually in your particular case, since it is currently an iOS only app, there is a solution.
After the user downloads and runs the app for the first time, the app hits a /access_token/create
API that comes up with a GUID and relays it back to the Application via Apple's Push Notifications.
App stores this access_token, and uses it on all subsequent requests. Your actual API's can rate limit on the basis of the access_token.
Basically, you let Apple do all the hard work of ensuring that the initial request came from an actual iOS device.
Extending this to Desktop clients is possible, but somewhat ruins the UX. Just change step 1 to allow /access_token/create
to accept arbitrary requests, and if the request is not from a iOS device, then force the user to verify their email address/solve a captcha etc before issuing them an access_token.
Android devices (not really familiar with them) may have a similar Push Notification mechanism, in which case you can use that, or may not have a Push Notification mechanism, in which case you can subject your Android users to the inconvenience listed above.
I've heard about this idea once, when talking about finding a global solution to SPAM problem: force your client to perform some time-taking computation.
To be precise: find some computational algorithm, that can compute some z
for a pair of x
and y
in a blink of an eye, but it takes some considerable amount of time to compute z
being given only x
. I can not provide actual algorithm but I am sure that there are plenty of them that would much this criteria.
Now the whole procedure should look as follows:
session_id
and for this session_id
a pair of x
and y
.session_id
and x
.session_id
and calculated z
.z
is all right, for you already have x
and y
that let you easily do it.session_id
store how much/often it is being requested. The moment you suspect it is being abused - force regenerating x
and y
.x
and y
upon each consecutive request for a session_id
.Choosing between 6 and 7 is actually tweaking that depends on the complexity of algorithm vs. expected 'fair' use of marker database. If your estimates are good - the evil client should never obtain too much data or overload your server.
Hope it helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With