Protect server URL in mobile app - url

I know this can sound absolutely stupid, but I could not find any way to solve this problem.
Say I've a mobile app: from this app, after purchasing an item, since the item is downloadable from a server, I make the user download a file to his device. Problem is it looks like it is very easy even for not so smart people, to get the URL of the file, so, without purchasing anything, the not-so-smart-guy can eventually download the same file for free (using a common browser).
Apart from the language I use (it is not important here, it can be JavaScript, Java, Objective-C, whatever), how can I prevent this issue WITHOUT developing an authentication system?

Generate a token for successful purchase, store it in the server side session or database. Add the token as a query string parameter for the file download request. Implement an filter for the file download request to validate the token.
To make sure that the URL is not share able - find some unique attribute of the device that can't be spoofed easily, hash(url,token,unique property) and add it to the url.

Related

Securing login credentials in an iOS app bundle

I am writing an iOS app and have a dilemma. The app will be used to test the BLE protocol of devices coming off our production line. It needs to be very simple, It is a one button app that automatically connects to devices and tests commands in our protocol and gives a pass or fail result. If it passes the device id is sent to our API to be entered in our database.
My problem is I don't want the user to have to login, but I need to send a username and password to the API to log in. This means the username and password has to be included in the app. I am trying to find out the most secure way to do this. I initially thought I would include a plist in the app with the credentials, enter them in keychain, then delete the plist. However I don't believe you can delete a file included in the app bundle (I get a 513 permission error).
I have 2 questions. Is it secure to include credentials in code? Is there a better way to do this?
Thanks!
No.
Use API to retrieve credentials and store to keychain. Simple call to firebase could solve this. Or use your own backend with your custom “security”.
But even obtaining via API don’t give you 100% security. Everything depends. API solution gives you flexibility and ability to support different versions with different credentials.

From an app, POST data to the default iOS browser

I have an iOS app, with a long list of items to be POSTed to a remote web server. The list can be long enough to exceed recommended lengths for a GET request. After the list is posted, the user can log into their account and manipulate the list.
Ideally, I'd like to POST the list to Safari (or another default browser) so that if the user already has logged in, they don't need to do so again and they have access to all the normal web browser functionality.
It seems to work with a UIWebView, but isn't the best interface.
This can be done on Android or the UIWebView using this: https://stackoverflow.com/a/9909613
Do it in two steps:
POST the data to the server "anonymously". The server would assign some kind of unique id, and store the received data somewhere (database, temp file...), associated with the ID. Send back the ID to the client.
Alternatively, the ID might be provided by the client directly. For that, make sure it's some kind of UUID/GUID so you don't have conflicts.
Open a second URL (either in Safari or, probably better, in an SFSafariViewController) pointing to the login process along with the ID from step 1.
The server can then use the ID to locate the data posted during the first step.

iOS safely pass content between apps

I'm curious if there is a way to safely pass content between apps on iOS. The ultimate goal is to implement oauth between two ios apps.
Since apps are not guaranteed to have unique url schemes, this option is out.
I have considered using keychain groups, but do not have experience with this. It looks like an app needs to specify exactly which apps can access the keychain items.
Are there any other options? Is there some sort of identifier (such as android bundle ID) that can be used to verify the apps during a request?
You can use URL schemes for this.
The basic process
You'll have a ServerApp and many ClientApps. The ServerApp listens to an URL-scheme like serverapp://. The client then can make a call to the server to ask it for authentication. The client has to implement an URL-scheme too. E.g. ClientAppOne implements the URL scheme clientapp1://. The server takes as parameter a backlink to the client app. E.g. the client calls the URL serverapp://auth?back=clientapp1%3A%2F%2Fserverapp-auth (here the backlink is clientapp1://serverapp-auth and has been urlencoded).
The server then checks the users identity, asks him for permission, password, etc. and then uses the backlink to provide the data. How the backlink works exactly is application specific, but you usually need at least 2 parts: an access token and a username. E.g. a backlink will then be clientapp1://serverapp-auth?success=1&token=fi83ia8wfzi3s8fi8s3f8si8sf&user=robert or maybe in case of error clientapp1://serverapp-auth?success=0&errno=421. The client then needs to verify the accesstoken through some public (or private) API, e.g. https://serverapp.example.com/userdetails?apikey=fai83jw93fj93389j&token=fi83ia8wfzi3s8fi8s3f8si8sf. The server will return some structured response.
Necessary components
an URL scheme on the server App
an URL scheme on each client App
an SDK that is to be included into each client app and that handels the details of authentication, and a standard UI component (e.g. facebook has a standard button that says "login with facebook", so the ServerApp needs some re-recognizable button that says something like "login with ServerApp")
a server that provides services that can be accessed through the access token.
a defined API that explains how the client has to communicate with the server
an SDK to be included into the client that handels such client-server-communication (should be part of the SDK mentioned in component 3.)
maybe a wiki that documents all of the steps above, so that you and other developers dont lose track
a way to invalidate access tokens, and a way for the client to detect if an access token has been invalidated. furthermore, if the user changes his password, all access tokens should be invalidated.
Random notes
in your client app you can check if the serverapp is installed by calling [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:#"serverapp://auth"]].
the URL schemes should be sufficently collission-free. These URLs are never seen by users, only by developers, so they don't have to be beautiful. You can e.g. append the iTunes-Connect-App-ID to your URL-scheme, like serverapp1234567://. This will greatly reduce the possibility that someday some other app will use the same URL scheme.

"Remember this approval" when using dotNetOpenAuth and Google Apps doesn't work as expected

I'm using dotNetOpenAuth to provide SSO to my app via a user's Google Apps account. Besides just simple authentication I also ask Google to return the user's email, first name and last name. When a user first goes in they get redirected to the typical Google Accounts page telling them that the app is asking for this info and do they want to allow it. There is the checkbox there to Remember This Approval. The problem is, the approval isn't being remembered. It does remember them if they go back to the site without closing their browser. But if they close their browser and then open it later and go back in, they are again prompted to allow it.
If I look through my Google account page that shows me connected sites, apps, and services, I see my app listed multiple times. It's like it doesn't recognize that it's the same app and keeps adding it.
I know I must be missing something obvious, but I'm not sure what it is. Any ideas?
Thanks!
You can find my code here
I see several problems in your code. To first answer your direct question, the reason Google doesn't remember you on return visits is because you are passing a random GUID in as part of your Realm each time you log in. The symptom is actually much worse than you realize. It's not just that Google prompts the user on return visits, your site won't recognize the user at all on return visits because Google will give them a new claimed identifier on each visit.
The fix is that you should use the exact same Realm for every login request:
Realm realm = "http://www.yoursite.com/";
var req = openid.CreateRequest(discoveryUri, realm, URIbuilder.Uri );
Or my personal favorite:
var req = openid.CreateRequest(discoveryUri, Realm.AutoDetect, URIbuilder.Uri );
Realm.AutoDetect will work for you unless your site is available both via HTTP and HTTPS, in which case you need to lock it down to just one or the other of these so that Google recognizes your site as always the same.
You must also remember that the returnTo URL that you pass in as the 3rd parameter to CreateRequest must always be based on the realm. So if your realm is HTTPS, so must your returnTo parameter be.
I also want to call out that you seem to have some GUID code and complex URL manipulation around trying to ensure that every OpenID response you accept comes from a request you sent out. I'm not sure why you're trying to do this in the first place, although there certainly can be legitimate reasons. The way you did it is insecure and can be circumvented. I suggest you delete all this code, in favor of adding this to your web.config file:
<dotNetOpenAuth>
<openid>
<relyingParty>
<security rejectUnsolicitedAssertions="true" />
</relyingParty>
</openid>
</dotNetOpenAuth>
The library has support for requiring all responses to come from your requests built in, and it does so securely so that the security exploit I alluded to earlier isn't possible.
But if you're only trying to apply this restriction so that you know it's coming from Google, may I recommend that instead of rejecting unsolicited assertions, you instead check the IAuthenticationResponse.Provider.Uri property when you receive responses and verify that it is coming from the Google OP Endpoint? Then, if Google ever supported sending unsolicited assertions it would work on your site, and ultimately your security gate is exactly where you intended it to be anyway.

How to store a secret API key in an application's binary?

I am creating a Twitter client for Mac OS X and I have a Consumer secret. It's to my understanding I should not share this secret key. The problem is that when I put it as a string literal into my application and use it, like this:
#define QQTwitterConsumerSecret #"MYSECRETYOUMAYNOTKNOW"
[[QQTwitterEngine alloc] initWithConsumerKey:QQTwitterConsumerKey consumerSecret:QQTwitterConsumerSecret];
It is in the data section of my application's binary. Hackers can read this, disassemble the application, etcetera.
Is there any safe way of storing the Consumer secret? Should I encrypt it?
There is no real perfect solution. No matter what you do, someone dedicated to it will be able to steal it.
Even Twitter for iPhone/iPad/Android/mac/etc. has a secret key in there, they've likely just obscured it somehow.
For example, you could break it up into different files or strings, etc.
Note: Using a hex editor you can read ascii strings in a binary, which is the easiest way. By breaking it up into different pieces or using function calls to create the secret key usually works to make that process more difficult.
You could just base64-encode it to obfuscate it. Or, better idea, generate the key instead of just storing it - write something like this:
char key[100];
++key[0]; ... ; ++key[0]; // increment as many times as necessary to get the ascii code of the first character
// ... and so on, you get the idea.
However, a really good hacker will find it no matter what; the only way to really protect it from others' eyes is using a secure hash function, but then you won't be able to retrieve it, too :)
You should not use a secret api key in an application that does not run solely on your server.
Even if it's perfectly hidden.. you can always snoop on the data going through the wire. And since it's your device you could even tamper with SSL (man in the middle with a certificate created by a custom CA which was added to the device's trusted CA list). Or you could hook into the SSL library to intercept the data before actually being encrypted.
A really late answer...
If you setup your own server, you can use it for helping you desktop app getting authorized by users on twitter without sharing (i.e.: embedding) your secret key.
You can use this approach:
When a user installs you desktop app she must register it with twitter and with your server
*)
*) The app asks the server to generate the token request URL
*) The server sends the generated URL to the app
*) The app directs the user to the authorize URL
*) The user authorizes your app on twitter and pastes the generated PIN into it
*) Using the PIN you app grabs the token
*) All further communication uses the token and does not involve your server
Note: the app logs to your server using the user credentials (e.g.: id and password) for your server.

Resources