ChatGPT解决这个技术问题 Extra ChatGPT

How does OAuth 2 protect against things like replay attacks using the Security Token?

As I understand it, the following chain of events occurs in OAuth 2 in order for Site-A to access User's information from Site-B.

Site-A registers on Site-B, and obtains a Secret and an ID. When User tells Site-A to access Site-B, User is sent to Site-B where they tell Site-B that they would indeed like to give Site-A permissions to specific information. Site-B redirects User back to Site-A, along with an Authorization Code. Site-A then passes that Authorization Code along with its Secret back to Site-B in return for a Security Token. Site-A then makes requests to Site-B on behalf of User by bundling the Security Token along with requests.

How does all of this work in terms of security and encryption, on a high level? How does OAuth 2 protect against things like replay attacks using the Security Token?

oauth2 simply explained here: gist.github.com/mziwisky/10079157
Read the spec: tools.ietf.org/html/rfc6749 You might be surprised how understandable it is. It is also correct which may not be too bad.
This question and its (current) answers all focus on one particular "grant type" in OAuth 2.0 (i.e. code) but there are other grant types defined in OAuth 2.0 that are relevant for different use cases (e.g. non-user related ones).
Oh, why not replace "Site B" with something more readable like "IdProvider Site"?

L
Luis Perez

How OAuth 2.0 works in real life:

I was driving by Olaf's bakery on my way to work when I saw the most delicious donut in the window -- I mean, the thing was dripping chocolatey goodness. So I went inside and demanded "I must have that donut!". He said "sure that will be $30."

Yeah I know, $30 for one donut! It must be delicious! I reached for my wallet when suddenly I heard the chef yell "NO! No donut for you". I asked: why? He said he only accepts bank transfers.

Seriously? Yep, he was serious. I almost walked away right there, but then the donut called out to me: "Eat me, I'm delicious...". Who am I to disobey orders from a donut? I said ok.

He handed me a note with his name on it (the chef, not the donut): "Tell them Olaf sent you". His name was already on the note, so I don't know what the point of saying that was, but ok.

I drove an hour and a half to my bank. I handed the note to the teller; I told her Olaf sent me. She gave me one of those looks, the kind that says, "I can read".

She took my note, asked for my id, asked me how much money was ok to give him. I told her $30 dollars. She did some scribbling and handed me another note. This one had a bunch of numbers on it, I guessed that's how they keep track of the notes.

At that point I'm starving. I rushed out of there, an hour and a half later I was back, standing in front of Olaf with my note extended. He took it, looked it over and said, "I'll be back".

I thought he was getting my donut, but after 30 minutes I started to get suspicious. So I asked the guy behind the counter "Where's Olaf?". He said "He went to get money". "What do you mean?". "He take note to bank".

Huh... so Olaf took the note that the bank gave me and went back to the bank to get money out of my account. Since he had the note the bank gave me, the bank knew he was the guy I was talking about, and because I spoke with the bank they knew to only give him $30.

It must have taken me a long time to figure that out because by the time I looked up, Olaf was standing in front of me finally handing me my donut. Before I left I had to ask, "Olaf, did you always sell donuts this way?". "No, I used to do it different."

Huh. As I was walking back to my car my phone rang. I didn't bother answering, it was probably my job calling to fire me, my boss is such a ***. Besides, I was caught up thinking about the process I just went through.

I mean think about it: I was able to let Olaf take $30 out of my bank account without having to give him my account information. And I didn't have to worry that he would take out too much money because I already told the bank he was only allowed to take $30. And the bank knew he was the right guy because he had the note they gave me to give to Olaf.

Ok, sure I would rather hand him $30 from my pocket. But now that he had that note I could just tell the bank to let him take $30 every week, then I could just show up at the bakery and I didn't have to go to the bank anymore. I could even order the donut by phone if I wanted to.

Of course I'd never do that -- that donut was disgusting.

I wonder if this approach has broader applications. He mentioned this was his second approach, I could call it Olaf 2.0. Anyway I better get home, I gotta start looking for a new job. But not before I get one of those strawberry shakes from that new place across town, I need something to wash away the taste of that donut.


Well, in practice Olaf should be able to take $30 from your account anytime he wants, even if you don't order any donut. Interestingly that's the main goal in the real oauth2.0 scenarios :) This is certainly a great answer, but whoever is reading this please head to the git gist that Paolo mentioned in his comment of the question (gist.github.com/mziwisky/10079157). A good complementary read to make the concept crystal clear.
Great answer but 2 points to raise: 1. As @Samiron pointed out, Olaf would be able to take 30$ anytime he wants. 2. In a real OAuth2.0 scenario, Olaf won't be able to serve the donut before taking money out of the bank. While in this example, he could've kept the cheque and simply handed Luis his well-earned donut. So if we alter the example to make it that I authorize Olaf to get dough from some third party that I know, then it would make more sense as Olaf would have to get the dough before he starts baking the donut (assuming the lonely donut Olaf had was for display purpose only!).
ticker23, the donut story unfortunately beats your technical correction - I was sold on the story when I read it. It was written by Homer Simpson.
@Prageeth Olaf always carries the note to and from the bank in a secure box that leaks ink if tampered with, it would take many lifetimes to restore the note. The bank also takes customers fingerprints on their first visit, if Olaf loses his fingers in a baking accident then he'll have to ask Luis to setup the bank transfer again, and the bank will have to identify Olaf by his Breaking Bread tattoo next time.
I love cute answers as much as the next person, and when their cuteness helps make the answer more accessible that's awesome ... but at the end of the day Stack Overflow is about educating people, and this cute story doesn't do that. To even understand the doughnut analogy you have to already understand how OAuth2 works, but the whole point of the answer was supposed to be to explain precisely that. Please consider editing this (top) answer to actually explain the concepts, not just reference them obliquely at the end ... even if that comes at the cost of a joke or two.
P
PeterUstinox

Based on what I've read, this is how it all works:

The general flow outlined in the question is correct. In step 2, User X is authenticated, and is also authorizing Site A's access to User X's information on Site B. In step 4, the site passes its Secret back to Site B, authenticating itself, as well as the Authorization Code, indicating what it's asking for (User X's access token).

Overall, OAuth 2 actually is a very simple security model, and encryption never comes directly into play. Instead, both the Secret and the Security Token are essentially passwords, and the whole thing is secured only by the security of the https connection.

OAuth 2 has no protection against replay attacks of the Security Token or the Secret. Instead, it relies entirely on Site B being responsible with these items and not letting them get out, and on them being sent over https while in transit (https will protect URL parameters).

The purpose of the Authorization Code step is simply convenience, and the Authorization Code is not especially sensitive on its own. It provides a common identifier for User X's access token for Site A when asking Site B for User X's access token. Just User X's user id on Site B would not have worked, because there could be many outstanding access tokens waiting to be handed out to different sites at the same time.


You've overlooked an important function of the authorization code. Why not just return the refresh token (what you call the Security Token) immediately, instead of having the extra step of swapping the authorization code for it? Because capturing the refresh token would allow replay attacks, whereas the authorization code can only be used once.
OK, @mauricen, that makes sense.... But couldn't the replay attack happen just as well with the refresh token, since that's what ends up being passed with each request?
The authorization code is passed via the user, so (for example) could be stored as a cookie (see stackoverflow.com/questions/4065657/…). The refresh token passes directly between the two sites, so is much less vulnerable.
Out of curiosity, does OAuth return any unique identifiers for the program to use? For example, I am currently relying on the MAC address for user identification, but with that said, MACs are unreliable/easilySpoofed/etc. I may just scrap the MAC address identification mechanism and go OAuth if it does allow me to uniquely identify users.
Notice in this diagram: tools.ietf.org/html/rfc6749#section-4.1 that the "Secret" is not shown, only the Client Identifier (ID in the question). Why is the Secret important and why is it not included in the RFC? Also in the question there is also the local state which is recommended to be passed in the initial transmission of the Client Id (A), and the redirect back to the client along with the authorization code to protect against XSSF.
r
rogerdpack

OAuth is a protocol with which a 3-party app can access your data stored in another website without your account and password. For a more official definition, refer to the Wiki or specification.

Here is a use case demo:

I login to LinkedIn and want to connect some friends who are in my Gmail contacts. LinkedIn supports this. It will request a secure resource (my gmail contact list) from gmail. So I click this button: A web page pops up, and it shows the Gmail login page, when I enter my account and password: Gmail then shows a consent page where I click "Accept": Now LinkedIn can access my contacts in Gmail:

Below is a flowchart of the example above:

https://i.stack.imgur.com/bt7k0.png

Step 1: LinkedIn requests a token from Gmail's Authorization Server.

Step 2: The Gmail authorization server authenticates the resource owner and shows the user the consent page. (the user needs to login to Gmail if they are not already logged-in)

Step 3: User grants the request for LinkedIn to access the Gmail data.

Step 4: the Gmail authorization server responds back with an access token.

Step 5: LinkedIn calls the Gmail API with this access token.

Step 6: The Gmail resource server returns your contacts if the access token is valid. (The token will be verified by the Gmail resource server)

You can get more from details about OAuth here.


All your images have gone missing. Any chance you can load them to stack.imgur?
How can this be correct? Isn't this process initiated by by the user sitting in front of the brower, not LinkedIn. But you have that as step 3. This is what I don't get.
The easiest explanation. Thanks, I'll never buy donuts again
4th step linkedin returns with an authorization token. This has to be supplied in the 5th step, where we will get an access token and a refresh token which could be used further for protected resources.
@amesh Thanks,you're right, that's the authorization code flow, here I just stated in simplified way to show the basic idea of OAuth 2.
C
Community

Figure 1, lifted from RFC6750:

     +--------+                               +---------------+
     |        |--(A)- Authorization Request ->|   Resource    |
     |        |                               |     Owner     |
     |        |<-(B)-- Authorization Grant ---|               |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |--(C)-- Authorization Grant -->| Authorization |
     | Client |                               |     Server    |
     |        |<-(D)----- Access Token -------|               |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |--(E)----- Access Token ------>|    Resource   |
     |        |                               |     Server    |
     |        |<-(F)--- Protected Resource ---|               |
     +--------+                               +---------------+

S
Suraj

This is how Oauth 2.0 works, well explained in this article

https://i.stack.imgur.com/Mo2wi.jpg


Can you describe OAUTH2 in terms of not using facebook or other 3rd party but if you use secret key and TOTP tokens with phone app to secure webapp?
Facebook is Authorisation server in this example which issues access token to any client so they can access Facebook APIs. If you want to secure your APIs you need to implement your own Authorisation server. Then you decide what Grant type you want to use to get access token. tell me what exactly you want? will explain.
I am looking at setting up with springboot security. Client (phone) and webapp exchange secret at registration - then use google authenticator to generate time/secret based code to enter during login in addition to password.
does my last comment enlighten you anymore? See my profile for twitter info
you can get client Id and secret at registration. Then phone make a login request with client Id to your webapp(authorization server). web app validate the client id, and send the OTP to phone. Phone makes another request with client secret to webapp to exchange the OTP with access token. phone use this accss token to access the protected resources on webapp. I think this would be the Oauth2 flow for the given scenario. let me know if it helps you.
B
Belfield

This is a gem:

https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2

Very brief summary:

OAuth defines four roles:

Resource Owner Client Resource Server Authorization Server

You (Resource Owner) have a mobile phone. You have several different email accounts, but you want all your email accounts in one app, so you don't need to keep switching. So your GMail (Client) asks for access (via Yahoo's Authorization Server) to your Yahoo emails (Resource Server) so you can read both emails on your GMail application.

The reason OAuth exists is because it is unsecure for GMail to store your Yahoo username and password.

https://i.stack.imgur.com/6CMie.png


C
Community

The other answer is very detailed and addresses the bulk of the questions raised by the OP.

To elaborate, and specifically to address the OP's question of "How does OAuth 2 protect against things like replay attacks using the Security Token?", there are two additional protections in the official recommendations for implementing OAuth 2:

Tokens will usually have a short expiration period (https://www.rfc-editor.org/rfc/rfc6819#section-5.1.5.3):

A short expiration time for tokens is a means of protection against the following threats: replay...

When the token is used by Site A, the recommendation is that it will be presented not as URL parameters but in the Authorization request header field (https://www.rfc-editor.org/rfc/rfc6750):

Clients SHOULD make authenticated requests with a bearer token using the "Authorization" request header field with the "Bearer" HTTP authorization scheme. ... The "application/x-www-form-urlencoded" method SHOULD NOT be used except in application contexts where participating browsers do not have access to the "Authorization" request header field. ... URI Query Parameter... is included to document current use; its use is not recommended, due to its security deficiencies


n
nethsix

Here is perhaps the simplest explanation of how OAuth2 works for all 4 grant types, i.e., 4 different flows where the app can acquire the access token.

Similarity

All grant type flows have 2 parts:

Get access token

Use access token

The 2nd part 'use access token' is the same for all flows

Difference

The 1st part of the flow 'get access token' for each grant type varies.

However, in general the 'get access token' part can be summarized as consisting 5 steps:

Pre-register your app (client) with OAuth provider, e.g., Twitter, etc. to get client id/secret Create a social login button with client id & required scopes/permissions on your page so when clicked user gets redirected to OAuth provider to be authenticated OAuth provider request user to grant permission to your app (client) OAuth provider issues code App (client) acquires access token

Here is a side-by-side diagram comparing how each grant type flow is different based on the 5 steps.

This diagram is from https://blog.oauth.io/introduction-oauth2-flow-diagrams/

https://i.stack.imgur.com/kC8bX.png

Each have different levels of implementation difficulty, security, and uses cases. Depending on your needs and situation, you will have to use one of them. Which to use?

Client Credential: If your app is only serving a single user

Resource Owner Password Crendential: This should be used only as last resort as the user has to hand over his credentials to the app, which means the app can do everything the user can

Authorization Code: The best way to get user authorization

Implicit: If you app is mobile or single-page app

There is more explanation of the choice here: https://blog.oauth.io/choose-oauth2-flow-grant-types-for-app/


f
fallincode

To be honest, I did not find among the answers one that answers the question "How does OAuth 2 protect against things like replay attacks using the Security Token?", which is the main one.

First, the access scheme described by OP only applies to one of the flows provided by OAuth 2.0 - Authorization Code Grant. There are other flows. One of the common features of all flows is that as a result of successful authentication, the client receives an access token.

How can you protect yourself from replay attacks? This is possible (with some reservations), but you need to understand that, firstly, this requires a set of measures (described below), and secondly, you can’t just protect yourself 100% from this type of attack, sometimes you can stop unauthorized access attempts right away , sometimes you can only shorten the duration of such an attack if it occurs.

So what do you need for this:

Use signed JWT as your tokens. Use a very short expiration time for access tokens, 10 minutes is enough in my opinion. Your authorization server must issue refresh tokens, which is generally optional according to the standard. The expiration time of refresh tokens should not be too long, for each situation it should be solved differently, for example, for a website, I would set it a little longer than a normal user session. You can also implement session expiration when the user is idle, but this applies to the application logic and is not provided for by the standard (this is a fairly simple mechanism, but it's out of the scope of the question). You must store issued refresh tokens in the authorization server database. However, you don't have to store access token data to take advantage of self-contained JWTs. It is advisable to store data about refresh tokens during the lifetime of the session, that is, until the time when the refresh token expires (in fact, it will not be one token, but a family - more on that below). Take general measures to protect against token/session theft, they are probably well-known, among them are the following: use only a secure connection; if you store tokens on the end user side using cookies, set cookie flags to protect them, more details here; implement protection against cross-site request forgery (CSRF), more details here. (Now the most interesting part begins) Implement refresh token rotation. This means that every time a client uses a refresh token to get a new access token (because the access token has expired), a new refresh token must be issued along with the new access token, and the old refresh token must be invalidated. It could just be a flag in the database indicating that the refresh token is invalid. Each time the authorization server issues a refresh token, it must add to it (among other required/recommended) the following claims: jti with a unique token id and a private claim with any unassigned public name, e.g. fid with unique token family id (within one session). For example, refresh token 1 had jti 3c30a712-247b-4091-b692-8c3e92b83bb2, fid 4eb44450-84e9-4fbc-830e-33935e20f7e6, after issuing refresh token 2 instead of refresh token 1, it might have a new jti f467cf40-8cd7-485e-8711-b5c657832fc6 but will have the same fid 4eb44450-84e9-4fbc-830e-33935e20f7e6. You keep holding the entire refresh token family in the database until the last one, the one that is still valid, becomes invalid, for example, until it expires. *You can do without the fid claim, then you will have to link the entire chain / family of refresh tokens issued within the same session using relational database mechanisms. Implement an absolute expiration time for refresh tokens. Each time, when the authorization server within the same session issues a new refresh token instead of the previous refresh token, the value of its exp claim should not exceed the expiration time of the very first refresh token. For example, if refresh token 1 had a value of 1643384057 for exp claim, then each subsequent refresh token, for example refresh token 5, should also contain the same value 1643384057 in the exp claim. Implement refresh token replay (reuse) detection. Perhaps you have already guessed what to do next. Each time the authorization server receives a request to issue an access token, the authorization server, among other things, must check whether the presented refresh token is one from an existing chain / family and is not marked invalid. If an authorization server receives an invalidated refresh token that is in a family that has a valid (latest) refresh token, it MUST invalidate the most recent refresh token (no valid tokens left) and MUST refuse to issue an access token.

What happens when an attacker steals a token/session and tries to reuse it. There are several scenarios:

The token/session was used by the attacker before, at the request of a legitimate user, the client requested the issuance of new access and refresh tokens. That is, the attacker managed to do it first. Then, at the next request of a legitimate user, the client will send an invalid refresh token to the authorization server (because the attacker made the request earlier and the legitimate user's refresh token was invalidated). The session will be invalidated. The token/session was used by a legitimate user, and the stolen token/session was later used by an attacker. In this case, the same thing will happen - the session will be invalidated, I think this is understandable. It is possible that after the token/session was stolen, the legitimate user did not send any more requests, then the attacker will have access until the absolute expiration of the refresh token (see point 9).

The authorization server cannot know who is a legitimate user and who is an attacker, so in such a situation the last (valid) refresh token is always invalidated, making the session expired / invalid. After that, a legitimate user can verify his identity by entering a password, and an attacker cannot.

Understanding how this works, you should choose values related to token expiration that are relevant to your project.

I recommend that you take a deeper look at the related standards, as well as the OAuth 2.0 Security Best Current Practice. There you will also find the Token Replay Prevention section.


m
mnj

OAuth2, by itself, doesn't protect you against replay attacks. However, there are "extensions" like MTLS or DPoP that can be used. You can find out more at https://marcinjahn.com/technologies/security/oauth2/sender-constraint.html