In a series of two posts, I will explain how to secure the communication between a Flex client and PHP server architecture. The first part will explain how I envision that security, and in the second part I will show snippets of PHP code for the practical implementation.
I’m currently working together with my friend and colleague Vic on a client-server application that involves Flex on the front-side, and PHP (Zend Framework) on the back. Since I’m the PHP guy, I’m in charge of creating the API for his Flex application. For the moment, the project will only be accessed locally from the client’s network. But there is a possibility that in a later stage, it might open up to the general public. One of my main concerns was how we could make every API call as secure as possible. This without making it too complicated, or involve too many service calls that might slow everything down.
First login…
The first aspect of securing the application, is authentication of users. The application is accessible to multiple users, and those are grouped in various groups. Each group has different privileges. To identify every user, they are given usernames and passwords. My biggest concern with the login process, is that we didn’t have access to a secure connection via SSL. This means that every communication between the client and server software can be monitored by network sniffers. Flex uses the AMF protocol to communicate with Zend_AMF. Even though this is a binary stream, the specifications are open to everyone. So it is possible to intercept communications, and read everything out.
I wanted to make sure that during the login process, the password was not exposed to the outside world via the communications line. Because once the password and username are intercepted, then it would be easy to start making fake API calls to the server. The solution I had in mind, is called CHAP – Challenge-Handshake Authentication Protocol. Here’s a diagram about how this protocol works.
The main purpose of using CHAP, is to authenticate users, without having to transmit the password between the client and the server. To accomplish this, we have to replace the password with something else, but still allowing the server to recognize the correct user, and log him in. I call this password replacer the “signature”.
In the first phase of the diagram, the client requests a “challenge” from the server. A challenge is a key that will be used by both the client and the server, to create the signature. During the first phase, the client asks the server what key will be used to encrypt the password. It is important that both the client and the server use the exact same challenge.
During the second phase, an authentication request is being transmitted. Instead of using the username and password, we use the username and signature. The final signature is calculated like this:
$signature = MD5(MD5($password) . $challenge);
The client calculates this signature, and sends it to the server. The server then looks up the given username in the list of possible users. The corresponding password is then used by the server, to also calculate a signature, with the earlier given challenge. The outcome of that comparison is given during the third and last phase of the CHAP authentication.
This is not a very difficult protocol to implement, but according to me, it still provides a reasonable amount of security during the login process.
… and then the rest of the calls.
Now that a user is logged in, the most important stuff still has to happen: interactivity with the server by calling API methods. Once the user is authenticated, he remains authenticated by using the browser session. So now we have to keep in mind that other people might try to steal the session, and invoke undesired API calls. During each call, the server needs to be sure that it was still the same client making the call, and not some man-in-the-middle.
For this, I decided to elaborate on the CHAP protocol, used for authentication. How about we could keep the system, where the client signs its calls with a signature. For obvious reasons, it is not possible to recycle the signature from the login procedure. But I wanted to force the client to generate a new signature for each API request. There are still two variables to generate the signature: the password and the challenge.
It was not a practical option to ask the user’s password for each and every API call. Instead, once the user was authenticated, I had the Flex application remember the password in its memory. This way, it could be recycled to generate new signatures.
The only problem was the challenge. A first option was to have the client request a challenge from the server. But this would mean that for each regular API call, there would be an additional call for a challenge. That would double the amount of API calls. I was afraid that in the long run, this would generate too much calls for the server. That’s why I chose a second option: have the client generate the challenge and transmit it alongside the signature. The server would then use this challenge, and the password from the session, to calculate the signature. If they matched, then the call was permitted to be executed.
As far as I could see, this wouldn’t impose a bigger security risk. Of course, a man-in-the-middle could generate fake challenges. But he still wouldn’t be able to generate fake signatures. For that, he still needs the correct password. Once he has that, then well… all security checks fail. The responsibility of keeping the password secret lies entirely at the client now.
9 Comments
Pingback: Security with Zend_AMF and Flex – Part 2: Practise
Thanks for your elaboration,
This is exactly what I was thinking, I was just wondering what your take on it all was. I really like the signature idea for verification a lot
Hi,
The password should never be stored as plain text in your database. This makes it easy for a hacker to see everything. You could encrypt it via a hashing method (sha1 or md5), but that’s not good in this case, since hashing is one-way. I usually encrypt/decrypt the password in the database with AES_DECRYPT() and AES_ENCRYPT(). Both are MySQL functions, and require a salt to encrypt the password with. This salt should be known to your application, so you would have to store it somewhere in a configuration file.
As for creating new users, I honestly haven’t thought about that. My method comes from a case at work, where new users were created via a web interface that already existed. I haven’t put any thought into that part. So obviously it suffers the same flaws as a connection via Flash/flex: it can be intercepted. At the moment, I cannot think of a really safe way to register a new user, except with an SSL encrypted connection (HTTPS). But then again, if you have SSL, you won’t be needing this method.
This method is not for encrypting the data you send to the server (creating a user sends his username and password to the server). It is meant to digitally sign a request to the server, thus making sure that the data can be trusted to come from the user. A hacker will still be able to see what the user is sending to the server, but he won’t be able to tamper with the data.
Interesting solution, I have a question about the signature though.
Interesting solution, I’ve got a couple of questions though.
In order to correctly generate the signature, both parties need to know the challenge and the password already. How do you generate your initial password for a new user safely, without a third party listening in on this?
Even more important (I think), how do you store it? In order for this to work correctly, it seems that you need to store the password as is. Or do you encrypt/decrypt the password on the server side?
PKI infrastructure sounds good, but you will need a client that is able to handle this kind of thing. Perhaps it is possible with flex. But I’m not sure if it is possible with Javascript. And my design was a bit meant to be working with both Flex and Javascript (even though I didn’t mention that in my post).
For your question: I don’t know if you mean you want to send a push from the server to the client side, or if you just mean that you want to require the client side to sign his challenge-request with his private key. The former is probably not possible, since it is strictly a pull technology as far as I know. The latter should be possible. You can build it, and then require your client to use the private key for the challenge-request by design. If someone wants to develop an alternative client, then he will have to incorporate that particular design as well.
Does that answer your question?
I have a suggestion: use pki infrastructure instead that strict same challenge.
server crypt with client public key(the client will decrypt with his private key) and the client side will crypt with server public key(..)
and a question: do u have any idea if I can make a request from server side for client side (browser in my case) to sign(with his private key) a challenge…?
Hmm, make that tomorrow. I still have to do some testing before I publish the article.
Thanks. I’m in the process of writing the second part. I hope to have it ready by this evening (CET timezone), and you’ll be able to download my code.
Great stuff, now the second part?
I’m specifically interested in how you structered the zend_amf side of it.