I've created a new ASP.NET Web API and things are working well. I'm at the point now where I want to secure the API.
I put the [Authorize] attribute above my base controller and it's working properly if I want to make API calls within the ASP.NET application itself.
However, I'm wondering, what's the best practice for an external client that wants to make API calls and get past the authorization? Also, keeping in mind I have custom authentication logic.
How should the client send over credentials? At what point do I process these credentials?
How should I send the client credentials?
The default location to send authentication info, is the authorization header. You can use this for basic authentication but also for other types of authentication (JWT, Bearer, etc.).
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
To add, for example, a basic authentication header to your request you could use the following code on your client:
WebRequest request = (HttpWebRequest)WebRequest.Create("https://yoururl");
request.Headers.Add(HttpRequestHeader.Authorization, "Basic " + Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes("user:password")));
At what point do I process these credentials?
I would write a DelegatingHandler and use it to resolve your 'principal'. You can then set it to the HttpContext.CurrentPrincipal to have it available wherever you need it within the scope of the request. The DelegatingHandler is called before your controllers as you can see in the image below, which makes it ideal for authentication logic.
I would do the same on the client (write a DelegatingHandler or ActionFilterAttribute) to add the authentication header on a default location. Note that DelegatingHandlers are part of the HTTP pipeline and ActionFilterAttributes belong to the MVC pipeline.
Last but not least I would recommend not to write your own custom authentication logic but stick with one off the default frameworks. This can be as easy as using basic authentication over HTTPS and as complicated as implementing OAuth. But I would stay away from do it yourself solutions.
I did like to also invite you to have a look at this answer I gave to a similair question.
Note: ASP.NET Web Api is REST based, so imho you don't want to keep session information at all.
Edit: For an example on how to implement a delegatinghandler that handle basic authentication see: basic http authentication in asp.net web api using message handlers.
Basically you'll want to send the username and password encrypted over the net to your server application, then you can let your API generate a random session ID and keep it in a list (serverside) and send the ID back to the client. Now each time your client sends something to the server, include the ID he received in the packets and so the server can check it each time.
On client disconnection or fixed timeout you can remove the ID from the server list and ask the client to re-authenticate.
Related
I need to create a proxy working as Azure Functions between two APIs. Let's draw a little diagram:
[API A/client] <----> [proxy] <----> [API B/backend]
The backend API has a custom authentication scheme - in order to be authorized to use all endpoints we need to get Session Token first. Then we put it as an Authenticate header - this way calls to other backend's endpoints will not result in some kind of 401 or similar.
Client's view n authentication is not defined yet (meaning that we haven't reached it's techinical team yet) so it's hard to assume anything but let's say it will handle whatever we tell it to do.
How to implement such auth scheme for our proxy? I was thinking about following approach:
client calls proxy's method GetSessionToken anonymously
proxy calls backend's method GetSessionToken anonymously, backend responds with Session Token in in response body
proxy creates a jwt token that keeps the Session Token, proxy attaches this token as a Authentication/Bearer header in response to client
I just started using Azure Functions a few days ago and while I know how to implement this as an usual .net core app, I have no idea how to do it in Azure Functions which are not as sophisticated.
Daniel
Proxies currently don't support extracting some value from response body and adding it to a response header. You might need to do this in a function code or use Azure API Management.
I looked everywhere for an answer about securing my webApi but always i'm pointed to OAuth or openID, but i don't want the user to login or authenticate. This is my problem:
I have a webapi which is called via Javascript to get the data in Json. This data is used in the Html of that page. (deployed on Azure)
Now i don't want someone else to get that data via Javascript or with a simple GET request. Only my html page is allowed to do so.
I'm looking for something to secure my Webapi to be only consumed by the applications i want. If i look to the OAuth and Azure stuff, people always have to login, but i want this page to be public, but only the webapi needs to be secure.
I can't check on IP, because the call is done at client side in the browser.
It is not possible to authenticate and thus secure the API to be used by a specific client (run entirely in the browser - like SPAs) app. You cannot protect the data the app sends to the API. (see for more details Protecting REST API behind SPA against data thiefs)
You could build some modules server side and then use some token based server to server communication if you do not want to introduce users and end user authentication.
Of course it is also a question of how you interpret security.
If it is just that you do not want other web apps to use the data -
CORS policies will do the job. It is unlikely that there will be more
than some isolated cases of users using a browser other than the
popular once which respect CORS.
If it is you do not want data to be mass downloaded you could
implement some client filtering based on IP. This could even be done
on the networking layer so the API do not need to be modified in any
way.
As a suggestion, you can have it secured making sure the request has some headers defined by you. For example, you can set an Authorization header with a token that only you know. You can for example, create a token based on a key that you and the webapi share, encrypt it with the time you are calling the api. The web api receives the request and:
1 - Check if the request has the token it requires;
2 - if it does, it creates a token the same way your page did;
3 - matches its token with the requests token;
If you are calling the webapi via javascript, the method may be exposed. However, it's one idea
Take a look to CORS (Cross Origin Resource Sharing), it may be your solution.
In synthesis you can allow requests to the Api only from some specific websites. Most, nearly all browsers, support it.
This is how you enable and configure it in Web Api 2.
I have an ASP MVC4 web site. Originally, most of the content was served via controllers as one would expect. I have moved the data storage from SQL Server to MongoDB. I have also added a lot of ajax to update data client side, without a full refresh. This is working fine, but my controllers now have lots of methods that take json and return json. I was able to build a Node.js server that hits the database and exposes exactly the same functionality, without lots of going to and from C#.
My javascript client-side is now calling a Node.js REST API, this works great. My 'secure' code (like adding a new user) hits the same REST API from the server side.
My question is this: How can I handle security properly with this? I have three scenarios:
GET api/messages: No need for security, I want to expose my site's messages to anyone who is interested via a Json REST API.
GET api/my/messages: I need to allow access to this only if the user is logged in (it gets the user's messages).
POST api/users: This is a function that should only be called from the server, and nothing else should be able to use it.
As the user is already logging in to my ASP website, how can I use their logged in credentials to authenticate them with my REST service? While the user is logged in, the pages client side will hit it regularly for updates.
Is there any sensible/standard way to do this? The core idea is that the client side code uses a REST API that is at least partially open to the public, and that in fact that API offers all of my business logic - only parts of it (like creating a user) are locked down to super-admins only.
Thanks in advance!
Create two authentication middleware handlers. One you add to all your "my" routes and another which you add to your POST routes.
The "my" authenticator takes the asp.net auth cookie that is present in the request and makes a http call to your asp.net mvc site with it.
You'll need an action which either returns a 401 if the cookie is invalid otherwise it returns some info about that user's permissions perhaps.
If the request into node doesn't have a cookie, return a 401 again.
In addition, to prevent excessive calls to your mvc site to check the cookie, you could use the cookiesession middleware to set a cookie on the client with a flag of authenticated. That will result in 2 cookies for your client, but that shouldn't be an issue. Just make the node one expire before the aspx one.
The POST authenticator middleware can use any shared secret you like between your node and mvc server. e.g. a special header in the request.
If the user is required to login you can use [Authorize] on your controller actions. Autorization will be handled like any other webrequest.
Furthermore you might consider to add a key to your api requests which you can provide in the initial page load. A autorized user will have a GUID which he will sent with the api call. You can check if this key was issued by your app to a valid user.
As you said all the secure calls already go through your MVC server code which in turn calls the Node.js code, am I right? Basically you need a way to block calls to this Node.js from other clients that are not your MVC code.
Thinking out loud, these are the ideas that pop into my mind:
Use SSL only between MVC and Node. You can set up client and server certificates so that the Node code will only respond after authentication (I don't know how Node handles SSL so you will need some documentation here
If you want, the Node server could also check the call origin and so you can filter based on IP and only allow IPs where your MVC code is sitting
Use an encrypted authentication token on the secure methods on the Node code. Again I'm not really a Node expert but I can imagine it has ways of decrypting a token, or you can simply base it on a random number with a common seed... If noone has access to your server code ideally noone should be able to guess this token. Again, SSL will help against traffic sniffing
I am quite sure that people will come up with other ideas. For me, the most basic thing is anyway ensure that the secure methods are only accessible through an SSL connection and on this connection you can exchange all the info (token, passwords, etc.) you desire.
I'm currently developing a web api, with WCF web api, which allows me to write restful apis. One concern I have is security. For this reason I decided to protect my api with the OAuth protocol which works very good. However, the team got to the conclusion that our own applications shouldn't be authorized by oauth, instead they sould be authorized by http basic, meaning that the client application should send username and password.
So I have 2 questions:
How can I set up WCF Web Api to work with SSL, I'm using Web Api preview 6, and the project is a MVC3 application?
I have an operation handler which takes care of the creation of IPrincipal from the client access token, and then injects it into the operation parameters, so I can access the user's info. I would like to have in the same operation handler a condition where I could check if the authorization scheme is OAuth or http basic, and then in the case of http basic extract the user's credentials and authenticate that specific user against my data base, if authentication is successful create an IPrincipal and inject it to the operation parameters. However, as I see it, everytime an application using http basic requests something to the api, I would have to go to the data base and authenticate. So my question is: Am I in the right path, or this could be accomplished in some other way?
Any answers would be appreciate it. Thank you in advanced!
You setup SSL for WCF Web API just like you would any other WCF service exposed over HTTPS. If you are hosted in IIS, then you need to configure a site binding for HTTPS. If you are self hosted, then the configuration is bit more involved. See http://msdn.microsoft.com/en-us/library/ms733768.aspx for all of the details.
To handle basic auth against a custom identity provider you would typically use a custom authz module when hosted in IIS. See [http://custombasicauth.codeplex.com/] for an example of how to do this. If you are self hosted then you can use a custom username passworld validator. See http://msdn.microsoft.com/en-us/library/aa702565.aspx for details.
Yes, I believe you are correct that every request will require authentication unless you establish some sort of session-like semantics.
Hope this helps.
I'm using the Client Application Services for Client (WPF) authentication with ASP.Net membership, which is working just fine. However, on the server I have additional MVC queries that I must authenticate when calling them from the client. When looking at the available Membership.ValidateUser call, I fail to see how this helps me in any way, as I need to validate every single call.
I assume sticking [Authorize] on each MVC call is the first step.
Can I get a security token, or extract a cookie for the CookieContainer, or am I simply misunderstanding something here?
I am assuming you ASP.Net MVC site, WCF services are hosted in same virtual application and ASP.Net compatibility mode is on.
If you are using WPF to authenticate your user by calling a web service do the following
On Server side
Implement code to do authentication
Once authentication is successful
create a form authentication cookie
and add it to response cookie
collection.
On the client side
The client class that you are using
to connect to authentication service
should contain a static CookieContainer class instance.
Once authentication is
successful add the cookie received to
this cookie container and pass it along every subsequent request.
Hence forth all request to ASP.Net MVC application or any service would contain the cookie and the user would get authorize automatically. Check this blog post for sample
Hope this helps.