How do you save API keys without exposing them in the first place? - flutter

If I save API keys to Flutter_secure_storage, they must be exposed in the first place. How could they be pre-encrypted or saved to secure storage without exposing them initially?
I want to add a slight layer of security where keys are stored securely, only to be exposed when making an API call. But if I have keys hardcoded then they are exposed even if only at initial app run. How do you get around this logic?

To avoid exposing API key, you should store keys in a '.env' file and use flutter_dotenv package to access it while making API calls. Although this method will not help when making API call. If you really want to secure exposing keys, you should move the API calls to the backend so those network calls cannot be seen by the client.

If this is a web project, you could use something like base64 on both ends, then debase and save like this:
SERVER ON PHP
apiKeyEncoded = base64_encode(apiKeyGenerator());
CLIENT:
apiKeyEncoded = await getApiKey();
apiKeyDecoded = base64Decode(apiKeyEncoded).toString(); //this is the usable one, save it.
Now, if the project is focused on mobile use, I don't think you actually need to implement this, tho the code would be the same.

I will add some input to this. I am using Parse Back4App which exposes app API keys in the same way that firebase does. I have discovered a few very important security designs which may help with this.
Client side
Don't worry about app API keys being abused. Firebase/Back4App both have some security features in place for this including DoS & DDoS security features.
Move ALL actual API calls to server and call from client via cloud code. If you want to go to the extreme, create a user-device hash code for custom client rate limiting.
Server side
LOCK DOWN ALL CLPs, ALL ACLs, basically lock ALL PERMISSIONS and ONLY allow cloud calls with heavy security checks authorized access to anything server side including outside API calls.
Make API calls from your server only. Better yet, move your API calls outside cloud calls & create "cloudJobs", these run on schedule with Back4App and you can periodically call whatever API from server. Example: a crypto currency app might update prices once per second, once per minute etc. server gets these updates and pushes to clients. No risk of someone getting your crypto API keys and running the limits.
Put in a custom rate-limiting design & design around this so your rate limits would never trip under normal circumstances. If they do trip in excess, ban user & drop their requests.
Also put API keys in .env file on server. Go a step further & use a key encryption hardware service.
It would be a tell-tale sign that your server is compromised if your API keys get abused with this structure.
Want further DoS & DDoS protection? Mirror your server a few times and create a structure whereby client requests can be redirected under attack times or non-DDos/DoS attacking clients receive new app API keys.
... I could go on and on about security & what I've learned but I'll leave it at that.

Related

Is it worth while to hide/obfuscate server connections in an iPhone app? If so how?

If I have an app that connects to Amazon's S3 service, is it worth my time to hide/obfuscate the connection strings and API keys? I'm guessing that most hackers won't care all that much, but it would be financially painful if someone found this information and was able to upload data to my account!
For instance, if I store a username/password (or Twitter/Facebook API key and secret), these may be easily found using "strings". A hacker could see the functionality, grab the secrets and use them for nefarious purposes. I've seen people suggest using a simple Rot13, or storing the strings backwards or something like that in the app binary. Are these useful?
Has anyone done this or have any ideas/patterns/code to share?
-dan
You can hide your secrets in a webserver you have full control over, and then having this server relay the query to Amazon. You can then use whatever encryption/validation method you like, since you are not relying on what is supported by Amazon.
Once you have validated that the request is from your own application, you then rewrite the query including your secrets and then forward this to Amazon. The result from Amazon could then be relayed directly back to the application.
In php this could for instance be done using something similar to this snippet (not showing your url rewrite):
$fp = fopen($amazon_url,'r',false);
fpassthru($fp);
fclose($fp);
You dont really need to hide them...what you should do is have an extra key such as a secret, that one IS hidden and is only present in the signature of the call (which can be an MD5 hash or sha (or whatever)) without that secret key people wont be able to just make calls since the signatures created by the server and the offender wont match since they dont know the secret key used...
I'm guessing that most hackers won't
care all that much
It just takes one who's bored enough.
Has anyone done this or have any
ideas/patterns/code to share?
This is what SSL is for. You can encrypt all your transmissions or just the login process (which would return a session id that can be used for subsequent requests during the session).

iPhone App with a Server Backend - How to ensure all access is from the iPhone app only?

I don't mind so much about pirating etcetera, but I want to ensure that the backend (Rails based) isn't open to automated services that could DOS it etc. Therefore I'd like to simply ensure that all access to the backend (which will be a few REST queries to GET and PUT data) will be via a valid iPhone application, and not some script running on a machine.
I want to avoid the use of accounts so that the user experience is seamless.
My first intention is to hash the UDID and a secret together, and provide that (and the UDID) over a HTTPS connection to the server. This will either allow an authenticated session to be created or return an error.
If eavesdropped, then an attacker could take the hash and replay it, leaving this scheme open to replay attacks. However shouldn't the HTTPS connection protect me against eavesdropping?
Thanks!
Like bpapa says, it can be spoofed, but then, like you say, you aren't worried about that so much as anybody coming along and just sending a thousand requests to your server in a row, and your server having to process each one.
Your idea of the hash is a good start. From there, you could also append the current timestamp to the pre-hashed value, and send that along as well. If the given timestamp is more than 1 day different from the server's current time, disallow access. This stops replay attacks for more than a day later anyway.
Another option would be to use a nonce. Anybody can request a nonce from your server, but then the device has to append that to the pre-hash data before sending the hash to the server. Generated nonces would have to be stored, or, could simply be the server's current timestamp. The device then has to append the server's timestamp instead of its own timestamp to the pre-hashed data, allowing for a much shorter period than a full day for a replay attack to occur.
Use SSL with client certificate. Have a private key in your client and issue a certificate for it, and your web server can require this client cert to be present in order for the sessions to proceed.
I can't give code details for Rails, but architecture-wise it's the most secure thing to do, even though might be a bit overkill. SSL with certificates is a standard industry solution and libraries exist for both the iPhone/client end and server end, so you don't have to invent anything or implement much, just get them to work nicely together.
You could also consider HMAC, like HMAC-SHA1, which is basically a standardization of the hashes stuff that other people here talk about. If you added nonces to it, you'd also be safe against replay attack. For an idea about how to implement HMAC-SHA1 with nonces, you could look at OAuth protocol (not the whole flow, but just how they tie nonce and other parameters together into an authenticated request).
There is no way to ensure it, since it can be spoofed.
If you really want to go this route (honestly, unless you're doing something really super mission critical here you are probably wasting your time), you could pass along the iPhone device token. Or maybe hash it and then pass it along. Of course, you have no way to validate it on the Server Side or anything, but if a bad guy really wants to take you down, here is roadblock #1 that he will have to deal with first.

Best practice to detect iPhone app only access for web services?

I am developing an iPhone app together with web services. The iPhone app will use GET or POST to retrieve data from the web services such as http://www.myserver.com/api/top10songs.json to get data for top ten songs for example.
There is no user account and password for the iPhone app. What is the best practice to ensure that only my iPhone app have access to the web API http://www.myserver.com/api/top10songs.json? iPhone SDK's UIDevice uniqueueIdentifier is not sufficient as anyone can fake the device id as parameter making the API call using wget, curl or web browsers.
The web services API will not be published. The data of the web services is not secret and private, I just want to prevent abuse as there are also API to write some data to the server such as usage log.
What you can do is get a secret key that only you know, Include that in an md5 hashed signature, typically you can structure signatures as a s tring of your parameters a nd values and the secret appended at the end, then take the md5 hash of that...Do this both in your client and service side and match the signature string, only if the signatures match do you get granted access...Since t he secret is only present i n the signature it w ill be hard to reverse engineer and crack..
Here's an expansion on Daniel's suggestion.
Have some shared secret that the server and client know. Say some long random string.
Then, when the client connects, have the client generate another random string, append that to the end of the shared string, then calculate the MD5 hash.
Send both the randomly generated string and the hash as parameters in the request. The server knows the secret string, so it can generate a hash of its own and make sure it matches the one it received from the client.
It's not completely secure, as someone could decompile your app to determine the secret string, but it's probably the best you'll get without a lot of extra work.
Use some form of digital signatures in your request. While it's rather hard to make this completely tamper proof (as is anything with regard to security). It's not that hard to get it 'good enough' to prevent most abuse.
Of course this highly depends on the sensitivity of the data, if your data transactions involve million dollar transactions, you'll want it a lot more secure than some simple usage statistic logging (if it's hard enough to tamper and it will gain little to no gain to the attacker except piss you of, it's safe to assume people won't bother...)
I asked an Apple security engineer about this at WWDC and he said that there is no unassailable way to accomplish this. The best you can do is to make it not worth the effort involved.
I also asked him about possibly using push notifications as a means of doing this and he thought it was a very good idea. The basic idea is that the first access would trigger a push notification in your server that would be sent to the user's iPhone. Since your application is open, it would call into the application:didReceiveRemoteNotification: method and deliver a payload of your own choosing. If you make that payload a nonce, then your application can send the nonce on the next request and you've completed the circle.
You can store the UDID after that and discard any requests bearing unverified UDIDs. As far as brute-force guessing of necessary parameters, you should be implementing a rate-limiting algorithm no matter what.
A very cheap way to do this could be getting the iPhone software to send extra data with the query, such as a long password string so that someone can't access the feed.
Someone could reverse engineer what you have done or listen to data sent over the network to discover the password and if bandwidth limitations are the reason for doing this, then a simple password should be good enough.
Of course this method has it's problems and certificate based authentication will actually be secure, although it will be harder to code.
The most secure solution is probably a digital signature on the request. You can keep a secret key inside the iPhone app, and use it to sign the requests, which you can then verify on the server side. This avoids sending the key/password to the server, which would allow someone to capture it with a network sniffer.
A simple solution might be just to use HTTPS - keeping the contents of your messages secure despite the presence of potential eavesdroppers is the whole point of HTTPS. I'm not sure if you can do self-signed certificates with the standard NSURLConnection stuff, but if you have a server-side certificate, you're at least protected from eavesdropping. And it's a lot less code for you to write (actually, none).
I suppose if you use HTTPS as your only security, then you're potentially open to someone guessing the URL. If that's a concern, adding just about any kind of parameter validation to the web service will take care of that.
The problem with most if not all solutions here is that they are rather prone to breaking once you add proxies in the mix. If a proxy connects to your webservice, is that OK? After all, it is probably doing so on behalf of an iPhone somewhere - perhaps in China? And if it's OK for a proxy to impersonate an iPhone, then how do you determine which impersonations are OK?
Have some kind of key that changes every 5 minutes based on an algorithm which uses the current time (GMT). Always allow the last two keys in. This isn't perfect, of course, but it keeps the target moving, and you can combine it with other strategies and tactics.
I assume you just want to dissuade use of your service. Obviously you haven't set up your app to be secure.

How to ensure access to my web service from my code only?

I am writing a very simple web service for my iPhone app. Let's say this is a http page that returns a random number at http://mysite/getRand. How do I ensure that this page can only be accessed from my iPhone app and not from other clients? I've thought of doing some simple password mechanism but that can easily be sniffed by capturing what my app sends out.
The reason for this is to lower the load of my server by only allowing legitimate requests.
You can't really do this. Your application can be disassembled and whatever secret is in the binary can be replicated in a malicious application.
Another attack you should be aware of is people settings the hosts file to a location they control and then installing a root certificate that allows them to provide a signature for that domain. Your application would do the post with the secret, and they'd just be able to read out the secret. They could extract the password from any complicated encryption system within the binary in this way.
Most of the ideas in this thread are vulnerable to this attack.
That said, the likelihood of somebody caring enough to disassemble your application is probably fairly remote.
I'd just keep it simple. Have a password that's hardcoded in to your application. To prevent someone just looking at the resources and trying every string, make it the XOR of two strings or the result of an AES decrypt of a particular fixed string.
Obviously, you should do the request over SSL otherwise an attacker can just sniff the traffic.
Yes, a determined attacker will circumvent the scheme but like any DRM scheme, that's always been the case. The trick is to make it too much effort to be worth it.
To follow up on Simon's idea, you could very easily have a key string in your application, then send the device ID, and then the DeviceID XOR'ed (or some other simple algorithm for string encryption) with your key string.
Since you know the key value to use, it's trivial for you to "decrypt" this string on the sever side and verify that the values match.
This way, the password is different for each user's device, and the "key" string is never sent over the wires of the great unwashed internets. :-)
Yes, this would by no means be impossible to figure out, but like others have said, the idea is not to make it impossible. The idea is to make it more trouble than it is worth.
I would use the https protocol with client-side keys too. You can use one client key for everyone or you can even generate a different key for each client and "register" them at your server.
I suppose that it's a lot of work for small project, but it sounds like the appropriate thing to do if you need authentication.
You should check that keys aren't seen easily by mobile phone owner. And remember that somebody will be able to hack it in any case.
Here's one thought - send up the device ID along with requests from your app.
Monitor the device ID's used - if you see a ton of requests from different IP's near or at the same time, that device is probably being used as a fixed key in the requests sent to you - block it.
For those that actually send the real device ID from other apps (not yours), you can monitor usage trends to see if the calls match the pattern of how your app performs - like one call being used by a device before some initialization call you would normally expect, and so on - block those too.
Basically by being able to shift rules around patterns of use, you can better adjust to someone trying to use your service by making sure it's not a fixed target like some random use key would be.
You may also want to use a simple use key as well as a first line of defense, and then layer on the traffic analysis approach. Also custom http header values you look for are another simple way to trip up a naive attacker.
I am assuming you don't want to use SSL? If you do then you can open HTTPS session and then pass some secret key in the request.
If you don't want SSL your options are limited: to have pseudo security I suggest both authentication and authorization methods and a third to reduce overall traffic:
Authentication: Generator in client application that creates secret keys by combining with a key file. The keyfile can be updated every so often for greater security: lets say you update the key file once a week. To re-cap: Generator combines in app secret with out of app key file to generate a 3rd key for transmission used in authentication. The server would then be able to authenticate.
Authorization: Of course you also want to lock out rogue applications. Here it would be best to have authorization mechanism with the site. Don't replace keyfiles for unless the client logs in. Track key files to users. etc.
Traffic reduction:
If you are receiving obscene amount of traffic or if you suspect someone trying to DOS your server, you can also have both the server and clients sync to request/response on a procedurally generated URL that can change often. It is wasteful to open/close so many HTTPS sessions if someone is just flooding you with requests.
I'm not sure what web technology you are using, but if you are using Ruby on Rails, it uses a secret authentication token in all of its controllers to make sure malicious code isn't accessing destructive methods (via PUSH, POST, or DELETE). You would need to send that authentication token to the server in your request body to allow it to execute. That should achieve what I think you are looking for.
If you're not using Ruby on Rails, that method of code authentication might be a good one to research and implement yourself in whatever technology you are using.
Take a look at the Rails Security Guide, specifically section 3.1 (CSRF Countermeasures).
You could do something like encrypting the current time and IP address from the iPhone, and then decrypt it on the server. The downside is that you need the iPhone app to know the "secret" key so that only it can generate valid access tokens... and once the key is in the wild, it will only be a matter of time before it's hacked if your app is really worth the effort.
You could encrypt the response using some random portion of the application which is meant to be using it, specifying the location of the binary in an unencrypted bit of the response. Then at least only clients with access to your binary would be able to decrypt it... but again, that's hardly 100% secure.
Ultimately you need to ask yourself how much effort you want to put into securing the service vs how much effort you think hackers will put into abusing it.
I'm not an Cocoa Touch developer, but I think HTTP Authentication over SSL would be easy to implement and it's probably exactly what you're looking for.
All you need to do is setup HTTP Authentication on the server side (you haven't mentioned what you're using on the server side) and create a self-signed SSL cert on your webserver. Done. :)
Tell us more about your setup and we will be able to help you further.
As some of the answers have stated, closing your web service off to everyone else will be a major hassle. The best you can hope for is to make it easier for the hackers to use another web service, than to use yours...
Another suggestion to do this, is to generate random numbers from a random seed on both the server and the client. The server would need to track where in the sequence of random numbers all of the clients are, and match that number to the one sent by the client.
The client would also have to register to be given access to the server. This would also serve as a authentication mechanism.
So:
//Client code:
$sequence = file_get_contents('sequence.txt');
$seed = file_get_contents('seed.txt');
$sequence++;
//Generate the $sequence-th random number
srand($seed);
for ($i = 0; $i <= $sequence; $i++) {
$num = rand();
}
//custom fetch function
get_info($main_url . '?num=' . $num . '&id' = $my_id);
This will generate a request similiar to this:
http://webservice.com/get_info.php?num=3489347&id=3
//Server Code: (I'm used to PHP)
//Get the ID and the random number
$id = (int)$_REQUEST['id'];
$rand = (int)$_REQUEST['num'];
$stmt = $db->prepare('SELECT `sequence`, `seed` FROM `client_list` WHERE `id` = :id');
if ($stmt->execute(array(':id' => $id)) {
list($sequence, $seed) = $stmt->fetch(PDO::FETCH_ASSOC);
}
$sequence++;
//Generate the $sequence-th random number
srand($seed);
for ($i = 0; $i <= $sequence; $i++) {
$num = rand();
}
if ($num == $rand) {
//Allow Access
} else {
//Deny Access
}
By using a a different seed for each client, you ensure that hackers can't predict a random number by tracking previous numbers used.

C# ASMX webservice semi -permanant storage requirement

I'm writing a mock of a third-party web service to allow us to develop and test our application.
I have a requirement to emulate functionality that allows the user to submit data, and then at some point in the future retrieve the results of processing on the service. What I need to do is persist the submitted data somewhere, and retrieve it later (not in the same session). What I'd like to do is persist the data to a database (simplest solution), but the environment that will host the mock service doesn't allow for that.
I tried using IsolatedStorage (application-scoped), but this doesn't seem to work in my instance. (I'm using the following to get the store...
IsolatedStorageFile.GetStore(IsolatedStorageScope.Application |
IsolatedStorageScope.Assembly, null, null);
I guess my question is (bearing in mind the fact that I understand the limitations of IsolatedStorage) how would I go about getting this to work? If there is no consistent way to do it, I guess I'll have to fall back to persisting to a specific file location on the filesystem, and all the pain of permission setting that entails in our environment.
Self-answer.
For the pruposes of dev and test, I realised it would be easiest to limit the lifetime of the persisted objects, and use
HttpRuntime.Cache
to store the objects. This has just enough flexibility to cope with my situation.