I've been trying to understand exactly how the antiforgery works. What confuses me are the cookies which are created. To my understanding, you include the antiforgery token in your form and then you validate for that token when a request is made. This way if a third party websites posts to your website, it will be denied.
Now, I'm reading here https://learn.microsoft.com/en-us/aspnet/core/security/anti-request-forgery?view=aspnetcore-2.1 that the antiforgery token gets stored in a cookie, maybe I'm reading this wrong? But why? Isn't the whole point of this not to make this value accessible outside of your website? If I look at my cookies, I can see 3 cookies created with antiforgery in their name.
services.AddAntiforgery(options =>
{
options.CookieDomain = "contoso.com";
options.CookieName = "X-CSRF-TOKEN-COOKIENAME";
options.CookiePath = "Path";
options.FormFieldName = "AntiforgeryFieldname";
options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
options.RequireSsl = false;
options.SuppressXFrameOptionsHeader = false;
});
I did a little test, I created a post form which ended up including anti forgery token and then I tried submitting it and it worked. Then I created another form without the token and then it failed. So to me it seems it only looks for the token passed in the form, then what is the cookie for?
Anti-forgery is a two-part process. When the page is generated, the token is included as part of the form, so that it will be posted along with the rest of your data. The cookie is set, for the client side of things. When the post is made, the client sends the request with the post data (including the token) and it sends the cookie back to the server, which also includes the token. Server-side, the posted token is matched up with the cookie token, and rejected if the two don't match.
This may seem weird since the client is posting both, but the cookie part ensures that the same client that got the page is also the same client sending it back. The goal isn't so much to protect the anti-forgery token, but rather to ensure that the page on your site is the one that's submitted, rather than some scammer's recreated version of your page. Since a third-party would be incapable of setting a cookie for your domain, there's no way they can fake this portion of the check, even if they were able to retrieve a valid token from your page by requesting it and parsing out the token.
From the asp.net core website AntiforgeryOptions.Cookie Property. The cookie part of the CSRF is only necessary when using cookie based authentication.
The cookie used by the antiforgery system is part of a security system that is necessary when using cookie-based authentication.
Related
I'm going to get so many "okay grandpa" comments for this one.
I've read a dozen articles and every SO question I could find on this subject.
I must have been away too long or missed something completely, because I swear that user authentication used to be very simple. I seem to recall built-in methods and a session on the server simply knowing who the user was via a cookie or similar, with the ability to store information "in session". I don't recall even setting up authentication in years past, it was just built-in to new applications.
Instead, the most succinct guide I could find is very involved. I think I need a token authorization/authentication setup because there may be consumers (like apps) who don't have a typical cookie pattern these days. In my head, the token works like a cookie except it's manually held on the user end and passed via header with each request?
To its credit, the guide worked, at least for logging in and correctly utilizing the simple Authorize attribute in controllers. However, User.Identity.Name is always empty, even when User.Identity.IsAuthenticated is true, which is perplexing.
How I think auth is working:
User request hits API with username/password
Service checks the combination, and returns an encrypted JWT to the user
The user sends the JWT back with every request
The server decrypts this JWT to identify the user - this is probably where I'm wrong
So here is where my question comes in:
I need more data about the user, like access to the entire UserModel with every request, but I don't want to go to the database to find it every time. This is where I think there should just be a session object in memory, but that doesn't appear to be the case with token authentication.
TL;DR:
Where do I put user-specific, short-term ("session") information for consumption in future requests where a user is identified with a JWT in the Authorization header instead of a cookie?
Session state isn't right, because it's hard-wired to a cookie
HttpContext.Items aren't right, because it's just for the one request
Cache storage isn't right, because it's not user/session specific. I could potentially create a session-like user-keyed storage here but that seems way, way over-engineered for this.
Basically anything where I'm passing all the data (not just a user identifier) to the client then relying on the client to pass it back seems wrong? But feel free to correct me.
The server decrypts this JWT to identify the user This is probably
where I'm wrong
The JWT token is not encrypted, its signed so you can't alter it. You can open it if you look at jwt.io for example.
Where do I put user-specific, short-term ("session") information for
consumption in future requests where a user is identified with a JWT
in the Authorization header instead of a cookie?
You put it in the principle claims of the token. In the guide you linked it wrote:
var claims = new List<Claim>
{
new Claim(JwtRegisteredClaimNames.NameId, user.UserName)
};
So you add whatever you want to the claims to store it on the token and later you can access this data via:
var claim = _contextAccessor.HttpContext.User?.Claims.FirstOrDefault(d =>
d.Type == ClaimTypes.NameIdentifier);
You also can't use any of these other examples that you listed like HttpContext.Items because those are not signed. If the token is altered in any way the system identifies this and returns a 401
I’m writing a web api that will be called from a background service to fetch some data. After some research I decided to use a Json web token to achieve that but I’m still a bit confused regarding when a new token should be requested.
Let’s say I start up my service, I request a token, the token expires after 15 minutes, then after 20 minutes I make an api call with the expired token. I will get an unauthorized error or something.
My question is: How will the client know when to request a new token? Should it request a new one before every api call? Seems like I’m missing something. Maybe I should make the token permanent and store it in the database?
Thanks
The answer to this is slightly application specific, but the OAuth specification has a mechanism for "refresh tokens", which can be used to grant new "access tokens" (the token typically included on each API request), without having to send the user to the UI authentication process to have them re-authenticate. So, once you request an access token, you will receive a refresh token and an access token. This methodology allows access tokens to be used for much shorter time frames.
This can also be done without refresh tokens, but in those cases the access token timeout would likely be longer, and then you would request that the user re-authenticate through the usual OAuth UI process. Note that even when you do have refresh tokens, the refresh token can also be set to expire, in which would then require a user re-authentication through UI again.
In some API's you just make the API request as usual, and if you get a response that is defined by the API to be one that indicates the access token has expired, you can then issue an API call to refresh the token (or fully request a new one if that is expired, or you the API doesn't have refresh tokens), and then make the original API call again with the new access token.
The API can also have a response that includes the timeout or expiration date/time of the access token as well. Then, the client can avoid sending the initial API call first, and simply send the refresh token call first.
In implementing your API, you could likely use any of these methodologies.
Here's some general discussion on the OAuth spec website, to provide more depth:
https://www.oauth.com/oauth2-servers/making-authenticated-requests/
https://www.oauth.com/oauth2-servers/access-tokens/access-token-lifetime/
https://www.oauth.com/oauth2-servers/access-tokens/refreshing-access-tokens/
And also, here's an example from the Twitter API regarding response codes showing one of the access token expiration techniques (see the "Error Codes" section, under error code 89, which implies the token has expired and you need to get a new one):
https://developer.twitter.com/en/docs/basics/response-codes
Since your client is background service , you can use the Oauth2 Client Credential Flow . Your background service can request an access token using only its client credentials when the client is requesting access to the protected resources under its control.
With this flow , you does't need to care much about the token expires , if client sends an expired token to web api , web api validate the token and create token expires response to your service , your service check the status code/response , directly send a new token request to web api to get new access token , there is no need to use refresh token which uses in other flows .
The fact is that your harness should be prepared to request any token when getting an Unauthorized status code. What I do in test is to check the expiration datetime, if close enough I refresh or get a new token whatever applies to your Auth. Also when getting an unauthorized status code my code does a refresh once and keep a count. If I get another unauthorized code then I return a false or throw an exception after I log the error on the second try. This works fine for me.
I've got all the code working to generate the JWT and I've wired up my ConfigureServices with the proper config code but I'm not seeing the header actually get set.
I assumed that the middleware would do this for you but maybe not, is it up to me to return the token from the login method of my controller and the client to then take it and set the header for subsequent requests?
No it does not.
The way it works is that you send your login credentials to a login server. In most cases its the same but in more secure applications this won't be the case.
The server then authenticates your credentials, creates a JWT token and sends that back to you.
You can then use that JWT in your header when making a request to the application server:
"Authorization":"Bearer xxxxx.yyyyy.zzzzz"
This needs to be done with every call to the server because the point of JWT is that it is stateless, meaning the server does not save the data at all. Instead in reads the JWT token with every call and grants access/functionality based on that.
I want to do token based mechanism where I would be having either SPA or mobile apps supporting multiple clients.
Use case of my web service engine and my application:
My web application: Client will do registration of their application either SPA or mobile apps.They will get client id on registration.Only client id as secret key would be compromised in case of SPA or mobile apps hence I am just providing clientid.
Web service engine: Support multiple client with managing session of each user after login in to respective application of clients.
So let's say there are 2 client who have register their application in to my web application :
Client 1 : MyApp1
Client 2 : MyApp2
Now if MyApp1 have 2 users with John and Stephen and if they login in MyApp1 then i want to manage session for those users with token based mechanism. Now if John and Stephen wants to access protected resource then they can access only through valid accesstoken.
Same goes for MyApp2.
For token based mechanism I have seen lots of question referring to this below article only:
http://bitoftech.net/2014/06/01/token-based-authentication-asp-net-web-api-2-owin-asp-net-identity/
But the only confusion part in above tutorial and in most of the tutorial is after validating user name and password and generating access token. Does above tutorial is storing access token in server side cookie for validating accesstoken when request comes to access protected resource?
I am really confused here. I know accesstoken validation happens inside [Authorize attribute] but I am not getting without storing accesstoken how above tutorial is validating accesstoken.
My thought is like may be when request comes for accessing protected resources access token is encrypted or decrypted based on machine key attribute in webconfig and this is how access token is validated inside [Authorize] attribute but I am just not sure about this.
You can control what information goes inside a token. Look at the SimpleAuthorizationServerProvider class in the article:
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
identity.AddClaim(new Claim("sub", context.UserName));
identity.AddClaim(new Claim("role", "user"));
Use the Claims to store anything you need regarding to the user, their username or roles and this is what happens in the article you referred to.
The token generated already contains that information about the user.
This is taken from the article :
The second method “GrantResourceOwnerCredentials” is responsible to
validate the username and password sent to the authorization server’s
token endpoint, so we’ll use the “AuthRepository” class we created
earlier and call the method “FindUser” to check if the username and
password are valid.
If the credentials are valid we’ll create “ClaimsIdentity” class and
pass the authentication type to it, in our case “bearer token”, then
we’ll add two claims (“sub”,”role”) and those will be included in the
signed token. You can add different claims here but the token size
will increase for sure.
This is why you do not need to store the token anywhere,the token is self contained and everything is stored inside it in an encrypted form. Don't forget that before you add a claim containing the username you have already validated the username and password, so you can guarantee that the token is created correctly for a valid user / password combination. Of course you do not want to store the password inside the token, the whole point of tokens is to avoid doing that. Passing passwords to an API all the time does increase the risk of them being stolen, tokens are much better for this.
Finally, the tokens expire after a time you control, usually they are short lived so even if someone does get their hands on one they will not last long.
If you take care of how you pass the tokens, meaning in the Authorisation Header over an https call then you are as protected as you can be and the headers will be encrypted. The point here is to never issue calls like this over basic http.
The author of the article you referenced is a well respected authority in this particular area and currently a Microsoft MVP and you are basically in good hands. Keep reading his articles, but pay attention to the details.
----------- Clarification related to JWT format --------------
yes the JWT token will contain information related to its issue date and expiry date as well. I have an article of my own on this : https://eidand.com/2015/03/28/authorization-system-with-owin-web-api-json-web-tokens/
Look at the calls which create the token and look at the information returned in the screenshots.
In my example the token contains the actual encrypted token, the token type, seconds it expires in, the audience which is the ClientID, when it was issued and when it expires.
This is just an example of a token, yours will look probably a bit differently but you get the idea I hope. Use Postman to see what's coming back in the token
There are a number of concepts to be understood when it comes to OAuth2, it does require a bit of research and practice.
In short, you request a token with A Basic Authorisation Header, you get the token back and it's telling you what type it is, in my case it's Bearer so that's my next Authorisation Header for any call to a protected resource.
My suggestion is to start small, one step at a time, use Postman to build your calls and understand what's going on. Once you have that knowledge it's much easier to progress. Took me about 6 weeks to wrap my head around all concepts and get something working first time around, but now it takes a couple hours at most. Good luck
The application does not need to store the access token server side, it will only read the user from the token which is passed along.
When the request hits the authentication server, which is attach to the Owin pipeline in the ConfigureOAuth() method,
the HTTP header token is decrypted and the user data from the token is sat to the current user of the context.
This is one of the things that bugged me for a long time
I'm not sure I understand why did you give an example for 2 applications, but the token mechanism is actually simple, but it's kinda black boxed when you use owin and identity
the token is not stored anywhere on the server or the database, authenticating the user on login is done using your logic or usually again black boxed in identity, this involves validating a secured password etc
after this the token is generated (usually using identity) or if you did it manually this will involve securing the token with whatever info you want to store in it
when the user sends a request next time he should pass the token and you will need to decrypt it and validate what's necessary (like expiration time for example), all of this is done behind the scene usually
just a fun note: even if you changed the DB completely the token will still be valid with the user id that doesn't even exist in your new DB! but of course identity automatically invalidates this token when it compares with the securityStamp
We have some web services with OAuth on them.
I am required to run some tests against them, preferably in an automated environment without using a browser.
The problem is logging in.
Without using a browser, and with using DotNetOpenAuth and setting the HttpContext.Current manually, I seem able to do everything and get a request token and a verifier (I use a test username and password).
I believe the next stage is to get an authorising token. Unfortunatly, no matter how I construct the request, I cannot get it to work.
At the moment, using a WebConsumer (DotNetOpenAuth library) and calling consumer.ProcessUserAuthorization() results in an error:
DotNetOpenAuth.OAuth.Messages.AuthorizedTokenRequest message: oauth_verifier
Probably the whole approach is wrong, so any help/advice would be useful.
Thanks.
I would recommend you skip the entire OAuth handshake and authorization step by having a test access token and access token secret that your web service's token manager always includes. Then wiring your test to also have that token pair included in its token manager, and always using that access token when authorizing your outbound calls.
In the end, it was a problem with cookies not being stored properly.
I was losing cookies between the login page (where the user types their username and password), and the authorise page (where the user says it is okay to share details with the third party). The second page was doing an extra check to see if the user was who they say they were (reading a cookie value that the login page was meant to have written).
It was not really an OAuth issue, just something I did not understand in the Authorising page (which has since been removed anyway - c'est la vie).
I then had issues with the domains of the cookies (when the domain starts with a ‘.’). This post helped me:
CookieContainer bug?
I ended up copying cookies from one domain to another.