Протокол OpenID Connect стал признанным стандартом аутентификации в Интернет. Например, если ты пользуешься сервисами Microsoft или Google, ты почти точно используешь OpenID Connect. Поэтому разрабатывая своё решение требующее учёта пользователей и их аутентификации OpenID Connect – наилучший выбор. Так давай посмотрим, что же этот протокол собой представляет и что взять для его использования в .NET.
2. Андрей
Чебукин
MCSD
по Windows 8 на C#
F# программист
Преподаватель
КА ШАГ
Эксперт по
Microsoft ALM
Сооснователь
outstaff/outsource
компании
The Secret
Circle
Solutions
КА ШАГ
8. Токены (по типу)
WS-Security tokens, (как SAML tokens)
JWT (JWA, JWK, JWS + JWE = JOSE)
Свои
Прозрачные
Непрозрачные
9. JSON Web Token
compact, URL-safe means of representing
claims to be transferred between two
parties.
JSON Web Algorithms
JSON Web Keys
JSON Web Signature and Encryption
10. Почему не OAuth2
Confused deputy problem
Any specification that uses the authorization
process as a form of delegated end-user
authentication to the client (e.g., third-party sign-
in service) MUST NOT use the implicit flow
without additional security mechanisms that
would enable the client to determine if the access
token was issued for its use (e.g., audience-
restricting the access token).
13. OAuth2 → Open ID Connect
Стандартный набор значений токена
Identity token
Стандартная криптография
Стандартная проверка токенов
Стандартные области действия
23. Код для авторизации
Authorization code flow
Браузер не получает доступа к
токенам
Клиент может быть
аутентифицирован
Безопасно делать обновление
токена
Bearer – наличка
HoK – банковская карта (нужен ПИН)
You can think of bearer tokens like cash. If you find a dollar bill on the ground and present it at a shop, the merchant will happily accept it. She looks at the issuer of the bill, and trusts that authority. The saleswomen doesn’t care that you found it somewhere. Bearer tokens are the same. The API gets the bearer token and accepts the contents of the token because it trusts the issuer (the OAuth server). The API does not know if the client presenting the token really is the one who originally obtained it. This may or may not be a bad thing. Bearer tokens are helpful in some cases, but risky in others. Where some sort of proof that the client is the one to who the token was issued for, HoK tokens should be used.
HoK tokens are like a credit card. If you find my credit card on the street and try to use it at a shop, the merchant will (hopefully) ask for some form of ID or a PIN that unlocks the card. This extra credential assures the merchant that the one presenting the credit card is the one to whom it was issued. If your API requires this sort of proof, you will need HoK key tokens. This profile is still a draft, but you should follow this before doing your own thing.
http://nordicapis.com/api-security-oauth-openid-connect-depth/
JWA cryptographic algorithms and identifiers to be used with JWS, JWE, JWK
JWK JSON data structure that represents a cryptographic key
JWS represents content secured with digital signatures or Message Authentication Codes (MACs) using JSON
JWE represents encrypted content using JSON
https://tools.ietf.org/html/rfc7515
https://tools.ietf.org/html/rfc7516
https://tools.ietf.org/html/rfc7517
https://tools.ietf.org/html/rfc7518
https://en.wikipedia.org/wiki/Confused_deputy_problem
https://tools.ietf.org/html/rfc6749#section-10.16
http://stackoverflow.com/questions/17241771/how-and-why-is-google-oauth-token-validation-performed/17439317#17439317
Since the implicit flow exposes the access token to the end user through the URI fragment, it introduces the possiblity that the access token might be tampered with. A legitimate app (an OAuth client) can become the confused deputy by accepting an access token that was issued to a different (malicious) app, thereby giving an attacker access to a victim's account.
Note: When verifying a token, it is critical to ensure the audience field in the response exactly matches your client_id registered in the APIs Console. This is the mitigation for the confused deputy issue, and it is absolutely vital to perform this step.
As a simplified example, imagine there are two apps: (1) FileStore, a legitimate file storage app, and (2) EvilApp. Both apps use Google's authentication process for client-side apps. Alice is an innocent end user, and her Google user ID is XYZ.
Alice signs into FileStore using Google.
After the auth process, FileStore creates an account for Alice and associates it with Google user ID XYZ.
Alice uploads some files to her FileStore account. So far everything is fine.
Later, Alice signs into EvilApp, which offers games that look kind of fun.
As a result, EvilApp gains an access token that is associated with Google user ID XYZ.
The owner of EvilApp can now construct the redirect URI for FileStore, inserting the access token it was issued for Alice's Google account.
The attacker connects to FileStore, which will take the access token and check with Google to see what user it is for. Google will say that it is user XYZ.
FileStore will give the attacker access to Alice's files because the attacker has an access token for Google user XYZ.
An id_token is for authentication; it is analogous to a driver’s license, a passport, or another form of ID. An access_token is for authorization; it is analogous to car key, a bank card, or a building access card. We use an id_token to prove who we are; we use an access_token to gain access to our stuff (or someone else’s stuff).
https://blogs.msdn.microsoft.com/mvpawardprogram/2016/09/27/using-openid-connect/
One OpenID Connect library which can connect to any arbitrary provider.
https://www.scottbrady91.com/OpenID-Connect/OpenID-Connect-Overview
Тип использованных учётных данных
Имя, фамилия, размер обуви
Authorize endpoint: Found in the OAuth framework, this endpoint performs authentication and authorisation. Think of it as interacting with humans, it performs the login, consent, renders a UI, etc.
Token endpoint: Again from OAuth, this endpoint allows the requester to get an access token, an ID token and optionally a refresh token. If the authorize endpoint is human interaction, this endpoint is machine to machine interaction (it is a web API).
UserInfo endpoint: New to OpenID Connect, this endpoint allows you to make a request using your access token to receive claims about the authenticated end-user. This user information could be included in the identity token, however this can cause bloat especially if we include things like profile pictures.
Session Management: This includes multiple endpoints for log in and log off processes. Log off is something that OAuth never had. Why? Because, as I may have stressed already, it is not an authentication protocol!
Discovery: These endpoints provide metadata about the OpenID Connect provider, allowing applications to automatically configure for that provider. This includes data such as the location of the core endpoints, allowed scopes and public keys.
Client Registration: These endpoints allow a relaying party to register with the OpenID provider, providing it with the necessary profile information (claims) to register and obtaining the information needed to use the provider (e.g. automatically signing up to a new website using your existing Google account).
https://www.scottbrady91.com/OpenID-Connect/OpenID-Connect-Endpoints
The client credentials grant is almost identical to the resource owner password credentials grant, except it's been specifically designed for client-to-server scenarios (no user is involved in this flow): the client application sends a token request containing its credentials and gets back an access token it can use to query its own resources.
Unlike the resource owner password credentials grant, client authentication is not optional when using the client credentials grant and ASOS will always reject unauthenticated token requests, as required by the OAuth2 specification.
This means that you CAN'T use the client credentials grant with public applications like JS, mobile or desktop applications, as they are not able to keep their credentials secret.
http://kevinchalet.com/2016/07/13/creating-your-own-openid-connect-server-with-asos-choosing-the-right-flows/
The client credentials grant is almost identical to the resource owner password credentials grant, except it's been specifically designed for client-to-server scenarios (no user is involved in this flow): the client application sends a token request containing its credentials and gets back an access token it can use to query its own resources.
Unlike the resource owner password credentials grant, client authentication is not optional when using the client credentials grant and ASOS will always reject unauthenticated token requests, as required by the OAuth2 specification.
This means that you CAN'T use the client credentials grant with public applications like JS, mobile or desktop applications, as they are not able to keep their credentials secret.
http://kevinchalet.com/2016/07/13/creating-your-own-openid-connect-server-with-asos-choosing-the-right-flows/
Though not recommended by the OAuth2 specification as it's the only flow where the user password is directly exposed to the client application (which breaks the principle of least privilege), the resource owner password credentials grant is one of the most popular flows.
It is is particularly appreciated by SPA writers as it's trivial to implement in vanilla JavaScript, doesn't involve any redirection or consent form and, unlike interactive flows, doesn't require implementing token validation or cross-site request forgery (XSRF) countermeasures to prevent session fixation attacks.
As recommended by the OAuth2 specification, you SHOULD NEVER use it with third-party applications. If you want to support applications you don't fully trust, consider using an interactive flow instead (e.g authorization code or implicit flow).
http://kevinchalet.com/2016/07/13/creating-your-own-openid-connect-server-with-asos-choosing-the-right-flows/
Though not recommended by the OAuth2 specification as it's the only flow where the user password is directly exposed to the client application (which breaks the principle of least privilege), the resource owner password credentials grant is one of the most popular flows.
It is is particularly appreciated by SPA writers as it's trivial to implement in vanilla JavaScript, doesn't involve any redirection or consent form and, unlike interactive flows, doesn't require implementing token validation or cross-site request forgery (XSRF) countermeasures to prevent session fixation attacks.
As recommended by the OAuth2 specification, you SHOULD NEVER use it with third-party applications. If you want to support applications you don't fully trust, consider using an interactive flow instead (e.g authorization code or implicit flow).
http://kevinchalet.com/2016/07/13/creating-your-own-openid-connect-server-with-asos-choosing-the-right-flows/
The authorization code flow is probably the most complicated flow as it involves both user-agent redirections and backchannel communication. In return, using this flow with server-side applications has a great advantage: the access_token cannot be intercepted by the user agent.
There are basically 2 steps in the authorization code flow: the authorization request/response and the token request/response.
http://kevinchalet.com/2016/07/13/creating-your-own-openid-connect-server-with-asos-choosing-the-right-flows/
The authorization code flow returns an authorization code (like it says on the tin) that can then be exchanged for an ID token and access token. This requires client authentication using a client id and secret to retrieve the tokens from the back end and has the benefit of not exposing tokens to the User Agent. This flow allows for long lived access (through the use of refresh tokens).
Clients using this flow must be able to maintain a secret.
This flow obtains the authorization code from the Authorization Endpoint and all tokens are returned from the token endpoint.
https://www.scottbrady91.com/OpenID-Connect/OpenID-Connect-Flows
In this flow, the client application always initiates the authentication process by generating an authorization request including the mandatory response_type=code parameter, its client_id, its redirect_uri and optionally, a scope and a state parameter that allows flowing custom data and helps mitigate XSRF attacks.
The way the identity provider handles the authorization request is implementation-specific but in most cases, a consent form is displayed to ask the user if he or she agrees to share his/her personal data with the client application.
When the consent is given, the user agent is redirected back to the client application with a unique and short-lived token named authorization code that the client will be able to exchange with an access token by sending a token request.
To prevent XSRF/session fixation attacks, the client application MUST ensure that the state parameter returned by the identity provider corresponds to the original state and stop processing the authorization response if the two values don't match. This is usually done by generating a non-guessable string and a corresponding correlation cookie.
http://kevinchalet.com/2016/07/13/creating-your-own-openid-connect-server-with-asos-choosing-the-right-flows/
In this flow, the client application always initiates the authentication process by generating an authorization request including the mandatory response_type=code parameter, its client_id, its redirect_uri and optionally, a scope and a state parameter that allows flowing custom data and helps mitigate XSRF attacks.
The way the identity provider handles the authorization request is implementation-specific but in most cases, a consent form is displayed to ask the user if he or she agrees to share his/her personal data with the client application.
When the consent is given, the user agent is redirected back to the client application with a unique and short-lived token named authorization code that the client will be able to exchange with an access token by sending a token request.
To prevent XSRF/session fixation attacks, the client application MUST ensure that the state parameter returned by the identity provider corresponds to the original state and stop processing the authorization response if the two values don't match. This is usually done by generating a non-guessable string and a corresponding correlation cookie.
http://kevinchalet.com/2016/07/13/creating-your-own-openid-connect-server-with-asos-choosing-the-right-flows/
Имитовста́вка — средство обеспечения имитозащиты в протоколах аутентификации сообщений с доверяющими друг другу участниками — специальный набор символов, который добавляется к сообщению и предназначен для обеспечения его целостности и аутентификации источника данных.
a short piece of information used to authenticate a message—in other words, to confirm that the message came from the stated sender (its authenticity) and has not been changed in transit (its integrity).
When the client application gets back an authorization code, it must immediately reedem it for an access token by sending a grant_type=authorization_code token request.
To help the identity provider mitigate counterfeit clients attacks, the original redirect_uri must also be sent.
If the client application is a confidential application (i.e an application that has been assigned client credentials), authentication is required.
http://kevinchalet.com/2016/07/13/creating-your-own-openid-connect-server-with-asos-choosing-the-right-flows/
The implicit flow requests tokens without explicit client authentication, instead using the redirect URI to verify the client identity. Because of this, long lived tokens are not allowed. From the middleware's point of view this is the simplest to implement, as it only needs to redirect to the user the location of the OpenID Connect provider.
This flow obtains all of its tokens from the Authorization endpoint.
https://www.scottbrady91.com/OpenID-Connect/OpenID-Connect-Flows
The implicit flow is similar to the authorization code flow, except there's no token request/response step: the access token is directly returned to the client application as part of the authorization response in the URI fragment (or in the request form when using response_mode=form_post).
This flow is inherently less secure than the authorization code flow, but is easier to implement and has been specifically designed for JS applications. Using it with confidential applications is not recommended and authorization servers SHOULD STRONGLY consider rejecting implicit flow requests when the client_id corresponds to a confidential application to prevent downgrade attacks and token leakage.
When using the implicit flow, the client application MUST also ensure that the access token was not issued to another application to prevent confused deputy attacks. With OpenID Connect, this can be done by using response_type=id_token token and checking the aud claim of the JWT identity token, that must correspond or contain the client_id of the client application.
http://kevinchalet.com/2016/07/13/creating-your-own-openid-connect-server-with-asos-choosing-the-right-flows/
The hybrid flow is a combination of aspects from the previous two. This allows the client to make immediate use of an identity token and optionally retrieve an authorization code via one round trip to the authentication server. This can be used for long lived access (again through the use of refresh tokens).
This flow gets an authorization code from the authorization endpoint, with some tokens returned from the authorization endpoint and others from the token endpoint.
https://www.scottbrady91.com/OpenID-Connect/OpenID-Connect-Flows