Why is it a bad idea to send username and password with every request between mobile app and backend api? - api

I've been looking at the traffic from what is supposed to be a secure iPhone app for a work related task recently, and I've noticed that the app does not use any form for session id / token when talking to the backend. Every request contains the username, password and the device id, and all traffic is sent over https. It's a restful api, so there is no state server side.
I really feel that this is a bad idea, but i cant come up with too many good arguments for why.
If you are the victim of a man in the middle attack, the attacker can in most cases find your password when you log in, as the username and password needs to be sent to the server to obtain the session id / token anyways.
A better approach might be to send username, a timestamp and hash of timestamp and password. This server then drops the request if the timestamp is x seconds old, and the cleartext password does not have to be sent over the wire.
However, most apps i've looked at (except those who use oath and so on) just send username and password in in cleartext (over https) to obtain a token. this happens every time you start the application (both username and password are stored within the app data).
As the topic says, why is it a bad idea to send username and password with every request from a mobile/web app to the backend api, if https is used?

Well, you stated it yourself. You have to store the username and password on the device itself. How secure are those credentials stored? Would a rogue application installed on the device be able to retrieve the credentials? If the rogue application is running under the same account as the valid application, it probably can. Even if you store those credentials encrypted, you'd have to store the secret on the device itself.
Also, mobile devices have a much higher likelihood of being lost/stolen, giving an attacker access to the device itself.
Another reason is that sending the username and password every time, increases the attack surface. It will give an attacker more messages with constant data to try to decrypt.
Finally, verifying passwords, when implemented correctly should be relatively slow, making it less desirable for API authentication.
Protocols like OAuth 2.0 work with access tokens that are valid a limited time and you'd have to have access to the refresh token to get a new access token. Refresh tokens can be easily revoked in case the device is lost or stolen.

Related

Is such access-refresh token authorization schema without addressing to database safe?

So here is the modification of jwt access-refresh authorization schema without addressing database I come up with:
We store ip-address and device type in jwt refresh token, then encrypt the token.
Let's imagine malicious user hijacks the refresh token. The malicious user doesn't know anything about content of such refresh token as it is some encrypted string.
He wants to receive a new refresh token and sends us the hijacked one.
We decrypt the token, extract ip-address and device type from the token and compare with ip-address and device type of request. If they were equal, then we know it is request from authorized user and we give him new refresh token, otherwise it is request from malicious user and we reject the request.
Is there any pitfalls with such authorization schema?
Encrypting the refresh token is a good idea. It is a way of changing the JWT token into an opaque one, without the need for a database. It's also convenient that the token will be decrypted only by the authorization server, so there is no need to distribute any keys.
As for rejecting tokens with a different IP — that actually depends on your system and the characteristics of your users. A user's IP number can change even when it's not a malicious action. E.g., the user might switch to a different wifi or turn on VPN protection and will get a new IP number. Many routers are also assigned a new IP on every connection to the ISP, so the IP number can sometimes change even when the user does not change their location or network settings. If you know that this will not happen to your users and that they should always operate under the IP that they logged in from (maybe you have a system that is only meant for employees connecting from a concrete VPN), then that approach might be ok.
You would also need mechanisms in place that will protect against spoofing IP information. The same goes for the device type. You would have to make sure that you have a reliable source of information for the type of device, and that that information cannot be spoofed.

Separate authentication server for users and APIs

I'm working on a cloud service authentication system and I'm not entirely sure what the optimal way to handle authenticating requests is. We're planning to run our image server as a separate process from our API server so that we can scale them independently of each other. Handling request authentication with API keys is fairly simple, because we can just have the image server store its own API key and check that requests provide it in a header (over HTTPS obviously), same with the API server. For users though it gets more complex.
Right now we have it setup so that the API server will handle generating a session token and storing users in its database, however what we'd like to do is use 3 servers:
authentication server
API server
image server
and have the image and API servers authenticate requests against the authentication server. How exactly should this be done though? It seems like a bad idea performance-wise to hit the authentication server for every request that the API and image servers make. Can/should a token be verified from a different server than it was created on?
So for example: can/should I pass the token received from the authentication server to the image server, verify that the token came from "my.auth.server" and check that the user ID is the right one? Would JWTs be a good type of token for this?
Here's an alternative approach.
Your authentication issues a JWT token that is signed using a secret that is also available in your API and server images. The reason they need to be there too is that you will need to verify the tokens received to make sure you created them. The nice thing about JWTs is that their payload can hold claims as to what the user is authorised to access should different users have different access control levels.
That architecture renders authentication stateless: No need to store any tokens in a database unless you would like to handle token blacklisting (think banning users). Being stateless is crucial if you ever need to scale. That also frees up your API and image servers from having to call the authentication server at all as all the information they need for both authentication and authorisation are in the issued token.
Flow (no refresh tokens):
User authenticates with the authentication server (eg: POST /auth/login) and receives a JWT token generated and signed by the auth server.
User uses that token to talk to your API and image servers and assuming user is authorised), gets and posts the necessary resources.
There are a couple of issues here. Namely, that auth token in the wrong hands provides unlimited access to a malicious user to pretend they are the affected user and call your APIs indefinitely. To handle that, tokens have an expiry date and clients are forced to request new tokens whenever expiry happens. That expiry is part of the token's payload. But if tokens are short-lived, do we require users to authenticate with their usernames and password every time? No. We do not want to ask a user for their password every 30min to an hour, and we do not want to persist that password anywhere in the client. To get around that issue, we introduce the concept of refresh tokens. They are longer lived tokens that serve one purpose: act as a user's password, authenticate them to get a new token. Downside is that with this architecture your authentication server needs to persist these refresh token in a database to make them revokable before they expire (think "revoked" column in tokens table).
New flow (with refresh tokens):
User authenticates with the authentication server (eg: POST /auth/login) and receives a JWT token generated and signed by the auth server, alongside a long lived (eg: 6 months) refresh token that they store securely
Whenever the user needs to make an API request, the token's expiry is checked. Assuming it has not yet expired, user uses that token to talk to your API and image servers and assuming user is authorised), gets and posts the necessary resources.
If the token has indeed expired, there is a need to refresh your token, user calls authentication server (EG: POST / auth/token) and passes the securely stored refresh token. Response is a new access token issued.
Use that new token to talk to your API image servers.
OPTIONAL (banning users)
How do we ban users? Using that model there is no easy way to do so. Enhancement: Every persisted refresh token includes a blacklisted field and only issue new tokens if the refresh token isn't black listed.
Things to consider:
You may want to rotate refresh token. To do so, blacklist the refresh token each time your user needs a new access token. That way refresh tokens can only be used once. Downside you will end up with a lot more refresh tokens but that can easily be solved with a job that clears blacklisted refresh tokens (eg: once a day)
You may want to consider setting a maximum number of allowed refresh tokens issued per user (say 10 or 20) as you issue a new one every time they login (with username and password). This number depends on your flow, how many clients a user may use (web, mobile, etc) and other factors.
You can store some additional metadata (ip, geolocation, device, browser cookie, etc.) alongside refresh tokens. That way, you can be smart about when to reject malicious usages of refresh tokens in case it's compromised.
Common Q: Why store all refresh tokens, and not just revoked ones? You could do that. Ask yourself the following: Will I, at any point, need to have a functionality where I can dynamically revoke valid refresh tokens, based on some arbitrary, regulatory, legal, integrity, security etc. criteria? If so, the least you will need is a list of all issued tokens, plus any data required to implement the criterion logic. Example: Due to regulation, I need to ban all EU users equates to a delete from refresh_tokens were user_ip in <... eu logic ...>
one of the best ways to use is a JWT Token , you can generate and share it between all your servers and validate it on the server side .
https://jwt.io
also I think the best architecture to use in this case is the micro service architecture

What if JWT is stolen?

I am trying to implement stateless authentication with JWT for my RESTful APIs.
AFAIK, JWT is basically an encrypted string passed as HTTP headers during a REST call.
But what if there's an eavesdropper who see the request and steals the token? Then he will be able to fake request with my identity?
Actually, this concern applies to all token-based authentication.
How to prevent that? A secure channel like HTTPS?
I'm the author of a node library that handles authentication in quite some depth, express-stormpath, so I'll chime in with some information here.
First off, JWTs are typically NOT encrypted. While there is a way to encrypt JWTs (see: JWEs), this is not very common in practice for many reasons.
Next up, any form of authentication (using JWTs or not), is subject to MitM attacks (man-in-the-middle) attacks. These attacks happen when an attacker can VIEW YOUR NETWORK traffic as you make requests over the internet. This is what your ISP can see, the NSA, etc.
This is what SSL helps prevent against: by encrypting your NETWORK traffic from your computer -> some server when authenticating, a third party who is monitoring your network traffic can NOT see your tokens, passwords, or anything like that unless they're somehow able to get a copy of the server's private SSL key (unlikely). This is the reason SSL is MANDATORY for all forms of authentication.
Let's say, however, that someone is able to exploit your SSL and is able to view your token: the answer to your question is that YES, the attacker will be able to use that token to impersonate you and make requests to your server.
Now, this is where protocols come in.
JWTs are just one standard for an authentication token. They can be used for pretty much anything. The reason JWTs are sort of cool is that you can embed extra information in them, and you can validate that nobody has messed with it (signing).
HOWEVER, JWTs themselves have nothing to do with 'security'. For all intents and purposes, JWTs are more or less the same thing as API keys: just random strings that you use to authenticate against some server somewhere.
What makes your question more interesting is the protocol being used (most likely OAuth2).
The way OAuth2 works is that it was designed to give clients TEMPORARY tokens (like JWTs!) for authentication for a SHORT PERIOD OF TIME ONLY!
The idea is that if your token gets stolen, the attacker can only use it for a short period of time.
With OAuth2, you have to re-authenticate yourself with the server every so often by supplying your username/password OR API credentials and then getting a token back in exchange.
Because this process happens every now and then, your tokens will frequently change, making it harder for attackers to constantly impersonate you without going through great trouble.
Hopefully this helps ^^
I know this is an old question but I think I can drop my $0.50 here, probably someone can improve or provide an argument to totally decline my approach.
I'm using JWTs in a RESTful API over HTTPS (ofc).
For this to work, you should always issue short-lived tokens (depends on most cases, in my app I'm actually setting the exp claim to 30 minutes, and ttl to 3 days, so you can refresh this token as long as its ttl is still valid and the token has not been blacklisted)
For the authentication service, in order to invalidate tokens, I like to use an in-memory cache layer (redis in my case) as a JWT blacklist/ban-list in front, depending on some criterias:
(I know it breaks the RESTful philosophy, but the stored documents are really short-lived, as I blacklist for their remaining time-to-live -ttl claim-)
Note: blacklisted tokens can't be automatically refreshed
If user.password or user.email has been updated (requires password confirmation), auth service returns a refreshed token and invalidates (blacklist) previous one(s), so if your client detects that user's identity has been compromised somehow, you can ask that user to change its password.
If you don't want to use the blacklist for it, you can (but I don't encourage you to) validate the iat (issued at) claim against user.updated_at field (if jwt.iat < user.updated_at then JWT is not valid).
User deliberately logged out.
Finally you validate the token normally as everybody does.
Note 2: instead of using the token itself (which is really long) as the cache's key, I suggest generating and using a UUID token for the jti claim. Which is good and I think (not sure since it just came up in my mind) you can use this same UUID as the CSRF token as well, by returning a secure / non-http-only cookie with it and properly implementing the X-XSRF-TOKEN header using js. This way you avoid the computing work of creating yet another token for CSRF checks.
Sorry being a little late on this, but had the similar concerns and now want to contribute something on the same.
1) rdegges added an excellent point, that JWT has nothing to do with the "security" and simply validates, if anyone has messed up with the payload or not(signing); ssl helps to prevent against breaches.
2) Now, if ssl is also somehow compromised, any eavesdropper can steal our bearer token (JWT) and impersonate the genuine user, a next level step what can be done is, to seek the "proof of possession" of JWT from the client.
3) Now, with this approach, presenter of the JWT possess a particular Proof-Of-Possession(POP) key, which the recipient can cryptographically confirm whether the request is from the same authentic user or not.
I referred Proof of Possesion article for this and am convinced with the apporach.
I will be delighted, if able to contribute anything.
Cheers (y)
To deal with the problem that tokens are getting stolen, you map each JWT with the list of valid IPs.
For eg, when the user logs in with a particular IP when you can add that IP as valid IP for that JWT, and when you get the request pf this JWT from another IP (either the user changed the internet or JWT is stolen, or any reason) you can do the following depending on you use case:
Map CSRF token with user token and incase it gets stolen then it's CSRF token will not match in that you can invalidate that user token.
You can provide a captcha to the user to validate if he is a valid user or not. If he enters the captcha then add that IP to the valid list of that JWT.
You can log out the user and make a new request to log in again.
You can alert the user that your IP has changed or requested from a different location.
You can also use cache with a small expiry of 5 mins in above use-cases instead of checking each and every time.
Suggest if it can be improved.
Can't we just add the ip of the initial host which has requested to generate this JWT token as part of the claim ? Now when the JWT is stolen and used from a different machine, when the server validates this token, we could verify if the requested machine ip matches with the one set as part of the claim. This would not match and hence the token can be rejected. Also if the user tries manipulate the token by setting his own ip to the token, the token would be rejected as the token is altered.
Once the token gets stolen - it is game over.
However there is a way to make it harder to make use of a stolen token.
Check https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_for_Java_Cheat_Sheet.html#token-sidejacking for reference.
Basically, you create a x-Byte long fingerprint in hexadezimal, store its raw value in the token - hash the fingerprint using for example SHA-512 and put the hashed fingerprint inside a httponly secure cookie.
Now instead of validating just the signature and expired date of the token you need to also validate the existence of the cookie and be sure that the raw fingerprint values match.
Client should use part of the hash of user password to encrypt the time that the http msg was sent by client to the server. This part of the hash should also be encrypted with some server secret key into the token when it is created.
The server than can decrypt the http request time and verify for short time delay.
The token is going to change every request.

Is there any way to programmatically generate a CouchDB cookie?

I'm working on an app which will use CouchDB to store some data for users. But I don't want users to log into CouchDB directly.
I will have an app client (mobile/web), an app server, and the CouchDB server. The client app will authenticate to the app server, then myy ideal scenario would be for my app server to authenticate the users programmatically, then send just the 10-minute cookie to the client app.
That is, I would like the app server to request a Cookie from the CouchDB server on behalf of the user of the app client, then send only the cookie to the app client.
The app server could just POST to _session on behalf of the authenticated user, but this requires:
maintaining a list of users' passwords in the app server
using a single, known, password for all users
resetting the password to something random for each authentication request
For security reasons, #3 seems the best, but this seems like extra work, and is an extra round-trip to the DB (albeit, not an expensive one). So my question is: Is there any, as an administrator, way to generate a cookie on behalf of a user, without using the users' password at all?
This would also potentially allow me to entirely reject requests to _session except from my app server, as an added security measure.
And for the sake of completeness, I'll also mention that I've looked at these other options, and found them wanting:
Proxy Auth
The fact that the x_auth_token never expires is worrisome to me. It means a compromised token would grant forever access to the user's data. And AFAICT, the token can't even be invalidated without changing the user name or the server secret (which would in effect invalidate everyone else's auth tokens as well). But maybe I'm missing something here?
OAuth auth
This seems to just move the problem. Now rather than storing users' passwords in my server app, I have to store OAuth secrets. Plus, now my server and client code must be more complicated.
I don't follow your exact goals. You seem to imply users might have passwords ("app server authenticating the users programmatically") but you don't want the users to "ever need to know their CouchDB password". What sort of authentication do you want?
There's two (and a half) general approaches I've taken to authentication with CouchDB:
"Man-in-the-middle[ware]" approach, where I have thin middleware in front of CouchDB. This middleware forwards username/password to the "/_session" which yields a cookie or error codes based on the CouchDB _users database. The middleware copies this cookie from CouchDB onto its own HTTP response back to the client (or displays a message in case of error). Then on subsequent requests, that need database access, it forwards the cookie (now from the client request) back again to the database.
The traditional approach, where you just use CouchDB as a data store and maintain your own "user" entries/indexes. Make sure you use current best practices for password storage/handling or use a library that takes care of those details for you. The middleware connects to the database as "itself" and handles read/write permissions with its own logic based on its own session handling.
Or — sort of a hybrid approach — you can use the "/_session" API only to see if CouchDB accepts the username+password as valid. If it does, create a separate middleware-handled session for that user. (Basically you're only using CouchDB's _user database as the "password handling library" and the rest is the traditional approach where the access control is implemented all in the middleware rather than at the database.)
For real-world production stuff, I've tended to use only the latter two (or one-and-a-half given the earlier numbering…) — the first method is kind of fun, but CouchDB's lack of document-level read permissions usually means that giving users nearly-direct access to the database server is untenable in practice.
UPDATE: your question now makes it clear that you want the client app to talk directly to both servers: the app (formerly "middleware") server and the CouchDB (database) server. I'm leaving the content above because I think it's still somewhat useful and provides a bit of background/context for this update.
You are right in your suspicions that Proxy Authentication is the wrong solution: it is not intended for end-user usage, but really to replace the cookie-forwarding "trick" portion of #1 above. That is, proxy authentication is when you fully trust one party (i.e. your middleware) to provide the user information as it works on behalf of a user. But you want the users to talk to the database directly, and you cannot trust them with the X-Auth-CouchDB-Token.
I will defer to your judgement on the OAuth option. I do think it is closer to want you want but it is clear that somehow you are authenticating users against a different service and don't need to store per-user keys in CouchDB itself. The request signing required by OAuth 1.0 does mean you'd need support in your client app's HTTP library too.
I see a few options, without building a custom CouchDB plugin, that could let your app server hand out a token to authenticated users which your database server will accept:
Proxy after all! That is, hide your database server behind your app server or another lightweight custom reverse-proxy. All this middleware needs to do is check your existing client app session (cookie or other authentication header) and if it's valid, set the internal proxy auth headers that CouchDB will accept — then it forwards the rest of the request/response verbatim.
Deterministic password, per-user if it makes you feel better. Configure your app server with a secret known only to it, then set each user password to something like HMAC(username, app_server_secret). Now when you want to generate a token for a user, your app server can generate the password on a per-user basis. Note that this really isn't any more secure than just using the app_server_secret as the password for every user — CouchDB already salts and hashes each user password independently so if someone gets a hold of the database but not your app's configuration values the attacker couldn't tell the two apart. In both cases, preventing unauthorized database usage hinges entirely on keeping app_server_secret secret.
Re-implement CouchDB's current cookie generation algorithm. CouchDB's cookie algorithm (view source) is basically data = username + ':' + timestamp; base64(data + ':' + sha_mac(data, secret)). Where secret is the couch_httpd_auth.secret value plus the user's salt value. You can tell your app server the couchdb_httpd_auth/secret value and it can follow the same steps to generate a valid cookie which you provide to the client app, and CouchDB will accept it as its own. This cookie will be valid until the timestamp + the configured couch_httpd_auth/timeout. As "hacky" as it seems, this is probably the closest to what you are asking for, although you still need to set/disable the users' actual passwords somehow.
Expanding on natevw's brilliant answer. I was having similar problems, and never would have realized option 3 was possible without having stumbled across that answer.
Here is my python3 implementation for generating a cookie (uses pycouchdb to interface with couch):
def generate_couchdb_cookie(couchAddress, couchSecret, username):
timestamp = format(int(time.time()), 'X')
data = username + ":" + timestamp
server = pycouchdb.Server(couchAddress)
db = server.database("_users")
doc = db.get("org.couchdb.user:" + username)
salt = doc["salt"]
secret = couchSecret + salt
hashed = hmac.new(secret.encode(), data.encode(), hashlib.sha1).digest()
inbytes = data.encode() + ":".encode() + hashed
result = base64.urlsafe_b64encode(inbytes)
return "AuthSession=" + (result.decode("utf-8")).rstrip('=')

Preventing "Pass the Hash" Attacks in a Web API?

I may not be going about this in the best way possible, but as a school project, I'm in a group where we are developing a system to handle checking in and checking out of dorm rooms and handling any charges that may arise because of damages to items in the room. We are digitizing the project and putting in on the web and writing a native iPhone app (part of the assignment, I'd rather just make it a universal web app, but oh well). For the iPhone app, we're putting together a web API but I'm having some doubts about our attempts to keep the API secure.
Our process right now is a call to the API to log in with a username and a password hash, if it was a successful login, an Authentication Token is generated and returned to the iPhone in XML along with various other data. Each subsequent request requires this AuthToken. A user can either sign out, or if there's inactivity for 20 minutes, the AuthToken is destroyed server side. But this leaves the API open for the "Pass The Hash" attack where anybody listening in on the request can get the password hash out of the query string. Anybody with Wireshark and a simple filter can wait for somebody to sign in when everybody would be moving into the dorms and be able to manipulate just about anything.
Every single request is susceptible to the Pass The Hash attack. When logging in, the username and password can be repeated later to obtain a different AuthToken. Not only that, any already generated AuthTokens could be used and the session extended without the real user knowing.
I have thought of the idea of tying the AuthToken to an IP address and rejecting requests that use a valid AuthToken from an alternate IP address, is this reliable or will the iPhone be jumping IP addresses when on the cell network instead of Wifi? I want to give any malicious users a hard time, but obviously not legitimate users.
The project is still in the early stages so now would be the time to make drastic changes to the API like this. Any tips on securing a web API would be awesome.
Your best bet would be to send everything over SSL. That will prevent anyone listening to the wire and sniffing either the password hash or the authentication token.
You should also consider sending a nonce to the client that gets hashed along with the password to prevent replay attacks.
It's also pretty easy to change the authentication token on each request. This prevents both replay and session-fixation. Just make sure the tokens are good random numbers.
You need to use HTTPS.
Most anything on HTTP is susceptible if you include people using Wireshark. HTTPS encrypts all traffic between the client and the server and will prevent most packet sniffing attacks.