I've been reading quite a few questions here on SO about securing web api's using api keys, tokens, hmac ect and haven't found the answer I am looking for.
I'm working on a MVC4 web application project with internet and intranet sites, web api and Android/iOS applications.
The Web API is to be used by my applications and nobody else as it will be accessing sensitive data.
What would be the best way of securing this api so only my apps can use it? Something that seems like such a simple request is extremely difficult to get started on.
I've looked at the post here on SO using HMAC and a few others but none of them sounded like they would fit here, more than likely I am just missing something.
Is HMAC the way to go or would client certificates be more appropriate for this situation?
Should I use SSL and some sort of API key?
I know the question is a bit vague, I've been staring at it for over an hour trying to figure out how to word what I am thinking so I figured I would just post it and update if needed... :(
I would be more than happy to provide more details upon request.
Generate a key for each of your apps and have them pass the key in each request as a token. Your server can then verify the key and authenticate the request.
Take a look at the Basic Authentication module from the ASP.NET site. The sample uses 'basic' as the authorization scheme but you can change it use 'token' instead.
private static void OnApplicationAuthenticateRequest(object sender, EventArgs e)
{
var request = HttpContext.Current.Request;
var authHeader = request.Headers["Authorization"];
if (authHeader != null)
{
var authHeaderVal = AuthenticationHeaderValue.Parse(authHeader);
// RFC 2617 sec 1.2, "scheme" name is case-insensitive
if (authHeaderVal.Scheme.Equals("token",
StringComparison.OrdinalIgnoreCase) &&
authHeaderVal.Parameter != null)
{
AuthenticateUser(authHeaderVal.Parameter);
}
}
}
Once you have the Basic Auth module in place you can simply decorate any actions or controllers with the Authorize attribute and it will forward the request to the Basic Auth handlers.
namespace webapi.Controllers
{
[Authorize]
public class SensitiveDataController : ApiController
{
...
}
}
As far as over the wire you MUST use SSL when using basic authentication as your key will be transmitted in plain text.
You can use FormsAuthentication. Encrypt the ticket and ensure machineKey is the same in both the config files. See this and this. This will allow the same user credentials to be shared between web app and api. ASP.NET FAM module will establish the identity in this case.
For api key, look at hawk scheme. It uses shared symmetric key. However, Hawk is feature-complete and until it reaches version 1.0 it is likely to change. Nonetheless, it will give you a good idea of implementing HMAC-based security. I have a .NET implementation here for Hawk. And there is one from Pablo as well. In this case, you will need to write a message handler to establish the identity for the consuming application.
In a general case for a high traffic app, all the above answer have a flaw that many attackers can easily exploit:
With a jail broken iPhone, you can break SSL - not to your server, but when they have your app on their phone, they can at least analyse the packages you send.
The best way to avoid that (in my opinion) is using 'on time passwords' - real on time passwords.
How can you generate these one time passwords?
A1. Get a device_identifier for each device (this could also just be any random number, but you should avoid collisions with other devices' identifiers)
A2. Have an api_key, that you will use for hashing
Now if you want to send a package to your api, you do the following:
B1. Construct your normal package, here is the example of some json payload:
var payload = {"hello":"world"}
B2. Hash your var hashed_payload = hash(payload) using your favourite hashing function
B3. Generate the one time password for this package:
var otp = hash(salt & hashed_payload & device_token & api_key)
Now you have everything you need, to send to the server:
In the headers, you need to send the otp,salt and device_token as well!
On the server, you will do the same steps marked as B1-3 and compare your hashing result with the one provided by the client. After that you have to make sure that you 'ban' this salt for this device_token in order to avoid replay attacks.
This method still has one flaw but requires much more work from attackers:
They can find your api_key in you compiled code.
I'm working on a similar project where I assign unique API keys to each user or client application accessing my API. I'm not a security expert, but I'd recommend that you use SSL and generate unique API keys for both your Android and iOS applications. With SSL, data being transmitted to your API will be encrypted and protected.
Related
I have an app, client side, that uses auth0 for accessing the different API's on the server. But now I want to add another app, a single page app, I'm going to use VueJs, and this app would be open "ideally" w/o a user having to sign in, it's like a demo with reduced functionality, I just want to check that the user is not a robot basically, so I don't expose my API in those cases.
My ideas so far:
- Somehow use recaptcha and auth0 altogether.
- Then have a new server that would validate that the calls are made only to allowed endpoints (this is not of my interest in the question), so that even if somehow the auth is vulnerated it doesn't leave the real server open to all type of calls.
- Pass the call to the server along with the bearer token, just as if I was doing it with my other old client app.
Is this viable? Now I'm forcing the user to validate, this is more a thing about UX (User-experience), but I'd like a way to avoid that. I'm aware that just with auth0 I can't do this see this post from Auth0, so I was expecting a mix between what I mentioned.
EDIT:
I'm sticking to validating in both cases, but I'm still interested to get opinions over this as future references.
At the end, with the very concept of how auth0 works that idea is not possible, so my approach was the following:
Give a temporary authenticated (auth 0) visitor a token which has restricted access level, then pass the request to a new middle server, the idea is to encrypt the real ids so the frontend thinks it's requesting project A123456etc, when indeed it's going to get decrypted in the middle server to project 456y-etc and given a whitelist it will decide to pass the request along with the token to the final server, the final server has measures to reduce xss and Ddos threats.
Anyway, if there's a better resolve to it I will change the accepted answer.
You could do a mix of using recaptcha for the open public, then on the server side analyse the incoming user request (you can already try to get a human made digital fingerprint just to differentiate with a robot-generated one) and the server (more a middle server) makes the call to you API (and this server has limited surface access)
What we normally do in these situations (if I got your issue correctly) is to create two different endpoints, one working with the token and another one receiving the Recaptcha token and validating it with Google servers.
Both endpoints end up calling the same code but this way you can add extra functionality in a layer in the 'public' endpoint to ensure that you are asking only for public features (if that cannot be granted just modifying the interface).
I have to implement a web site (MVC4/Single Page Application + knockout + Web.API) and I've been reading tons of articles and forums but I still can't figure out about some points in security/authentication and the way to go forward when securing the login page and the Web.API.
The site will run totally under SSL. Once the user logs on the first time, he/she will get an email with a link to confirm the register process. Password and a “salt” value will be stored encrypted in database, with no possibility to get password decrypted back. The API will be used just for this application.
I have some questions that I need to answer before to go any further:
Which method will be the best for my application in terms of security: Basic/ SimpleMembership? Any other possibilities?
The object Principal/IPrincipal is to be used just with Basic Authentication?
As far as I know, if I use SimpleMembership, because of the use of cookies, is this not breaking the RESTful paradigm? So if I build a REST Web.API, shouldn't I avoid to use SimpleMembership?
I was checking ThinkTecture.IdentityModel, with tokens. Is this a type of authentication like Basic, or Forms, or Auth, or it's something that can be added to the other authentication types?
Thank you.
Most likely this question will be closed as too localized. Even then, I will put in a few pointers. This is not an answer, but the comments section would be too small for this.
What method and how you authenticate is totally up to your subsystem. There is no one way that will work the best for everyone. A SPA is no different that any other application. You still will be giving access to certain resources based on authentication. That could be APIs, with a custom Authorization attribute, could be a header value, token based, who knows! Whatever you think is best.
I suggest you read more on this to understand how this works.
Use of cookies in no way states that it breaks REST. You will find ton of articles on this specific item itself. Cookies will be passed with your request, just the way you pass any specific information that the server needs in order for it to give you data. If sending cookies breaks REST, then sending parameters to your API should break REST too!
Now, a very common approach (and by no means the ONE AND ALL approach), is the use of a token based system for SPA. The reason though many, the easiest to explain would be that, your services (Web API or whatever) could be hosted separately and your client is working as CORS client. In which case, you authenticate in whatever form you choose, create a secure token and send it back to the client and every resource that needs an authenticated user, is checked against the token. The token will be sent as part of your header with every request. No token would result in a simple 401 (Unauthorized) or a invalid token could result in a 403 (Forbidden).
No one says an SPA needs to be all static HTML, with data binding, it could as well be your MVC site returning partials being loaded (something I have done in the past). As far as working with just HTML and JS (Durandal specifically), there are ways to secure even the client app. Ultimately, lock down the data from the server and route the client to the login screen the moment you receive a 401/403.
If your concern is more in the terms of XSS or request forging, there are ways to prevent that even with just HTML and JS (though not as easy as dropping anti-forgery token with MVC).
My two cents.
If you do "direct" authentication - meaning you can validate the passwords directly - you can use Basic Authentication.
I wrote about it here:
http://leastprivilege.com/2013/04/22/web-api-security-basic-authentication-with-thinktecture-identitymodel-authenticationhandler/
In addition you can consider using session tokens to get rid of the password on the client:
http://leastprivilege.com/2012/06/19/session-token-support-for-asp-net-web-api/
I'm designing a Service Oriented Architecture, and I also do need an authentication service in order to recognize clients and allow them to access resources.
Actually I found two possible solutions:
sign each single request using a pubkey and privatekey
token-based authentication using pubkey and privatekey
I'm not assuming an oauth2 service since it would add too many overhead designing the system for my needs, instead I do prefer to adopt a simpler (but also strong) authentication solution.
So here I come with my AuthenticationService, that can either be queried by the client making the API request (obtaining a token to pass alongside the request) or be queried by each single API endpoint to perform a reverse check of the HMAC that signed the request to see if it matches (checking if the private key used to produce the HMAC was valid).
I can see the latest to be simpler for the final developer performing several operations, but it would also require more checks to validate the token and handle it's expiration...
What potential security issues could the token solution raise that the single-request HMAC doesn't? What do you prefer and, possibly, why?
At the end I finally designed an authentication service based on the same Amazon solution.
It requires users to sign each request using the private key. So the request will send an Authorization header with the value "PUBKEY:SIGNATURE", where the signature is a HMAC composed of any request data (it could be the request body itself) plus a timestamp, to be passed inside the Date header. This implementation is strong enough to avoid MITM and replay attacks.
For more info about this solution here is a great explanation that helped me a lot to understand the real implementation.
Hope this really help someone else in the world facing the same problem.
I'm working on a project that will generate an OAuth querystring in JavaScript, using HTTPS and in internal application, so security is not a major concern at this point (figured I'd mention that up front )
The JavaScript querystring is used to call a C# script on a different server and domain, essentially to pass data from the internal application to the C# application, and allow to verification that a) the query comes from the right source, and b) the query is valid and hasn't expired, etc.
OAuthSimple gives me a signed URL like this:
http://www.myremotesite.com/mycodepath/mycodefile.aspx?firstname=Kevin&lastname=Blount&oauth_consumer_key=ThisIsTheConsumerKey&oauth_nonce=nuOoM&oauth_signature=DAoaSxD5SvVFTTDNSxiTbANzGlc%3D&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1313162452
My question is, one the C# side of things.. what do I do next? I've two thoughts, but I can't work out which I need to explore:
using C# generate a new signed URL and compare the two (or just compare the oauth_signature values)
take the querystring and somehow decrypt/decode it and verify it.
I'm told that DotNetOpenAuth is the standard to use, but I can't figure out my next step using it.
Can I get some advice on what I need to look into, or articles that explain how I should proceed?
Read the instructions on DotNetOpenAuth and make sure you understand it. I haven't used it previously, but have heard good things about it.
The oAuth server will do several steps:
Validate version - Is the client using the correct version of oAuth for you to handle
Validate TimeStamp - All timestamps must be in UTC to avoid Time Zone problems
Validate Nonce - Has it been used previously allowed time range
Validate Signature - Get the private key from the consumer key, compute the signature using the values passed in the parameters and compare to the actual signature.
Once the message has passed all the checks, then the server will return the resource requested by the message
I'm going to be writing the services for an iPhone app being built by a third party vendor.
I'll be using ASP.NET MVC to accept posts and also return JSON formatted data.
My question is, how do you secure it?
Just using an API key perhaps? Would that be enough to ensure that only data from the iPhone apps are allowed to hit the specified services?
I'm sort of struggling with the same concepts myself. I think the first thing is to do HTTPS only, so that it's starting out more secure than not.
Next, it depends on how you're going to do authentication. If all you need is an API key, (to track which entity is accessing the data) that should be fine. If you also want to track user information, you'll need some way to associate that specific API keys can access specific types of records, based on a join somewhere.
I'm looking at doing forms auth on my app, and using an auth cookie. Fortunately ASP.NET on IIS can do a lot of that heavy lifting for you.
Example time: (I'm sure I'll need to add more to this, but while I'm at work it gives something to gnaw on)
Forms auth:
Send a pair (or more) of fields in a form body. This is POST through and through. There's no amount of non-reversible hashing that can make this secure. To secure it you must either always be behind a firewall from all intruding eyes (yeah right) or you must be over HTTPS. Simple enough.
Basic auth:
Send a base64 encoded string of "username:password" over the wire as part of the header. Note that base64 is to secure as a screen door is to a submarine. You do not want it to be unsecured. HTTPS is required.
API key:
This says that an app is supposedly XYZ. This should be private. This has nothing to do with users. Preferably is that at the time that the API key is requested, a public key is shared with the API grantor, allowing the API key to be encoded on transit, thus ensuring that it stays private but still proves the source as who they are. This can get complicated, but because there is an application process and because it won't change from the vendor, this can be done over HTTP. This does not mean per-user, this means per-developing-company-that-uses-your-api.
So what you want to have happen is that for the app accessing your data, that you want to make sure it's an authorized app, you can do negotiation using private keys for signing at runtime. This ensures that you're talking to the app you want to talk to. But remember, this does not mean that the user is who they say they are.
HOWEVER.
What you can do is you can use the API key and the associated public/private keys to encode the username and password information for sending them over the wire using HTTP. This is very similar to how HTTPS works but you're only encrypting the sensitive part of the message.
But to let a user track their information, you're going to have to assign a token based on login based on a user. So let them login, send the data over the wire using the appropriate system, then return some unique identifier that represents the user back to the app. Let the app then send that information every time that you are doing user specific tasks. (generally all the time).
The way you send it over the wire is you tell the client to set a cookie, and all the httpClient implementations I've ever seen know that when they make a request to the server, they send back all cookies the server has ever set that are still valid. It just happens for you. So you set a cookie on your response on the server that contains whatever information you need to communicate with the client by.
HTH, ask me more questions so we can refine this further.
One option would be to use forms authentication and use the authentication cookie. Also, make sure all the service calls are being sent over SSL.