Genius DM

IdentityServer > Basic 본문

Architecture

IdentityServer > Basic

Damon Jung 2018. 7. 26. 22:25

IdentityServer Basic

IdentityServer 와 관련된 용어와, 특히 OAuth2 Flow 에 대해서 알아보자.




IdentityServer?

OpenID 스펙을 구현한 .NET/Katana 기반 프레임워크. OP ( OpenID Connect Provider 라고도 부름 )



Protocol Terms

    • OIDC ( OpenID Connect )
      OAuth2 기반 Security Layer ( IETF 스펙 아님 )

    • OAuth2
      Access Control 을 위한 RFC 프로토콜 ( IETF 스펙 )

    • OP ( OpenID Connect Provider )
      STS ( Security Token Service ), Identity Provider, Authorization Server 모두 같은 것을 지칭한다고 봐도 무방하다.
      일반적으로 아래 5가지 서비스를 제공하는 것을 OP 라고 부른다.

      1. 로컬 계정 저장소에서 유저를 인증하거나 외부 OP 를 통해서 인증한다.
      2. 세션 관리와 SSO ( Single Sign On ) 을 지원한다.
      3. 클라이언트를 관리하고 인증한다.
      4. 클라이언트에게 Identity Token 과 Access Token 을 발급한다.
      5. 토큰 자체를 검증한다.

    • Client
      유저를 검증하거나 리소스에 접근하기 위해 OP 에게 토큰을 요청하는 주체. 반드시 사전에 OP Client 리스트에 등록되어 있어야 한다.
      Web application, native mobile app, destop app, SPA app, Server process 등 OP 서버에 request 를 날릴 수 있는 모든 것을 의미함.

    • User
      등록된 클라이언트를 사용하는 End user 를 지칭한다.

    • Scope
      Identity Scope 와 Resource Scope 로 나눈다. 클라이언트가 접근하길 원하는 리소스에 대한 식별자이며, 검증 과정이나 토큰 요청 중 OP 서버로 전달된다.

    • Scope > Identity Scope
      Claims 로 불리는 Identity 정보를 요청한다. 이름, 이메일 주소 등이 OpenID Connect 스펙에 맞게 IdentityServer 에 모델링 되어 있다.

    • Scope > Resource Scope
      Resource Server 로 불리는, 리소스를 지니고 있는 서버에게 제공하는 API 에 대한 식별자이다. Calendar 라는 Resource Scope 를 지니고 있다면, 리소스 서버에 해당 스코프를 보여주고 Calendar API 를 사용할 수 있음을 증명하여 Calendar 리소스 ( eg. 기념일 데이터 ) 를 획득할 수 있는 것이다.

    • Authentication / Token Request
      클라이언트는 OP 서버에게 토큰을 요청하는데, Scope 에 따라서 Identity Token 이나 Access Token 을 넘겨주며, Flow 타입에 따라 두 가지 모두를 제공하기도 한다.

    • Identity Token
      Authentication 의 결과 즉 인증 결과 값이라고 생각하면 된다. 무조건 sub 라고 불리는 Subject Claim 라는 식별자 정보를 포함한다. OP 에서 어떤 방식으로 인증되었는지에 대한 추가 정보를 포함할 수 있다.

    • Access Token
      리소스에 접근하기 위한 토큰. 클라이언트는 Access Token 을 요청한 후 제공받은 토큰을 리소스 서버로 넘긴다. Access Token 는 클라이언트 정보를 포함하며, 유저 정보를 같이 포함할 수도 있다. 리소스 서버에서는 API 수행 전 자신의 리소스에 접근할 권한이 있는지 여부를 토큰 정보를 통해 식별한다

    • Subject
      Claim 의 Primary Key 개념이다. Claim 내용이 동일한 N 명이 있을 수 있기 때문에 ( e.g 동명이인 ) , Claim 마다 고유한 번호가 부여된다. 프로토콜에서 “sub” 로 주고 받으며, 이 값의 존재 여부에 따라 Machine vs Human Involved 를 구분할 수 있게 된다. OpenID 에서는 Subject Type 을 지정할 수 있는 것 같음. Default 는 Public 임



Relevant Terms

    • Claim
      System.Security.Claims namespace 에 포함된 개체.
      공항의 Baggage Claim Are 처럼, 의미 그대로 Claim ( 내꺼야! ) 을 나타내는 개체이다.
      "내꺼야" 를 대변하는 객체 답게 Claim 은 발급자, 권한, 역할 등을 속성으로 지니고 있다.
      더 자세한 정보를 입력하기 위해 Dictionary 에 추가적인 속성을 부여할 수도 있다.

    • Bearer Token
      Bearer Bonds 는 무기명 채권을 의미하는데, Bearer Token 도 말 그대로 무기명 ( 이름이 명시되지 않은 ) 토큰을 의미한다.
      호텔에서 2001호 Room Key 를 습득하면, 해당 키를 가지고 누구나 2001호의 문을 열 수 있듯,
      Bearer Token 을 지니고 있는 사람은, 해당 토큰으로 접근할 수 있는 특정 서비스를 이용할 수 있다.


    • Refresh Token
      새로운 Access Token 을 발급받기 위해 사용된다. 일반적으로 Refresh Token 은 long-lived 이다. 반면에 Access Token 은 short-lived.
      따라서 길게 유지되는 세션에서 Access Token 의 유효기간이 지났을 때, Refresh Token 을 가지고 다시 새로운 Access Token 을 발급받을 수 있게 된다. Refresh Token 이 만료되면, 유저는 다시 인증 절차를 거쳐야 할 것이다.


    • JWT
      JSON Web Token 의 약자. IETF RFC7519 스펙이다.
      Claim 정보를 안전하게 주고받게 된다. ( Access token & Identity Token )
      IdentityServer 에서 Access Token 을 해싱된 string 으로 받을지, JWT 로 받을지 결정할 수 있다.


    • Redirection URI
      아래 Flow 다이어그램에서 볼 수 있는 항목이다. Client 개체의 한 속성을 의미한다. Client 는 Authorization Code 나 Access Token 을 받을 주소를 지정할 수 있는데, 그 주소가 Redirection URI 이다. 당연히 Client 는 OP 서버에 미리 등록되어 있어야 하므로, 등록 시점에 Redirection URI 가 정해져 있어야 한다. 만약 Redirection URI 가 OP 서버에 등록된 것과 다른 주소로 지정된 경우, Client validation 단계에서 인증이 불가능하여 Authorization Code 나 Access Token 을 발급받을 수 없다.




Why do we use IdentityServer?





    • Browser
      SPA, MVC, Traditional Web app 등의 클라이언트

    • Native app
      Native mobile app, Desktop app 등의 클라이언트

    • Server app
      서버에서 구동되는 프로세스를 포함한 모든 클라이언트

IdentityServe 같은 OP 가 나오기 전까지 위 그림과 같은 흐름에서 1차로 Web app 에 접근할 때 Identity 체크가 필요하고, 2차로 또 다시 Web API 로 접근할 때 다시 한 번 Identity 체크가 필요했다.

Web app 에서 로그인 페이지, 쿠키 처리 등에 대한 개발이 별도로 필요했고, 계정 관리, 등록코드 관리, 또는 SSO 를 도입하는 것 또한 별도의 개발이 필요했다. 그리고 Web app 이나 도메인이 늘어나는 만큼 중복 코드를 계속해서 양산해야 하는 문제가 있었다. 이는 유지보수에서도 치명적이다.


그래서 위와 같이 OP 서버를 도입하여 인증 및 권한 부여 처리를 중앙화하여 수행하는 것이 중요한 것이다.




OAuth?

기존 클라-서버 인증에서는 Client 가 Server에 있는 제한된 리소스에 엑세스 요청을 하고, 이 때 Resource Owner 의 Credentials 를 사용했었다. Third Party 어플리케이션이 이런 제한된 리소스에 접근하게 하려면, Resource Owner는 무조건 자신의 엑세스 정보를 공유해야만 했다. 이런 방식은 아래와 같은 문제를 야기한다.

1. Third Party 어플리케이션은 지속적인 리소스 요청을 위해 리소스 주인의 인증 정보를 보관해야 하고, 보통 평문 패스워드를 그대로 보관한다.
2. 패스워드의 보안 취약점에도 불구하고 패스워드 인증 프로세스를 서버는 무조건 지원해야 된다.
3. Third Party 어플리케이션에 지나치게 많은 권한을 주게 된다. 실제적으로 Resource Owner 와 동일한 권한이기 때문에 기간이나 특정 리소스 그룹에 대한 엑세스 제한이 불가능하다.
4. 리소스 오너는 특정 Third Party 의 권한을 골라서 폐지할 수 없다. 모든 Third Party 의 권한을 철회시켜야 된다.
5. Third Party 중 하나라도 해킹당하면 그대로 끝이다.

그래서 인증 Layer 개념으로 OAuth 가 등장했다.




Flow?




OAuth2 에는 Authorization Code Flow, Implicit Flow, Resource Owner Password Flow, Client Credential Flow 가 존재한다. IdentityServer 에서 Default 는 Implicit 이다. 아무래도 Web app 에서 많이 사용해서 Implicit 으로 지정한 것 같다. 위 도식을 온전하게 이해하려면, 내가 개발하고 있는 환경에서 무엇이 Client 이고 무엇이 UserAgent 이고 무엇이 Resource Owner 인지 정확하게 구분할 수 있어야 한다.





OAuth Flow 를 이해하기 위한 Resource Owner 및 각 Entity 의 개념 정리.

아이폰의 주인 정동민 ( An end user ). 해외 여행하면서 찍은 사진 3만장 ( Resources ). 사진의 주인은 정동민이니까, 정동민이 Resource Owner 가 된다. 이 모든 사진들은 iCloud ( Resource Server ) 에 동기화 되어있다. 이 때 iCloud 에는 패스워드 따위의 인증 정보를 전혀 포함하지 않고, 대신 iCloud 가 갖고 있는 인증 Layer, 즉 OP 서버 ( Authentication Server ) 에서 Access Token 을 발급받아 인증할 뿐이다. Naver Cloud 를 새로 설치해서 Naver Cloud 에도 사진을 동기화 하기로 했다. 이 때 Naver Cloud 는 사진 데이터에 접근하기 위해 iCloud 에 접근 권한이 필요한데, 이 때 Naver Cloud 는 Client 가 된다. Naver Cloud 에서 OP 서버로 요청을 날리는 특정 코드, 프로그램, 프로세스 등은 논리적으로 User Agent 가 된다. 위 전제로 Entity 개념을 잡고 아래 Flow 내용을 보면 더 쉽게 이해할 수 있다.





Flow types

> Authorization Code

Resource Owner 는 오직 Authorization Server 와 인증 절차를 갖기 때문에, Resource Owner 의 기밀 정보가 Client 와 공유될 일이 없다. Authorization Server 는 Resource Owner 에 대한 인증 절차를 마치고, Authorization Code 를 Client 에게 발급한다. OP 서버는 Client 를 인증하고 Access Token 을 Client 에게 곧 바로 전송하는 보안 장점이 있다.




> Implicit

Javascript 를 이용하는 브라우저 클라이언트 앱에 최적화된 암시적 권한 부여 방식이다. Authorization Code 를 발급하는 대신, Client 는 Resource Owner 의 Authorization Grant 결과로 Access Token 을 바로 발급해준다. 암시적인 권한 부여라고 불리는 이유는 Authorization Code 따위가 발급되지 않고 곧 바로 Access Token 을 발급해주기 때문이다.

Access Token 을 발급하는 동안 Authorization Server 는 Client 를 인증하지 않는다. 어떤 경우에는 Client 에게 Access Token 전달할 때 사용한 Redirect URI 를 통해서 Client 를 인증할 수도 있긴 하다. 만약 Resource Owner User Agent 에 접근할 수 있으면 Access Token 은 Resource Owner 나 다른 앱에 노출될 수도 있다. Implicit 은 브라우저 앱 같은 클라이언트에게 빠른 반응성과 효율성을 제공하기 위한 것이기 때문에 ( Access Token 발급 받기 위한 Network round trip 을 줄여주니까 ) 편한 만큼, 보안에 취약할 수 있다. 그림상 F 지점. ( 여기 참고. 10.3 and 10.16 )






> Resource Owner Password

Resource Owner 의 패스워드 인증이다. ( Id, Password ) 패스워드 인증을 통해 권한을 부여하고 Access Token 을 얻는다. 반드시, 반드시 Resource Owner 와 Client 간에 확실한 신뢰관계가 있는 경우에만 사용한다. ( 혹은 Authorization Code 타입을 사용 불가능 한 경우 사용 함 )





> Client Credentials

Client 제어 하의 권한 부여 방식. 즉 Client 가 동시에 Resource Owner 인 경우에 사용할 수 있음. Authorization Server 와 같이 설치하는 App 을 예로들수 있다.




> Authorization Code With Proof Key ( PKCE https://tools.ietf.org/html/rfc7636 )

Authorization Code 탈취에 취약한 Authorization Code Flow 의 보안상 약점을 보완한 것이다.

1. Client 는 code_verifier 를 매 Auth Request 마다 생성한다.
2. code_verifier 를 이용해서 Code Challenge 를 만든다. ( SHA256 or plain )
3. 이 Code Challenge 와 함께 Request 를 날린다.
4. Server 는 이제 해당 code_challenge 와 Authorization Code 를 조합시켜야 된다. Code challenge 가 결국 무슨 클라이언트가 언제, 어디서 요청을 한 것인지, 그리고 그 Code Challenge 로 리턴했을 때 클라이언트가 그것을 해석할 수 있는지, 체크 해주는 것이다.




> Hybrid with proof key

Hybrid 가 implicit + Authorization Code Flow 조합이니까, 여기에 PKCE 개념까지 추가된 것. 즉 간단히 말해 Implicit 에서 Authorization code flow 를 섞어 쓰다가 Authorization code flow 에서 Authorization code 탈취가 걱정되면 이 Flow 를 채택할 수 있는 것이다.






Flow 를 선택하는 일반적인 기준






















IdentityServer Basic

Let's take a look at the glossaries and especially, OAuth2 flows.




IdentityServer?

It's a OpenID framework basing on .NET / Katana framework. We can call it OP ( OpenID Connect Provider )



Protocol Terms

  • OIDC ( OpenID Connect )
    A security layer based on OAuth2 ( which isn't IETF spec )

  • OAuth2
    A RFC protocol for access control ( which is IETF spec )

  • OP ( OpenID Connect Provider )
    STS ( Security Token Service ), Identity Provider, Authorization Server are pretty much the same thing.
    You can call it OP if it provides these kind of services below.

        1. Authenticate users in local account storage or via an external OP.
        2. Support session management and SSO ( Single Sign On ).
        3. Manage and authenticate clients. 
        4. Issue an identity token and an access token to a client.
        5. Validate the token itself.

  • Client
    The one who requests a token from OP to access some resources or validate a user. A client must be registered in the client list of OP beforehand. Anything that's able to send a request can be called a client. ( eg. Web application, native mobile app, destop app, SPA app, Server process, and etc )

  • User
    Means an user using a registered client.

  • Scope
    This can be split into an identity scope and a resource scope. It's an identifier for a client to access a specific resource. This is packed with the request in flight.

  • Scope > Identity Scope
    It represents an identity information called Claims. Name, an email address, and etc are modeled for the OpenID Connect spec.

  • Scope > Resource Scope
    It's an identifier for accessing an API in a resource server. If your app has a calendar resource scope then you can show your scope and prove that you have the right to access the calendar API and get the resources ( eg. birthday event data ).

  • Authentication / Token Request
    Client requests a token from an OP server. According to what scope you have, the OP server returns an identity token or an access token, or sometimes give you the both depending on the flow type.

  • Identity Token
    It's a result for an authentication job. It includes an identifier, a subject claim, which is called "sub". It can further have an information regarding how it could be authenticated.

  • Access Token
    A token for accessing to resources. Probably the most important token in OAuth protocol. This token has a client info in itself, or sometimes some user information together. A resource server can get to see if this client has the right to access this resource or not by sniffing the access token.

  • Subject
    It's a primary key like thing in Claim. Claims can have the same properties each other ( eg. the same name ) so a claim always has a unique id. It's called "sub" in the protocol and you can tell this request includes a human or not by looking at this Subject object. 


Relevant Terms

  • Claim
    It's an object in System.Security.Claims namespace.
    Imagine a baggage claim area in an airport. It is the claim, that you claim that I'm the owner of that bag.
    Since this Claim object represents "That's mine" voice, it has an issuer, a permission, and roles as its attributes.
    You can add more information to a dictionary the object has as a member.

  • Bearer Token
    Bearer bonds mean a bond without any name taken in the paper, the same goes on this bearer token. It's like a plastic hotel key. If you accidently lost the key and then anybody who picked up the card can open the room's door. So if someone has the bearer token, he can access to the specific services the access token can access.


  • Refresh Token
    It's for getting a fresh new access token. Normally a refresh token is a long-lived token whereas an access token is short-lived. So an app that has a long period of session can use a refresh token to get a new access token when the previous access token has expired. If the refresh token has expired, the app would have to reauthenticate itself again.


  • JWT
    It stands for JSON Web Token. It's a RFC7519 spec.
    By JWT, you can transfer a claim info ( identity token or access token ) between two parties in a safe way.
    In IdentityServer you can choose an access token format as hashed string or JWT.


  • Redirection URI
    You're gonna see this at the flow diagrams below. It's one of the properties of Client object. A client can set an URI to receive an authorization code or access token at there and that's the destination the redirection URI represents. Of course the URI should be registered at the time of the client is listed on the OP's client list. If a client app requests with somewhat different redirection URI, then the OP server will fail to validate the client properly, so there's no authorization code and access token for you.




Why do we use IdentityServer?





  • Browser
    SPA, MVC, Traditional Web app clients.

  • Native app
    Native mobile app, Desktop app clients.

  • Server app
    any clients including a process running on a server.

Before IdentityServer came on the way, your application would have to validate the client identity and then when they tried to a web api again, yours painfully had to go through the same validation job again.

Your app needed to develop a login page, cookie management process, account management, registration code management process seperately. And if the app needed to scale out or expanding the domain, you would have to repopulate the same code. It's obviously no good for maintenance for sure.


That's why it's getting important to have a centered server to handle all the authentication and validation jobs.




OAuth?

In the traditional authentication between a client and a server, the client requested restricted resources and it used the resource owner's credential ( eg. id and passwords ) directly. Resource owner had to share the sensitive security information with third parties to let them access the resources. This causes several problems like this.

1. A third party application need to store the resource owner's credentials to request resources whenever it wants. And in most cases, the credential info is saved in plain texts.
2. A server must support a password authentication service even if the password has so many defects in terms of security.
3. Third party applications get to have way more privileges by having the resource owner's credentials. They are basically the same as resource owners, so restricting them by limiting some periods or limiting some specific groups isn't just possible.
4. A resource owner cannot set roles on third parties. He would have to revoke the rights from all of them.
5. Compromise of any third parties will leak everything bound to the credentials.

That's why OAuth protocol was popped out.




Flow?




OAuth2 has several flow types such as Authorization Code Flow, Implicit Flow, Resource Owner Password Flow, Client Credential Flow. The default setting is implicit flow in IdentityServer. Well they decided to set it up so because the majority number of implementations are done on web applications. Understanding these flow diagrams properly, or in a deep level, you should know exactly which part of your systems goes for Client, which one is for UserAgent, Resource owner in your development environment.





Real life example for understanding the entities in the flow.

An iPhone's owner Damon ( An end user ). All the pictures ( Resources ) taken from trips all around the world by the gadget. The owner of the cellphone is Damon, so he is a Resource Owner. The pics have been synchronized on iCloud ( Resource server ). The resource server completely doesn't know anything about the resource owner's credentials, what it does is just ask its own security layer, an OP server ( Authentication Server )
for an access token and use it to validate the credentials. Damon decided to put those pics up on Naver cloud. The Naver cloud needs a permission to access to iCloud ( Resource Server ), so it becomes a Client and requests the OP server for an access token to get those pictures from iCloud. The elements generating requests to the OP including some specific codes, programs, processes, and etc are all User Agent. Keep these in your mind and keep reading further below. These are going to be very handy.





Flow types

> Authorization Code

In this flow, the validation procedure only takes place between a resource owner and an authorization server, therefore you don't have to be worried about leaking resource owner's credentials. Authorization server finishes authenticating job and directly sends the authorization code to the Client right after that. This has some security benefits.




> Implicit

Implicit flow is an optimal grant type for a browser client application using script language like javascript. A client can get an access token and receive it directly from the OP as a result of resource owner's authorization grant. The reason why it's called implicit is because there's no authorization code issuing job for making an access token. ( Resource owner doesn't grant permission in person, it does implicitly )

While issuing an access token, the authorization server doesn't validate the client. In some cases, it performs authentication on the client by looking at the destination URI to which an access token was delivered. Implicit flow expects a fast responsiveness and it is a efficient way to deliver an access token to a browser application ( cuz it takes less network round trip ). So relatively weak security is the trade off for convenient.
The security compromise point is the F in the diagram. ( ref here 10.3 and 10.16 )






> Resource Owner Password

It's resource owner's password authentication. ( typically id and password ) An OP server authenticates a client with the resource owner's password and return an access token. It must be used when there's absolute trust between the resource owner and client.





> Client Credentials

Authorization grant under control of a client. You can use this flow when a client is also a resource owner. Something that will be shipped with an authorization server is the example.




> Authorization Code With Proof Key ( PKCE https://tools.ietf.org/html/rfc7636 )

The authorization code interception attack is the biggest concern in the authorization code flow. PKCE is the backup.

1. A client generates code_verifier everytime it makes a request.
2. A client makes a code challenge using the code_verifier ( SHA256 or plain )
3. A client sends a request to an OP server with this code challenge.
4. The OP Server combines the code challenge and authorization code. The code challenge lets you tract down which clients, when it did, and how it made this request, and The server can see if the client can parse the code challenge accordingly.




> Hybrid with proof key

Hybrid flow is practically a combination of the implicit + authorization code flow. Hybrid with proof key means PKCE concept comes into the hybrid flow group. To put it simply, you can come up with this flow when you are worried about the authorization code interception attack on hybrid flow.






When to use which flows? 


































'Architecture' 카테고리의 다른 글

IdentityServer > Overview of IdentityServer  (0) 2018.07.26
RabbitMQ > Basic Understanding  (0) 2018.07.10
Comments