github-like authentication for api in rails - ruby-on-rails

I am creating an API that will only be used by specific devices. I'd like to authenticate using a public and private key pair, similarly to the way that github authenticates using SSH.
The scheme I think would work is as follows:
The device will request authorization with it's ID.
The server finds the public key of the device by the provided ID and encrypts a random string. The string is sent to the device.
The device receives the encrypted string and decrypts it with its private key, sending the result back to the server.
The server checks the string to make sure it matches and sets the correct session variables for the device if the check was correct.
All of this is over an SSL connection, so step 3 can't be snooped and used to authenticate again. Some devices will not need this type of authorization, so the SSL connection can't just verify that the public key of the device was generated by the server's certificate authority and close the connection if it was not.
First of all, does this make sense, or is there a better way? And second - is there some gem that already does this in rails? It seems like this would be a somewhat common method of doing things.

Related

Sending Apple device token to server and avoid spoofing

I'm not sure if I'm being over cautions; I'm implementing the ios push notifications and there's is a part where I need to send the device token to the server, so that's clear, all I had to do is send a request like this:
www.mysite.com?registerIosToken=asdfgadsfhgakjhsf
So my server can register the token in the db.
But what if someone sends multiple random requests to this url?, how can I detect ignore fake requests?,
I was thinking using the app public certificate, and I can decrypt it in the server with my private key, but if the key is public, everyone can encrypt it...

Validating requests in /server url

In iOS MDM /server url will be called for each operation by the device when it is woken by APNS. I have securely encrypted and signed other profiles at the time of enrollment and successfully passed the server url to device. Its working fine but I have few concerns over this server endpoint as follows.
1) Any client or entity who could send similar plist payload can invoke this service. If a 3rd party has access to a device UDID they can compose this xml payload and invoke this service. From the server point of view it will be hard to track this behavior and identify real devices. To identify that in the real scenario will it send and CMS data or related to validate this scenario?
2) Once the device hit this endpoint from server we can generate operation profiles and send back to devices. For the profiles at the enrollment time we could extract the public certificate from CMS data and encrypt from that. But for this server url how do I achieve that? Seems its not getting any cert like that from device side. Just wondering whether to save the public keys we got in earlier stages but since at the enrollment it goes through 2 SCEP calls not sure what to use it. Will those subsequent profiles payload can be encrypted using previous public cert? Right now I do the signing anyway which works fine.
1.) Any client or entity who could send similar plist payload can invoke this service. If a 3rd party has access to a device UDID they can compose this xml payload and invoke this service. From the server point of view it will be hard to track this behavior and identify real devices. To identify that in the real scenario will it send and CMS data or related to validate this scenario?
Yes, Any client who could possess the UDID and Server URl can send a valid Plist to your server acting like the device.
But they cannot sign the plist with the private key in the device(Which is generated during SCEP enrolment). You would be having corresponding Public key for it to validate the signature.
To force the device to send the signature along each request to Server URL, you have to include SignMessage tag in your MDM payload and set it as true. Like this
<key>SignMessage</key>
<true/>
So when you include this tag along with your MDM payload, you would be get the signature of Identity Private key in the Header HTTP_MDM_SIGNATURE.
Then you can validate the signature using your public key.
2.) Just wondering whether to save the public keys we got in earlier stages but since at the enrollment it goes through 2 SCEP calls not sure what to use it.
Yes I mentioned in the previous answer you should save the public certificate which is issued during SCEP phase. Later you will use that public certificate to Validate the signature from Device and Encrypt the profile you are sending.
Regarding 2 SCEP calls, First SCEP call is to generate the certificate and securely transfer the MDM Payload and actual SCEP payload which will be used as Idenitity certificate for MDM.
So you should use the second one for validating the signature and encryption.
One more hint is, you would have mentioned IdentityCertificateUUID in your MDM payload. The Identity Certificate SCEP payload should have same UUID as its PayloadUUID . That SCEP payload's certificate will be used as the identity certificate for MDM.
Ok. The bottom line that you want to authenticate device.
Each device has an identity cert (a cert distributed in PKCS12 or through SCEP).
Each time when a device communicate to the server it does authentication using SSL client certs.
Most of the time there is a reverse proxy sitting upfront of your web server. It could be Apache or Nginx or anything else. This reverse proxy terminates SSL connection and checks client certificate. Usually, they are configured to pass this client certificate as a header to your web application.
This way your web app can get this header, get a certificate out of it and check against your DB whether a device with specific udid (passed to your endpoint) have a certificate (passed to your webapp in the header).
I am not sure which reverse do you use and whether it's configured properly to pass the certificate.

iOS: Where shall I keep RSA public key in my application?

What I am doing?
- I am building an application where users signIn with Google in order to use my App.
- Since Server has no idea is request is coming from a device, a trust mechanism is needed in order to handshake.
- I created pair (private key, public key) using RSA algorithm. The intent is that public key will be staying on device(with application).
- Once user signs in, application encrypts user information with public key and sends to server using REST API. The server validates and inturn returns a token, that client(iPhone app) can reuse to communicate further with server.
Question
- Since I am new to developing iOS(or any mobile) application, I wanted to know where this public key will be stored in my iOS application

Sending Device Token Safely for APNs

For iOS applications that require push notifications, it must first request the user for permission to do so. After that, a device token is generated and with this, the remote server may communicate to the user through this token.
I have read a similar question here and I do not feel it is enough. The picture below is a trusted certificate, it allows me to view all traffic that happens on this device.
With Fiddler2 as well as CertMaker, I can sniff HTTPS traffic, which means the client can probably know what data they are sending, and to where.
My question is, knowing that SSL is not secure from protecting my clients from seeing what I send to the remote server, should I simply encypt with a secret key found within my application?
Such as encrypt("device_token","secretkey_a0a0a0a") (pretend this is Objective-C)?
Couldn't someone just find that key within my application? I also read this question, and it seems that it would be possible to get back the secret key.
My plan for this goes like this:
Within the iOS application, Generate a random string named activate.
Encrypt (not hash), the token by the random string and a secret key that I only know. (secretkey_a0a0a0)
Send the encrypted string along with the generated randomly generated string (active).
Within serverside, I check if I can decrypt a valid token from using the active and my secret key.
I save the token in my database if it is valid.
This prevents people from random entering tokens yes, however, secretkey_a0a0a0 is a string literal. It's very possible to get this within the application binary itself.
My question is, how do I protect this secret key? The answer can also be, how can I prevent people from sending invalid tokens to my server as well.
I have heard of encryption, but doesn't that only apply to resource files?
How should I approach this?
If you do SSL-Pinning ( AFNetworking has this implemented ) you won't be able to (in a reasonable timeframe) sniff the https traffic between the client and server if you don't have the servers private key.
If your fear is that man in the middle can steal your token and send fake push notifications to users of your application, be sure that this cant happend. Since requests to apple apn servers must be signed with pem file, the main concern should be how to keep certificate file secured, and not apn token. If you want to prevent writing invalid tokens in your database then you should implement some CRC or odd/even bit mechanism.
You might want to check the security section in the Push Notifications Guide, in particular the section titled "Token Generation and Dispersal".
The device token is generated by the device connecting through the Apple's APNS. My guess (they don't say in the docs) is that it's unique for a given app identifier.
The APNS then will probably match those identifiers with the pem certificate you use to communicate with it thus validating that the push notifications are actually originating from your app.
Encrypting the device token seems overkill in this scenario.
To prevent someone maliciously spamming your server with tokens, I would hash the token when a secret key and send both the token and the hash to the server. You can then hash the token again on the server, with your secret key, and check that the request is valid.

Authenticating against a REST API with iOS client using Facebook SSO as the only login mechanism

I'm planning to use Facebook as the only sign-on mechanism for an application that I'm building and need some feedback on the design. Here it goes -
User opens the app and is presented with a register screen. The facebook authorization flow starts and let's assume it succeeded and the user has successfully registered himself. Upon success, the app calls the Facebook graph API and gets the user's firstname, lastname, email, date of birth etc. With this data, the app then calls a web service method called RegisterUser(string Fullname, string FirstName, string LastName ...) which creates the user record in the database.
Now for subsequent calls to the API, I need to authenticate that the request is really coming in from my application (not necessarily a particular user). I've looked up the S3 REST API and it seems that with every request there's a HTTP header called Authorization that the client creates by appending a bunch of other HTTP Headers like Date, Method, Request data, signing it with the client's private key and computing its base64 encoded value. This is verified on the server side to authenticate the client.
Now, I'm comfortable implementing all this, but a few questions:
If I have a private key, is it safe to include it as a part of the iOS application itself? Can someone extract the key from the iOS application binary? If so, how do I deal with this?
Are there any other changes you'd make to this design ?
Thanks,
Teja.
Make sure you apply a one-way hashing algorithm to the value to base64 encode - base64 is a two-way encoding, so you don't want eavesdroppers reverse engineering your private key from that. Amazon S3 does this with performing a SHA-1 before doing the base64.
As with all (AFAIK?) compiled binaries, your app shouldn't be able to be decompiled.

Resources