89

In detail here's the problem:

I'm building an Android app, which consumes my REST API on the back-end. I need to build a Registration and Login API to begin with. After searching with Google for a while, I feel like there are only two approaches that I can take.

  • During Registration, I use https and get the user's credentials; save it in my DB against the username(server side). During Login, again I use https, and ask the user's credentials; verify the hashed password on the DB and return him a session ID, which I'm planning to never expire unless he Logs Out. Further any other API calls (GET/POST) that the user makes, will be accompanied with this session ID so that I can verify the user.

But in the above approach I'm forced to use https for any API call, else I'm vulnerable to Man in The Middle Attack, i.e. if anyone sniffs over my session ID, he can reconstruct similar GET/POST requests which I wouldn't want. Am I right with the above assumption?

  • The second option is to follow the path of Amazon Web Services, where I use public/private key authentication. When a user registers I use a https API to save his/her credentials in the DB. From then on I use the user's hashed password as the private key. Any further API calls that the user makes will be having a hashed blob of the request URL using the user's private key. On the server side I reconstruct the hash using the saved private key. If the hash is a match I let the user do his task, else reject. In this option I need to use https only for the registration API. The REST can go on on http.

But here the disadvantage is, that I'm forced to host my Registration API in a separate Virtual Directory (I'm using IIS and I'm not sure if I can host both http and https APIs in the same Virtual Directory). Hence I'm forced to develop the Registration API in a separate project file. Again Am I right with the above assumption?

Edit: I'm using ASP.NET MVC4 to build the web API.

The reason I'm reluctant to use https for all of my REST API calls is that I feel it's not lightweight and creates more network payload, which may not be best suited for a mobile app. Further encryption/decryption and extra handshake required may further affect a mobile's battery Life? Or is it not significant?

Which of the above two approaches would you suggest?

PS: We went with Https everywhere, and it was the best decision. More of that on my blog.

noob Mama
  • 993
  • 1
  • 7
  • 7
  • I've been through it before and it has a lot of interesting links, but none of it quite answers all of my above doubts ! –  Sep 09 '12 at 08:41
  • 7
    Have you benchmarked SSL? The most expensive part about SSL is the handshake, and you need that one already for login. The handshake can often be re-used for later connections (session resumption). – CodesInChaos Sep 09 '12 at 10:22
  • When considering HTTPS developers are usually more concerned about server performance. As for the client devices, how many requests do you send per minute? I wouldn't think that a few requests per minute would make a difference. – Ivan Sep 09 '12 at 08:18
  • You can generate a secure token on login time and you will send it in request. I got detail from here http://skillrow.com/basic-security-in-rest-api/ –  Mar 18 '14 at 16:47
  • Your second approach is not secure, it does nothing to prevent replay attacks. You are going to have a hard time ensuring security without HTTPS on everything. Also your reasons for avoiding HTTPS do not make sense, the extra overhead these days is not significant enough to worry about, certainly when compared to the security implications of *not* using it. – Sean Burton Oct 16 '17 at 17:39

7 Answers7

55

I'd go with SSL/TLS everywhere (since you control both sides, forcing TLS 1.2 should be feasible). It's relatively simple to use, and you get a lot of security features for free. For example if you don't use SSL, you'll need to worry about replay attacks.

If you're worried about performance, make sure session resumption is supported by both the server and the client. This makes later handshakes much cheaper. Since the handshake is quite expensive in SSL compared to the encryption of the actual data, this reduces overall load considerably.

If you use HTTP 2, you can even send multiple requests over a single connection, that way you avoid the complete TCP and SSL handshake overhead on later requests.

CodesInChaos
  • 11,854
  • 2
  • 40
  • 50
  • 1
    but what about the network payload ? wouldn't i be transferring more data on the wire if i used it for all actions? considering the limited bandwidth of cellphones is it still a good idea for an interactive app ? –  Sep 09 '12 at 10:31
  • 12
    It seems unlikely that SSL network overhead is relevant. But if you doubt it, *measure*. The handshake costs a few kB, the per packet overhead a few dozen bytes. – CodesInChaos Sep 09 '12 at 11:24
  • 1
    HTTP/1.1 can do a series of requests over one connection, although many servers (and proxies etc) and some clients won't keep it open if idle for 'too long' which can be anywhere from some seconds to many hours; what HTTP/2 adds is multiple *concurrent*/overlapping requests. – dave_thompson_085 Nov 10 '15 at 16:50
24

I recommend using OAuth. You should definitely read up on it if you're not familiar with it. As a plus, you get to use 3rd party identity providers, so your users can use their Google / Windows Live / etc. accounts for your application, sparing the registration.

Even if you want to roll your own authentication framework, I don't recommend using non-expiring sessions. The session should expire after enough idle-time, else this gives more room to exploitation (session-hijacking e.g.).

  • I've looked into OAuth, I see that it's useful when i want to let users login to my App, with Google/Windows/etc. credentials. But shouldn't I also give them the choice of registering solely for my app alone ? Further i see your point on session hijacking, Interesting,.. i never thought of it ! –  Sep 09 '12 at 08:57
  • 1
    You can also integrate OAuth on your server side, so your users can register an account solely for your application. It's not only useful because you can use 3rd party identity providers, it's useful because it's a pretty good and tought-out authentication framework that you can rely on. On the other side, it _may_ be too complex for a simple application, but that's for you to decide. –  Sep 09 '12 at 09:08
  • Hmm.. btw, the reason i thought of not expiring the session is because most apps like twitter and Pinterest don't have a log-out option. I assumed the never expire the session either. –  Sep 09 '12 at 09:20
  • 6
    +1 for the OAuth recommendation. However, I strongly disagree with the comment about non-expiring sessions. On mobile platforms, non-expiring sessions are great for most purposes. Don't force the user to type in a password repeatedly on a mobile keyboard (yuck! not only is it inconvenient, it may cause users to choose weaker passwords, which harms security overall). Personally, I'd recommend using a non-expiring session as a great way to get both security and convenience. – D.W. Sep 10 '12 at 00:53
  • 1
    It's worth mentioning that OAuth *must* be done over a secure channel, such as HTTPS. If you do OAuth without HTTPS or some other secure channel then the entire security is compromised... – Sean Burton Oct 16 '17 at 17:42
4

Depends on just how secure it needs to be. Every time you make the solution more complex, you are also likely to leave a gaping hole. It's better to use some kind of industry standard authorisation and authentication module.

You will probably be fine, as long as you are:

  • encrypting the password (with something like AES or Blowfish)
  • salting the password
  • sending the data over HTTPS

An alternative is OAuth.

If somebody wants to hack you badly enough, they will always find a way. The secret is increasing the time and effort required enough that it's not worth the while of somebody doing it. Hence, if you don't have huge amounts of customer and/or financial data, and you're not a high-profile company, a standard security implementation like the above should be fine.

Dan Blows
  • 172
  • 4
  • 27
    Passwords should never be encrypted. Passwords must always be hashed. AES and BLowfish are not suitable for password storage. You need PBKDF2, bcrypt, script. (hell even a broken hash function md5 is better than AES for password storage.) – rook Sep 09 '12 at 22:05
  • in 2022 add argon2 on top of bcrypt for password hashing – PirateApp Dec 16 '21 at 07:41
2

You will never be 100% sure that your API is secure.

The main reason for this is that you're probably handing a binary to your customers/users that simply works. So then they have all the time in the world to dissect that binary to look for keys/secrets on it, used to authenticate securely on your API server. The client API endpoint is the weakest point, because they own the device in which your binary runs on, therefore they can manipulate the certificates that their device deems as valid or not.

A clear example of what I'm talking about is this article ("A Tutorial for Reverse Engineering Your Software's Private API: Hacking Your Couch"). And I would like to finalize this answer by quoting one of the last paragraphs in it:

Is it possible to completely prevent usage of a private API by third-party clients? I don’t think so. Using SSL pinning would prevent sniffing into API requests using a simple transparent proxy technique as described earlier. In the end, even if you obfuscate the binary, a motivated hacker with some resources and time will always be able to reverse-engineer the app binary and get the private key/certificate. I think the assumption that the client endpoint is secure is inherently wrong. An API client is a weak spot.

knocte
  • 161
  • 7
2

In JEE we have the notion of container managed security. In which case I set up my restful services to use Basic authentication, which by default is using the HTTP password authentication against a realm set up on the app server. This bypasses the need for an HTML form to login, or the complexity of deploying client side certificates.

The application just assumes that there would be a user principal and perhaps other data such as identification details that are passed with the request. This includes the restful APIs.

In my set up, I implemented an OAuth2 JASPIC server auth module[Source] that stores the OAuth token that is symmetrically encrypted where the key resides in the server that also has a limited life in the cookie and use that as the authentication for the application.

By doing the above I keep the application away from authentication semantics and as a bonus when I want to perform functional integration tests using Selenium I am able to downgrade to using HTTP passwords instead of having a complex test that connects to an OAuth provider all the time.

Also, I will still use SSL to ensure that at the very least your transport is secure. Not using SSL just adds too much complexity in dealing with common attacks to your application.

Mind you that this is JEE but the mechanisms can be applied to any technology.

1

HTTPS-only is a must.

As you control both the app and the api, I would implement Certificate Pinning. Certificate Pinning can be defeated but it is a good deterrent against the casual inspector.

You can add another layer with Payload Encryption. That comes at the cost building a solid Key Distribution and Key Rotation process.

If your app uses Access Tokens or Session Cookies for authorization to specific APIs, make sure they times out. I so often observe bearer-tokens which don't expire for days, months or ever.

Golden rule: A mobile O/S is a hostile environment. Treat it with care & a lack of trust.

rustyMagnet
  • 129
  • 3
0

I feel it's not lightweight and creates more network payload

It has some impact on latency - so if you need to process data in order of 10s of millseconds, that may be a consideration. But even in 2012, very basic hardware coul handle the computing overhead with negligible impact.

which may not be best suited for a mobile app

Then the above is not an issue.

symcbean
  • 18,278
  • 39
  • 73