Adding to the high-level look at good API design that @Daisetsu provided, the best way to actually secure a web-based REST API boils down to two choices:
1 Send everything over HTTPS. Allow the user to auth with the API to get a session key, and just include that in every future Query.
GOOD: Everything is secure.
BAD: Cost of negotiating the HTTPS connection takes more server resources (not an issue unless you have a heavy-use API) and the turn-around time on a call will be longer.
2 Utilize an HMAC (signature) and send it along with every request.
2 is what a lot of the Amazon Web Services APIs use and the most popular method for implementing the approach is typically referred to as "2-legged OAuth".
2 can look confusing/random/insanely complex given your comfort level with security so I'll outline the gist of how it works:
- The SERVER and CLIENT share 2 values: a public and private key.
- The public key can be known by more people, that's fine.
- The private key CANNOT. It must only be known by the server and the client.
- When the client makes a request to the server, it sends along 2 important things: the public key and an HMAC (aka a "signature")
The signature represents a hash of the parameters included in the request: /search.json?public_key=123456&term=shritam&range=180days&sig=dKdjalkjDKd97daskdDKl2
- The hash is calculated by combining all the parameters that make up the query into a string, then running the string and the secret key through a hashing algorithm like MD5, SHA-1, SHA-256, etc.
- The server receives the request and before doing anything else, using the public key given in the request, it looks up the user's secret key.
- Then the server re-combines all the request parameters in EXACTLY THE SAME MANNER the client did it, and hashes them with the secret key it just pulled from the database for that user.
- If the hashes match, the request is executed. If the hashes do not match, the request is denied.
Given how pedantic and finicky the nature of generating a hash is (if the input is 1 character different, like an extra space, the resulting hash is different) there have to be REALLY specific rules on how the parameters are combined, how they are encoded, how they are hashed with the secret key and so on.
Thankfully the OAuth 1.0 spec (Sections 3.4.1 through 3.4.2) do exactly that; they lay out exactly the process both server and client need to follow when generating that hash, so any OAuth-compliant client or server can communicate with one another more effectively.
Side-note: OAuth 2.0 is out, grab that!
Regardless of if you use OAuth or not, you just have to make sure your clients and server all agree on HOW the string is created and signed. Amazon Web Services uses a slightly different method to generate the string to sign by inserting newlines where as OAuth just concatenates everything together.
I have seen some APIs online that generate the HMAC by having the person hash their public key with their secret key and send that along; in that case you are essentially turning the HMAC into a session ID and risk the same side-jacking problems that sessions-over-unsecured-APIs suffer from.
Keep in mind that any parameter you include in the HMAC generation cannot be changed by a man-in-the-middle intercepting and re-submitting your query.
Any parameter that IS NOT part of the HMAC calculation, can be changed by a man-in-the-middle and resubmitted because it is not part of the signature, so when the server goes to recalculate the HMAC it won't see the mis-matched hashes caused by the change.
These are the highlights of securing an HTTP-based (not HTTPS) REST API.