I'm building an API with no server-side authentication. A unique key (assume the key is very long and impossible to guess) will be generated for the session, but no cookie will be set on the client. The client could be a web browser with AJAX, a PHP script using CURL, or a desktop application. The normal transaction process I'm imagining will be:
Initial encounter
The client makes an initial request, calling a start_session method
The server generates a key and returns it along with some initial data
The client stores the key for later use (e.g. JavaScript sets a cookie with the key)
Next request
The client requests the server again, calling some set_data method, providing the original session key, as well as loads of private data such as a credit card number, information about legal cases, etc.
The server responds, and the responds with a success message
Another request
The client requests the server again, providing the original session key, and calling some get_data method
The server responds with all of the private data in some format (e.g. XML, JSON, etc)
A session key expires, if not used, in a 20 minutes, and all API URIs will require SSL.
My concern / question is: Do I need to be worried about whether the client has leaked the session key. Without authentication, I'm trusting that the original requester to keep the session key private. Is this common / safe practice?
Unless you use HTTPS throughout, you're vulnerable to HTTP sniffing, a la Firesheep.
Eve, if you do use SSL, if the client page isn't SSL or contains any non-SSL Javascript (or non-SSL frames in the same domain), you're still vulnerable (and there's nothing you can do about it)
To answer your stated question, it completely depends on your situation.
EDIT: You should warn your clients (developers) in the documentation page to handle the key correctly.
Beyond that, it depends on the average skill level of the clients.
You should probably have a disclaimer of some sort (I am not a lawyer).
It's probably OK.
Related
On webpage (with https)
Client connects to server with websocket (secure wss over TSL)
Server send 'ready-for-user-and-password'-message
User enters info and Client sends it
Server validates and as long as websocket is connected, knows who the recipient is
EDIT:
I am considering the above instead of using a post method.
It can be safe against some attacks but as usual, there are ways to break into the site and we have to evaluate security holistically
DB passwords
It is not clear from the description but plausible that the setup you've described stores user passwords in plain text.
Best practice in that respect is to calculate password's hash sum with salt and keep that in the database, so if attacker manages to get a db dump, they will need a lot of time to guess a password based on that.
Rate limiting
You should limit unsuccessful login attempts so the attacker won't be able to easily pick a password by bruteforce.
Logging
Another thing which can be problematic here is logging: you need to make sure the credentials don't end up on application log files (I've seen that with credit card numbers).
Similar concern is retaining the sensitive info for too long after verification has ended which makes them more vulnerable (to e.g. forcing a heap dump in Java and picking them from that file)
SSL secret material
If you don't pay enough attention to reducing the access to ssl private key, somebody can play a man-in-the-middle attack.
Depending on the ciphersuites your app server supports, previously recorded communications can be vulnerable to decryption if an attacker steals the key. The concept of resistance to that is called forward secrecy. You can validate if you properly tuned your web app here.
Your cert authority (or any other else) can issue a certificate for your website to somebody else allowing the attacker to misrepresent you (see Mozilla and WoSign, Additional Domain Errors).
CORS
You should also set the Content-Security-Policy so that it will be trickier to force the browser code to send this auth info to other servers.
Social Engineering
Attacker can trick your user into launching some code in the web tools console - you can try opening a web console e.g. on Facebook and see what they've done against that.
New stuff
Vulnerabilities get discovered each day, some of them are published on bulletins, you should follow those for your stack (e.g. OpenSSL) and patch / upgrade where appropriate.
I was discussing development of an API with a colleague, and the following proposal has made me wonder about the securability of it.
Scenario:
There is a web application that is running on server A that (in addition to other functions) allows the admin user to specify arbitrary URLs, and security for the users within their account related to each URL. So basically:
URL:"/foo/bar", UserID:1234, AllowedToView:true
The admin user then has their own web application running on their own, separate server B. And they want to check if their end users that have logged in on that server B application have access to a particular URL on that server B application by checking against the API on server A.
This check could come in 2 forms:
A server-side HTTP call (from server B to server A) that happens within the context of a user requesting a url from server B, so this would look like:
User requests "/foo/bar" with their client from server B
During the processing of that request on server B, it makes an HTTP call to server A to check if that user has access to the requested URL
With the response from server A, server B can then either allow the user to access or redirect, send 403 access denied, etc.
An AJAX request from the end user's client directly to server A and utilizing the response with JavaScript. An issue of cross-domain scripting could be problematic here.
One challenge that comes to mind immediately is that there would have to be a way for the admin user to directly associate the end user that is accessing their web app on server B with the UserID that is associated with that user in the web app on server A. But let's assume that has been solved elegantly somehow :-D.
My question related more to the inherent (in)security related to a scenario like this. If the requests that are being made to server A (in both 1 and 2 above) are made with https, then can the integrity of the responses be counted on?
HTTPS makes sure the message can't be read or tampered with any relaying parties (proxies, etc.) but it doesn't guarantee the source of the data is trusted. If another service can determine the other URL and wire format they could spoof a request to it. This is generally where something like request signing comes into play using a shared-secret signing mechanism. Twilio's API uses this method to prove to you that they're actually calling your servers. HTTP Signatures is a proposal for a standardized way of doing this.
You can't rely on client side validation if you really want to secure your server B. That is, your second scenario - calling server A from the client side to see if it can access resources - is not a secure method. You need to count on the client to behave nicely, which of course leaves you open to attacks.
You first scenario - server to server call is a secure and preferred method. You will still need to secure your call using signing or just passing the shared secret itself to validate the origin of the call (using HTTPS).
That said, there are ways to secure a flow that goes through the client, but it will usually involve signing the data on the server since you can't have your client sign it (you can't place your secret in the client).
We are partnering with a service provider which exposes their services via RESTful API.
We can authenticate with the API by passing a username and password as URL parameters.
Example: https://example.com/api/service.json?api_user=Username&api_key=Password
I know this is using SSL. However, since the username and password are part of the URL, couldn't this be intercepted by a third party?
No, a third party will only be able to see the destination (example.com). The rest of the URL is actually embedded inside the request.
It helps to understand the process of how an HTTP (or HTTPS) request is made.
determine protocol (in this case HTTPS, using port 443)
get IP address of server using DNS
establish a TCP connection to server (if SSL is involved, it's a bit more complicated)
issue a request to server on the new connection which will look something like
GET /api/service.json?api_user=Username&api_key=Password
Since the actual request is part of the encrypted data stream, there's no way for someone monitoring the connection to extract sensitive information.
The previous answers are both technically correct; if you're using HTTPS, the URL and querystring data will be encrypted prior to transmission and can be considered secure.
However, the fact that an API is asking for a username and password as querystring parameters may indicate a somewhat lax approach to security.
For example, many webservers will log the request querystring parameters by default , which means that your plain-text credentials might be lying around on disk somewhere (and many companies will store, or back up, webserver logs in insecure ways).
In short: passing credentials as querystring parameters isn't a security risk per se, but is generally a bad practice and may be symptomatic of larger security issues.
However, since the username and password are part of the URL, couldn't
this be intercepted by a third party?
The URL is sent under encryption as well. In other words, the process that secures the channel occurs before the URL is sent to the server.
You're safe.
I am implementing an app where I don't have a system requiring username and password. What I do require is a name and a phone number.
The scenario is like this:
1) user opens the app for the first time
2)app makes a request to my server and gets a unique UserKey
3)from now one any request the app makes to my REST service also has a signature. The signature is actually a SHA(UserKey:the data provided in the request Base64Encoded)
4)The server also performs the same hash to check the signature
Why I don't use SSH:
not willing to pay for the certificate
I don't need to send sensitive data like passwords, so I don't see the benefit of using it
I just need a simple way to call my own WCF REST services from own app
I understand that there is a flow of security at step2 when the UserKey comes in cleartext, but this happens only once when the app is first opened. How dangerous do you think this is?
What would you recommend? Is there any .NET library that could help me?
Actually, there are several problems with that approach. Suppose there's man-in-the-middle whenever you make a request to the server. By analyzing, for example, 100 sent packets he would recognize similar pattern with signature in your requests. Then he would forge his own request and add your signature. The server checks the hash - everything's alright, it's you and your unique user key. But it's not.
There's a notion of asymmetric keys in cryptography which currently is really popular and provides tough security service. Main concept is the following: server generates two keys - public and private; public key is used to encode texts; they can be decoded only with the use of private key, which is kept by the server in secure location. So server gives client the public key to encode his messages. It may be made double: client generates public key and gives it to the server. Then server generates keys and gives encoded with client's public key his own public key. This way it's almost impossible for man-in-the-middle to make an attack.
Better yet, since the problem is really common, you could use OAuth to authorize users on your website. It is secure, widely used (facebook, g+, twitter, you name them) and has implementations already in variety of languages.
Since you control both the application itself and the webservices, you can do this with SSL (which gets rid of the problems with your current approach) without paying for anything. You can create a self-signed certificate and install that on your webserver; configure the SSL context of your client application to only trust that one certificate. Then, create a client-side self-signed certificate and install that within your application. Set the server up to require mutually-authenticated SSL and only allow your self-signed certificate for access.
Done. You client will only talk to your legitimate server (so no one can spoof your server and trick the client in to talking to it) and your server will only talk to your legitimate clients (so no one can steal information, ID, etc). And it's all protected with the strong cryptography used within SSL.
I would like to use the HTTPS to secure the communication between my client and the server. The first encrypted communication will be used to authenticate the user - i.e. checking his/her user name and password.
After the user credentials will be successfully checked by server I would like to start getting some data in subsequent requests. BUT how the server will determine that the subsequent request is send by the user, whose credentials were already checked?
Since the TCP connection might be closed between login and subsequent HTTPS requests, (I think) this means that the SSL context must be released by the server, so with the new GET request, the new TCP connection must be established and the new SSL(TLS) handshake must be done (i.e. new shared password for the encryption must be exchanged by both sides, etc.)
For this I think server needs to send back to the client in 200 OK response for the initial authentication request some randomly generated nonce (which is valid for a certain time), which I will include in every subsequent request, so the server will be able to detect, based on this randomly generated nonce, which user name is behind the request and check that this user is already logged in. Is my understanding correct?
Thanks a lot for the reply
BR
STeN
The simplest method is to require all communication to go via HTTPS (so the data is confidential; nobody other than the client and the server can see it) and to use simple username and password on every request inside that secure connection. This is dead simple to do in practice (the username and password actually go over the connection as an HTTP header, which is OK here because we're using HTTPS) and the server can check every time that the user is allowed. You don't need to worry about the SSL handshakes; that's the SSL/HTTPS layer's responsibility (and that's why HTTPS/SSL is nice).
Alternatively, the login can be done with any method and generate some kind of magic number (e.g., a UUID or a cryptographic hash of a random number and the user's name) that is stored in a session cookie. Subsequent requests can just check that the magic number is one that it recognizes from session start (and that not too much time has passed since it was issued); logout just becomes forgetting the magic number on the server side (and asking the client to forget too). It's a bit more work to implement this, but still isn't hard and there are libraries for server-side to handle the donkey work.
The first option is particularly good for where you're writing something to be used by other programs, as it is really easy to implement. The second option is better where the client is a web browser as it gives users more control over when their browser is authorized (program APIs don't tend to need that sort of thing). Whenever the client is going to be a browser, you need to take care to armor against other types of attack too (e.g., various types of request forgery) but that's pretty much independent of everything else.
Inventing custom authentication mechanism in your case is very risky - it's easy to make a mistake that will let lots of wrong doing. So the right approach, as for me, would be to use HTTPS and pass user credentials with each request.