How to secure Account data in a WebAPI 2 - c#

I'm looking to secure my Web API and I have read a lot about it, but I'm stuck at one point.
I'm using a self build bearer-token generator to use tokens to Authenticate my customers and this works.
But where do I put checks if the user is allowed to modify or view the data.
Example:
I'm a customer of a web shop and I want to view all of my orders(url:"/api/overview").
I click on an order and see that url changes to "api/orders/1". Now the hacker that I am I will just change the "1" to "2" and I will see somebody else order.
Where do I put the security on this, is it in one of the filter layers(Authorization filter?) or is it in the controller?
Or am I missing the hole picture?
Thx, Phoenix

Related

RESTful API Design - same path diffrent roles

I´m currently working on a RESTful API, which has to give access to two diffrent Roles: Admin and User. (I'm wokring with Azure AD App Roles)
My Problem is that I don't understand how I can design the controller logic.
For example I want both (admin and user) to access the endpoint /books, but the admin is allowed to see all books and the user is only allowed to see his books.
What is the best practice to give both the allowed access? I thought of splitting it into two enpoints like this:
/books -> with annotation [Authorize(Roles="Admin")]
/user/{id}/books -> with annotation [Authorize(Roles="User")]
Thanks for helping!
Best regards
I think this sample may be of some help. And if you need sample written by other languages, you can refer to this document to find a suitable one.
And on your case, I think the most important thing is to find out the way to execute the right query and make the query result return to correct user.
So if you set a specific url for each user(I don't think this a good idea to expose user id in the request link), or you hide the user role/id into the token which contained in request header, you all need to write logic code to check which query method need to run. For example, hit domain:port/books with an access token, then your filter catch this request and decode the token to know the user id and user role, and maybe can save them in the session, then your controller may check the value stored in session and choose a right query to get the books information.

How can I protect controller actions in an MVC app that doesn't contain a db or user data?

I'm looking to understand the nitty gritty mechanics of authorization so I can devise a strategy for my situation.
My situation is that I am part of a distributed application. My part is an MVC5 application that basically just consists of a couple of controllers that return single page app views. So hit controller A and get back single page app A. Hit controller B and get single page app B. Etc. This application contains no database or user data. Some other application on a completely different website/server does. I want to ask that other application if a user is valid or have users ask the other application directly themselves and only allow access to my app views if the answer is yes. So, in essence, I want to protect my controllers based on the word of a remote application that contains an exposed api for login/user validation.
It has been suggested to me that token authentication is the way to go. It's a bit daunting with my lack of experience with it, but I've buried myself in some reading and video presentations. Here is my current, weak attempt at summarizing the task based on limited understanding. Please correct as needed:
An access token needs to be generated
Getting an access token is not part of the Account controller, it's part of OWIN middleware
The access token will be sent along with the requests for my contoller actions
My controller actions, decorated with the [Authorize] attribute, will parse the token and do the right thing
Questions:
Q1: Should I generate the token or should the other app - the one with the db and user data?
Q2: My controllers don't know anything about users. That data is in the other app. What specifically are the controllers parsing for under the hood in order to do the right thing? In essence, what specifically tells them, "yes, this request is OK. Return the view."
Q3: I started my project awhile back using a standard MVC5 project template that comes with VS2015 because I figured I'd be handling users/login etc. That turned out not to be the case. Am I going to have to go back and redo this project from scratch because that template doesn't fit this requirement or can I do some surgery on it and continue? For instance, I don't know if that template has all the OWIN stuff I need or maybe has too much extra junk (bloated Account controller, Entity Framework, etc.) to be easily transformed/maintained.
Q4: Is token authorization overkill here? Is there an easier way to keep unauthorized users from accessing my controller actions that makes more sense given the nature of the project?
Any insight would be appreciated.
Update: What I meant in Q2 was, at it's simplest, how does [Authorize] work? Details? I'm guessing I have to tell it how to work. For instance, a silly example to illustrate. If I wanted to tell a controller decorated with [Authorize] to let anyone in who has the username "fred", how and where would I do that? I'm not so much looking for code. I'm thinking conceptually. My app must know something about the tokens the other app (authenticating app) is genenerating. In general terms, what would I add to my MVC app to tell it how to decode those tokens? Where do I add it? Is there one standard place?
I think you are on the right track and are right about the steps you have mentioned. I will answer your questions based on what I understand:
Q1. The other application is the one that needs to authorize and generate a token (whatever be the authorization mechanism they use) and you should receive this token before showing your views. Since the data is coming from the other application , they have to give your controllers access to their data. This is why you need to ask the other application for the token/authorization. With a valid token got from the other application your application can send valid and authorized requests to their data.
Q2. What you can do from your side is to add a check as to whether the request for your action/view is coming from an authorized user. For this, you need to check if this request has a valid token.
Q3. I don't know what you mean by "template" here. But if you need to integrate your controllers to the other solution, you do need to know what the other solution does and what it offers in terns of authorization and of course the data. They should provide your application access to a public api for this purpose.
q4. THis is something the other application needs to do. From what I understand, I think you are only adding a web API to an existing system so I think you need to really know how you can integrate with the other application. They should have clear APIs that are public for you to do this to access their features and data.
Since you have not mentioned if this other application is something like a secure enterprise solution or a Google API (has public API ) it would be difficult to tell exactly what you can expect from the other application.
I think you would need to try JSON web tokens (JWT )
I have not used it myself though . stormpath.com/blog/token-auth-spa –
It is useful for authenticating if a request to your controller. Here is a similar question as you have (I think) and how JWT could solve it How to use JWT in MVC application for authentication and authorization? and https://www.codeproject.com/Articles/876870/Implement-OAuth-JSON-Web-Tokens-Authentication-in
You can override the AuthorizeAttribute like this : https://msdn.microsoft.com/en-us/library/ee707357(v=vs.91).aspx . Your authorization logic of checking for whichever tokens/auth mechanism you decide to can be added to this new action filter. Then add that new attribute to your actions. So if your custom authorization attribute when overriding looks like this:
public class RestrictAccessToAssignedManagers : AuthorizationAttribute
Then your action would have the attribute decoration like this:
[RestrictAccessToAssignedManagers]
public ActionResult ShowallAssignees(int id)
Found a good article which could also be of help - https://blogs.msdn.microsoft.com/martinkearn/2015/03/25/securing-and-securely-calling-web-api-and-authorize/
My answer to your question will be based on:
I want to ask that other application if a user is valid or have users
ask the other application directly themselves and only allow access to
my app views if the answer is yes. So, in essence, I want to protect
my controllers based on the word of a remote application that contains
an exposed api for login/user validation.
Yes, to my humble opinion, oauth token-based approach is overkill for your need. Sometimes, keeping things simple (and stupid?) is best.
Since you are part of a distributed application, I suppose you can (literally) talk to the team in charge of the "other application/website" where requests that hit your controllers will be coming from.
So, I will skip your questions 1, 2, 3 and 4, which are oriented towards the token-based oauth approach, and suggest a rather different, "simplistic" and faster approach, which is the following:
For clarity purpose, let's call the other application "RemoteApp", and your application "MyApp", or "The other team" and "You", respectively.
-Step 1: You (MyApp) exchange a symmetric secret key with the other team (RemoteApp);
-Step 2: MyApp and RemoteApp agree on the algorithm that will be used to hash data that will be posted to MyApp when a user from RemoteApp requests a page on MyApp. Here, you can, for instance, use MD5 or SHA256 algorithms, which are well documented in MSDN and pretty easy to implement in C#;
Step 3: MyApp tells RemoteApp what its needs to be part of the posted data to validate/authenticate the request.
Here is an example:
Step 1: BSRabEhs54H12Czrq5Mn= (just a random secret key. You can choose/create your own);
Step 2: MD5 (this is the algorithm chosen by the 2 parties)
Step 3: The posted request data could include (at least 3 - 4 parameters or form fields, plus the checksum):
- UserName+RemoteApp fully-qualified domain name + someOther blabla data1 + someOther blabla data2 + checksum
The above information will be concatenated, without space. For instance, let's assume:
UserName = fanthom
RemoteApp fully-qualified domain name = www.remote.com
someOther blabla data1 = myControllerName
someOther blabla data2 = myActionName
The checksum will be generated as follows (function prototype):
generateMD5(string input, string secretKey)
which will be called with the following arguments:
string checkSum = generateMD5("fanthomwww.remote.commyControllerNamemyActionName", "BSRabEhs54H12Czrq5Mn=")
Notice that in the first argument the above 4 parameters have been concatenated, without space, and the second argument is the secret symmetric key.
the above will yield (actual md5 checksum):
checkSum = "ab84234a75430176cd6252d8e5d58137"
Then, RemoteApp will simply have to include the checkSum as an additional parameter or form field.
Finally, upon receiving a request, MyApp will simply have to do the same operation and verify the checkSum. That is, concatenate Request.Form["UserName"]+Request.Form["RemoteApp fully-qualified domain name"]+["someOther blabla data1"]+["someOther blabla data2"],
then use the md5 function with the secret key to verify if the obtained checksum matches the one sent in the request coming from RemoteApp.
If the two match, then the request is authentic. Otherwise, reject the request!
That'all Folks!
I seems you need to implement an OpenID/OAuth2 process.
This way, your apps will be able to utilise single-sign-on (SSO) for all your apps, and all you would have to do is set up your MVC5 app as an OpenID/OAuth2 client.
Take a look into Azure AD B2C which is perfectfor this (I am currently implementing this right now for 3 projects I am working on).
https://www.asp.net/mvc/overview/security/create-an-aspnet-mvc-5-app-with-facebook-and-google-oauth2-and-openid-sign-on
https://azure.microsoft.com/en-us/services/active-directory-b2c/
https://identityserver.io/
So your app is publicly addressable? I can't tell for sure from your description.
Well you only have these issues if a public client is requesting certain page views from you...
Now here's where i'm confused. If it's an external client accessing different parts of your distributed app, ALL the parts have this problem.
Generally the client authenticates itself at one place (say written by Team A), any other subsequent view requests would need to be checked as well (HTTP being connectionless/stateless), including others done by Team A? So your problem would already be solved (because it would be a problem for everyone, and they would have done something using an auth cookie + checking service, use the same checking service...)?
Which leads me to believe that the view requests are internal and not client facing, in which case... why is auth such a big deal?
If you could clarify your scenario around what requests you need to authenticate...
you are on right track. But instead of you implementing OAUTH and OpenIDConnect user third party which does the heavy lifting. One such tool is IdentityServer
https://identityserver.github.io/Documentation/docsv2/
Now answering your question from IdentityServer point of view
An access token needs to be generated -- true
Getting an access token is not part of the Account controller, it's part of OWIN middleware -- yes, for better design
The access token will be sent along with the requests for my contoller actions
My controller actions, decorated with the [Authorize] attribute, will parse the token and do the right thing -- Yes as a part of response header
Questions:
Q1: Should I generate the token or should the other app - the one with the db and user data? The identity server will generate token that you requested.
Q2: My controllers don't know anything about users. That data is in the other app. What specifically are the controllers parsing for under the hood in order to do the right thing? In essence, what specifically tells them, "yes, this request is OK. Return the view. - usually the token is sent back to the identtyServer to check for validity and to get access_token which will check if the user has access rights. if not [Authorize] attribute will throw error message and return
Q3: I started my project awhile back using a standard MVC5 project template that comes with VS2015 because I figured I'd be handling users/login etc. That turned out not to be the case. Am I going to have to go back and redo this project from scratch because that template doesn't fit this requirement or can I do some surgery on it and continue? For instance, I don't know if that template has all the OWIN stuff I need or maybe has too much extra junk (bloated Account controller, Entity Framework, etc.) to be easily transformed/maintained. - Yes u can delete the extra stuffs
Q4: Is token authorization overkill here? Is there an easier way to keep unauthorized users from accessing my controller actions that makes more sense given the nature of the project? -- It is not an over kill. It is the right thing to do for your scenario

C#.net / MVC4 Authorize.net ARB - Subscription needed to register for an account

I am making my first subscription based website in MVC4 / C# / Razor and have created an Authorize.net "Card Not Present" sandbox account for testing.
I have implemented the subscription and it works like a charm. I am redirecting the new subscriber to the "Registration" page using the built in Visual Studio 2013 site that is created by default.
I have saved the SubscriptionId that was returned from Authorize.net and put it into a session variable. I then look at that session on the Registration page to see if it has a value or not.
If there is a value then I allow the user to create an account, otherwise I redirect them to an error page.
Is there anything you think I should add / best practices? I also planned on storing the SubscriptionId with the account when it gets created so I have a way to link up the user to a subscription on Auth.net's website.
Second question: Is there a way to ping Auth.net every time a user logs in so I can check to see if they still have an Active subscription? I would imagine that storing the SubscriptionId would be helpful so that is why I am saving it. I checked the documentation from Authorize.net and didn't see anything... I want to make sure people aren't getting a free ride out of the site...
Thanks in advance for your help / suggestions...
For your second question, if you've stored the subscriptionId in your database, you can use ARBGetSubscriptionStatusRequest to determine if they have an active subscription.
http://developer.authorize.net/api/reference/#recurring-billing-get-subscription-status

remember anonymous users when navigating

I'm trying to make a game with SignalR that can be played between two players.
I have an issue in remembering the anonymus players. At one point, the users are redirected to another page and there I'm lost.
Inspired by Mapping connections , I've been able to solve the authenticated users ( Context.User.Identity.Name ), but what should I do in order to remember the unaunthenticated users when they navigate through website? (from what I know the signalR ConnectionId changes every request).
Generate a cookie for them containing a random GUID and then use that in your connection mapping. Set the value as part of the initial HTML you send the browser. Read the value in your Hub via Context.RequestCookies.

Recognizing a returning visitor in ASP.NET

If an anonymous user on a site returns multiple times in a certain period (lets say three times a week), then I need to suggest the user to log in/register on the site.
I was thinking about keeping this info in a cookie, but is there a better way of doing this? Or maybe a standardized way build in .NET or in a third party library?
For anonymous user the only way is the cookie.
You place an encrypted ID to the cookie and connect that id with your anonymous user on the database.
Google set up advertising cookies to last for 30 days for example
http://www.google.com/privacy/ads/
Google analytic set up up to 2 years
http://code.google.com/apis/analytics/docs/concepts/gaConceptsCookies.html
Google Analytics sets an expiration date of 2 years for unique visitor
tracking. However, if your visitors delete their cookies and revisit
your site, then Google Analytics will set new cookies (including new
unique visitor cookies) for those visitors. While you can configure
the duration of a user session cookie (from the default 30 minutes)
using the _setSessionCookieTimeout() method, you cannot configure the
duration of the unique visitor cookie.
There are a few ways, but they not 100% accurate. That said, a cookie would be adequate for your situation.
One other way is that you can check the and store the visitor's IP address combined with the UserAgent value. This might not be entirely accurate since sometimes a company could have lots of internal users, but using only one public IP address.
Hope this helps. Cheers.
You can also use Javascript and localStorage to display the information.
if (localStorage.getItem('lastVisit')) {
alert('You have been here before!');
} else {
localStorage.setItem('lastVisit', new Date());
}
In short, just use a cookie, there isn't anything wrong with this method. Also, this allows the user to clear such information from their system and is the expected behavior of a website from an end-user, so its good practice.
Also quickly, a 'Visitor' is generally defined as a visit from a unique address (eg. IP Address). So you would want to check the IP to consider it as the same visitor. If they visit the website from a different IP, that would be considered a second visitor which is also expected behavior. You could go a bit further here though, and check the browser and consider that a separate visitor, or other specific information that would be available through all web browsers.
Conclusion, just use a cookie and IP Address, try not to over-complicate it, and definitely don't choose an option that isn't cross-browser if you don't go the cookie/IP route.
Hope this helped.

Categories