I have an API that is serving content to a mobile app, and have no current plans to use the API for other products. I have 2 main questions:
How to prevent someone from sniffing the API requests and making their own requests (this should not be an public API).
If preventing #1 is not possible completely, then how can I limit/throttle requests from un-approved consumers? Are there other concerns here?
Using an auth token (passed as A GET param) for each request satisfies #2 (I can revoke it at anytime) however I do not want to have to update the app to use a different token in future.
Also, there is no authentication for users in the mobile app, and the API is written in PHP.
What are the best practices in this area?
Here are a couple of suggestions that can help keep your API private.
Use TLS to discourage casual packet sniffing.
Make sure your clients verify the server certificate to prevent MITM attacks.
Encrypt or obfuscate the auth token in the client code so it's not obviously exposed in something like a string dump.
Ultimately, though, if someone really wants to access your API, they will - either through reverse engineering your client code, or more complex data interception techniques. The best you can hope for is to discourage access attempts by the average user.
How to prevent someone from sniffing the API requests and making their own requests (this should not be an public API).
I would echo the previous answer that you should use TLS as a matter of course, in order to encrypt the traffic on the wire to prevent sniffing. But I would add that you also need to deter "capture-replay" attacks, whereby an attacker may resend a previous message which they may have obtained (e.g. from a client-side log) despite the usage of TLS. In this case, if you are using a nonce (meaning "number once") and/or timestamp in your requests, with HMAC signing, then the replayed API request can be detected and blocked. I have written about an example of this on my blog: http://www.soatothecloud.com/2011/02/securing-apis.html . Amazon's APIs, for example, use this approach.
If preventing #1 is not possible completely, then how can I
limit/throttle requests from un-approved consumers? Are there other
concerns here?
As well as the HMAC signing (above), you can also consider monitoring incoming IP address range, device info (e.g. headers indicating the device type - Android vs iOS etc), and other factors which can be used to link multiple requests to particular clients, and then apply policies at the API level.
Full disclosure: I work for an API Management / API Gateway vendor (Axway) but the info above should be generic.
Related
I have a Single Page App application which is working based on RESTful APIs. Generally, all APIs have a route access which can be found while inspecting web application.
Although I have authentication mechanism based on user tokens, a hacker can find the API routes and use his given token to send many requests to APIs directly.
What is the best solution to prevent such behavior? I was thinking about CSRF, but as APIs are based on REST, and the project is a SPA, I think I should have another mechanism.
May you help me please?
You cannot authenticate the client application, it is not possible. If a user can send a request from an spa, because they have the credentials and the endpoints to send them to, they can use whatever client from Burp through ZAP or Postman to curl or whatever else to send the request.
Your API must be resilient, you should have rate limiting, user quotas, monitoring and secure operation practices in general on the server side based on your threat model to mitigate this risk.
In practice this might mean hosting the API in a way that's resilient to DoS on the network level, having a per-user request rate limit, identifying functionality that is a burden for the server for some reason (calls external services, sends email and so on) and protect/monitor those even more carefully. There is no one size fits all solution.
To ensure a REST API is accessed only by known consumers, client applications use to sign each HTTP request with a secret and then send the resulting signature togheter with the API key to the server.
In case of JavaScript clients the API key and secret are hardcoded in the script itself... so how does this mechanism ensure a client sending the request is really the client it is supposed to be? I'm asking because if the secret is hardcoded in the JavaScript, everybody could look at it, steal the secret, and use it in other applications.
Is there a safer way to expose an API to consumers? I know there are other posts in Stackoverflow covering this topic... but what is not clear to me is how to deal with both consumer authorization and user authorization. In my case, consumer authorization determintes whether or not a third party is allowd to access my API and has nothing to do with business logic, while user authorization is at application level (i.e. after the consumer has been identified and authorized).
You can check the domain and provide a SOP setting to restrict to only known domains.
You can drop requests by origin ip if the ips are going to be constant.
Moreover you can have a secret generator on your server which client need to call from there on servers and pass it on their js code, from there it can be attached to api call. This way client with SOP can make sure that their js is not injected. You can check on the clients IP before providing the response.
Basically, it would depend on the type of consumers you going to serve. Are they enterprise customers, etc.
After some googling I found this great article and just implemented the solution it describes ;-)
I am a beginner web-developer and I have some doubts about the security of an API that I developed. It's a simple web-service that requires authentication in order to access/modify data.
I am wondering what are the best practices for authenticating users via HTTP.
Currently my app works like this:
User authenticates through an API request (POST) which requires the username and the password. The response contains info about the user and a TOKEN which will be used in the future for further requests.
My concerns: I don't know if the auth request should be POST. It sounds more like a GET, because POST should create something (at least this is the convention in Ruby on Rails). And then, even with POST or GET, the information is still "visible" during the transfer of the information. I heard something about HTTPS - how does that solves the problem?
The token is generated at user creation time - and remains the same in time. Is this bad? Should the token be generated again after a "logout"? I've seen APIs that use an API_KEY along a token for authentication. How does that work?
I have some GET requests to retrieve information about something. With this request I pass as an parameter the token retrieved from the authentication request. Is this ok? I mean that token is sensitive information.
Where can I find more information about these concerns of mine (book, article, w/e)?
HTTPs encrypts all traffic to your web site, and so would hide any get and post requests. It requires you to purchase an HTTPS certificate (which are cheap), and get a non-shared IP to host on (not so cheap). (If anyone talks about self signed certificates - well, it's possible, but ill advised if external people want to talk to your service).
Having a long lasting login token can be bad, it depends what sort of non-repudiation you want. If someone can log in 2 years ago, and continue using a token how do you know it's still the original requestor? Tokens should expire and have a way to re-request.
API keys generally work on a shared secret which is swapped out of band (by getting it from the hoster's web site generally). A custom authentication scheme and header is used, and must be calculated and checked for each request. This doesn't require HTTPS - the shared secret is used to generate the authentication header, but isn't sent with it, so the secret doesn't travel with each request. Of course you need to write this code, and figure out what you want the process to be. I'd generally avoid this unless you know what you're doing - you need to take a canonical representation of the request, sign it, then use that as the header. It's not complicated, but it's not simple either.
The problem with GET is more one of physical security than web security - I know that I log into sites regularly at work or at home in the company of others - I certainly don't want my credentials appended to the URL as a query string.
Using HTTPS (SSL) will secure your postdata as the information is encrypted before it is sent over the line. The encryption algortihm uses some quite clever maths in generating its decryption tokens to ensure that it's not susceptible to a man-in-the-middle attack.
I'm developing a REST API that requires authentication. Because the authentication itself occurs via an external webservice over HTTP, I reasoned that we would dispense tokens to avoid repeatedly calling the authentication service. Which brings me neatly to my first question:
Is this really any better than just requiring clients to use HTTP Basic Auth on each request and caching calls to the authentication service server-side?
The Basic Auth solution has the advantage of not requiring a full round-trip to the server before requests for content can begin. Tokens can potentially be more flexible in scope (i.e. only grant rights to particular resources or actions), but that seems more appropriate to the OAuth context than my simpler use case.
Currently tokens are acquired like this:
curl -X POST localhost/token --data "api_key=81169d80...
&verifier=2f5ae51a...
×tamp=1234567
&user=foo
&pass=bar"
The api_key, timestamp and verifier are required by all requests. The "verifier" is returned by:
sha1(timestamp + api_key + shared_secret)
My intention is to only allow calls from known parties, and to prevent calls from being reused verbatim.
Is this good enough? Underkill? Overkill?
With a token in hand, clients can acquire resources:
curl localhost/posts?api_key=81169d80...
&verifier=81169d80...
&token=9fUyas64...
×tamp=1234567
For the simplest call possible, this seems kind of horribly verbose. Considering the shared_secret will wind up being embedded in (at minimum) an iOS application, from which I would assume it can be extracted, is this even offering anything beyond a false sense of security?
Let me seperate up everything and solve approach each problem in isolation:
Authentication
For authentication, baseauth has the advantage that it is a mature solution on the protocol level. This means a lot of "might crop up later" problems are already solved for you. For example, with BaseAuth, user agents know the password is a password so they don't cache it.
Auth server load
If you dispense a token to the user instead of caching the authentication on your server, you are still doing the same thing: Caching authentication information. The only difference is that you are turning the responsibility for the caching to the user. This seems like unnecessary labor for the user with no gains, so I recommend to handle this transparently on your server as you suggested.
Transmission Security
If can use an SSL connection, that's all there is to it, the connection is secure*. To prevent accidental multiple execution, you can filter multiple urls or ask users to include a random component ("nonce") in the URL.
url = username:key#myhost.com/api/call/nonce
If that is not possible, and the transmitted information is not secret, I recommend securing the request with a hash, as you suggested in the token approach. Since the hash provides the security, you could instruct your users to provide the hash as the baseauth password. For improved robustness, I recommend using a random string instead of the timestamp as a "nonce" to prevent replay attacks (two legit requests could be made during the same second). Instead of providing seperate "shared secret" and "api key" fields, you can simply use the api key as shared secret, and then use a salt that doesn't change to prevent rainbow table attacks. The username field seems like a good place to put the nonce too, since it is part of the auth. So now you have a clean call like this:
nonce = generate_secure_password(length: 16);
one_time_key = nonce + '-' + sha1(nonce+salt+shared_key);
url = username:one_time_key#myhost.com/api/call
It is true that this is a bit laborious. This is because you aren't using a protocol level solution (like SSL). So it might be a good idea to provide some kind of SDK to users so at least they don't have to go through it themselves. If you need to do it this way, I find the security level appropriate (just-right-kill).
Secure secret storage
It depends who you are trying to thwart. If you are preventing people with access to the user's phone from using your REST service in the user's name, then it would be a good idea to find some kind of keyring API on the target OS and have the SDK (or the implementor) store the key there. If that's not possible, you can at least make it a bit harder to get the secret by encrypting it, and storing the encrypted data and the encryption key in seperate places.
If you are trying to keep other software vendors from getting your API key to prevent the development of alternate clients, only the encrypt-and-store-seperately approach almost works. This is whitebox crypto, and to date, no one has come up with a truly secure solution to problems of this class. The least you can do is still issue a single key for each user so you can ban abused keys.
(*) EDIT: SSL connections should no longer be considered secure without taking additional steps to verify them.
A pure RESTful API should use the underlying protocol standard features:
For HTTP, the RESTful API should comply with existing HTTP standard headers. Adding a new HTTP header violates the REST principles. Do not re-invent the wheel, use all the standard features in HTTP/1.1 standards - including status response codes, headers, and so on. RESTFul web services should leverage and rely upon the HTTP standards.
RESTful services MUST be STATELESS. Any tricks, such as token based authentication that attempts to remember the state of previous REST requests on the server violates the REST principles. Again, this is a MUST; that is, if you web server saves any request/response context related information on the server in attempt to establish any sort of session on the server, then your web service is NOT Stateless. And if it is NOT stateless it is NOT RESTFul.
Bottom-line: For authentication/authorization purposes you should use HTTP standard authorization header. That is, you should add the HTTP authorization / authentication header in each subsequent request that needs to be authenticated. The REST API should follow the HTTP Authentication Scheme standards.The specifics of how this header should be formatted are defined in the RFC 2616 HTTP 1.1 standards – section 14.8 Authorization of RFC 2616, and in the RFC 2617 HTTP Authentication: Basic and Digest Access Authentication.
I have developed a RESTful service for the Cisco Prime Performance Manager application. Search Google for the REST API document that I wrote for that application for more details about RESTFul API compliance here. In that implementation, I have chosen to use HTTP "Basic" Authorization scheme. - check out version 1.5 or above of that REST API document, and search for authorization in the document.
In the web a stateful protocol is based on having a temporary token that is exchanged between a browser and a server (via cookie header or URI rewriting) on every request. That token is usually created on the server end, and it is a piece of opaque data that has a certain time-to-live, and it has the sole purpose of identifying a specific web user agent. That is, the token is temporary, and becomes a STATE that the web server has to maintain on behalf of a client user agent during the duration of that conversation. Therefore, the communication using a token in this way is STATEFUL. And if the conversation between client and server is STATEFUL it is not RESTful.
The username/password (sent on the Authorization header) is usually persisted on the database with the intent of identifying a user. Sometimes the user could mean another application; however, the username/password is NEVER intended to identify a specific web client user agent. The conversation between a web agent and server based on using the username/password in the Authorization header (following the HTTP Basic Authorization) is STATELESS because the web server front-end is not creating or maintaining any STATE information whatsoever on behalf of a specific web client user agent. And based on my understanding of REST, the protocol states clearly that the conversation between clients and server should be STATELESS. Therefore, if we want to have a true RESTful service we should use username/password (Refer to RFC mentioned in my previous post) in the Authorization header for every single call, NOT a sension kind of token (e.g. Session tokens created in web servers, OAuth tokens created in authorization servers, and so on).
I understand that several called REST providers are using tokens like OAuth1 or OAuth2 accept-tokens to be be passed as "Authorization: Bearer " in HTTP headers. However, it appears to me that using those tokens for RESTful services would violate the true STATELESS meaning that REST embraces; because those tokens are temporary piece of data created/maintained on the server side to identify a specific web client user agent for the valid duration of a that web client/server conversation. Therefore, any service that is using those OAuth1/2 tokens should not be called REST if we want to stick to the TRUE meaning of a STATELESS protocol.
Rubens
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.