반응형
반응형

JWT가 사용자 인증에 위험한 이유는 무엇입니까?

JWT의 가장 큰 문제는 토큰 취소 문제입니다. 만료될 때까지 계속 작동하므로 서버에서 쉽게 취소할 방법이 없습니다.

다음은 이를 위험하게 만드는 몇 가지 사용 사례입니다.

  1. 로그아웃은 실제로 로그아웃하지 않습니다!

트윗을 한 후 트위터에서 로그아웃했다고 상상해 보십시오. 서버에서 로그아웃했다고 생각할 수 있지만 그렇지 않습니다. JWT는 자체 포함되어 있고 만료될 때까지 계속 작동하기 때문입니다. 5분 또는 30분 또는 토큰의 일부로 설정된 기간이 될 수 있습니다. 따라서 누군가가 해당 시간 동안 해당 토큰에 액세스할 수 있으면 만료될 때까지 계속 액세스할 수 있습니다.

  1. 사용자를 차단해도 즉시 차단되지는 않습니다.

실제 사용자가 시스템을 사용하는 Twitter 또는 일부 온라인 실시간 게임의 중재자라고 상상해 보십시오. 그리고 중재자로서 누군가가 시스템을 남용하지 못하도록 신속하게 차단하고 싶습니다. 같은 이유로 다시 할 수 없습니다. 차단한 후에도 사용자는 토큰이 만료될 때까지 서버에 계속 액세스할 수 있습니다.

  1. 오래된 데이터가 있을 수 있음

사용자가 관리자이고 더 적은 권한을 가진 일반 사용자로 강등되었다고 상상해 보십시오. 다시 말하지만 이것은 즉시 적용되지 않으며 사용자는 토큰이 만료될 때까지 계속 관리자가 됩니다.

  1. JWT는 종종 암호화되지 않으므로 중간자 공격을 수행하고 JWT를 스니핑할 수 있는 사람은 이제 인증 자격 증명을 갖게 됩니다. MITM 공격은 서버와 클라이언트 간의 연결에서만 완료하면 되므로 더 쉽습니다. 

 

https://redis.com/blog/json-web-tokens-jwt-are-dangerous-for-user-sessions/

 

JSON Web Tokens (JWT) are Dangerous for User Sessions—Here’s a Solution | Redis

Learn why JSON Web Token (JWT), although popular, is dangerous and also view a proposed battle-tested solution.

redis.com

 

반응형
반응형

https://jwt.io/

https://brunch.co.kr/@jinyoungchoi95/1

 

JWT(Json Web Token)은 위와 같은 일련의 과정 속에서 나타난 하나의 인터넷 표준 인증 방식입니다. 말 그대로 인증에 필요한 정보들을 Token에 담아 암호화시켜 사용하는 토큰인 것이죠.

 

JWT는 리소스에 대한 액세스 권한을 부여할 수 있는 자격 증명입니다. 붙여넣는 위치에 주의하세요! 우리는 토큰을 기록하지 않으며 모든 유효성 검사 및 디버깅은 클라이언트 측에서 수행됩니다.

JSON 웹 토큰이란 무엇입니까?

JWT(JSON Web Token)는 당사자 간에 정보를 JSON 개체로 안전하게 전송하기 위한 간결하고 자체 포함된 방법을 정의하는 개방형 표준( RFC 7519 )입니다. 이 정보는 디지털 서명되어 있으므로 확인하고 신뢰할 수 있습니다. JWT는 비밀( HMAC 알고리즘 사용)을 사용하거나 RSA 또는 ECDSA 를 사용하는 공개/개인 키 쌍을 사용하여 서명할 수 있습니다 .

JWT를 암호화하여 당사자 간의 비밀도 제공할 수 있지만 서명 된 토큰 에 중점을 둘 것입니다 . 서명된 토큰은 그 안에 포함된 클레임의 무결성 을 확인할 수 있는 반면 암호화된 토큰 은 이러한 클레임을 다른 당사자로부터 숨길 수 있습니다. 공개/개인 키 쌍을 사용하여 토큰에 서명할 때 서명은 개인 키를 보유하고 있는 당사자만 서명했음을 증명합니다.

JSON 웹 토큰은 언제 사용해야 합니까?

다음은 JSON 웹 토큰이 유용한 몇 가지 시나리오입니다.

  • 권한 부여 : JWT를 사용하는 가장 일반적인 시나리오입니다. 사용자가 로그인하면 각 후속 요청에 JWT가 포함되어 사용자가 해당 토큰으로 허용되는 경로, 서비스 및 리소스에 액세스할 수 있습니다. 싱글 사인온은 오버헤드가 적고 여러 도메인에서 쉽게 사용할 수 있기 때문에 오늘날 JWT를 널리 사용하는 기능입니다.
  • 정보 교환 : JSON 웹 토큰은 당사자 간에 정보를 안전하게 전송하는 좋은 방법입니다. 예를 들어 공개/개인 키 쌍을 사용하여 JWT에 서명할 수 있기 때문에 발신자가 누구인지 확인할 수 있습니다. 또한 헤더와 페이로드를 사용하여 서명을 계산하므로 콘텐츠가 변조되지 않았는지 확인할 수도 있습니다.

JSON 웹 토큰 구조는 무엇입니까?

간결한 형태의 JSON 웹 토큰은 점( .)으로 구분된 세 부분으로 구성되며 다음과 같습니다.

  • 헤더
  • 유효 탑재량
  • 서명

따라서 JWT는 일반적으로 다음과 같습니다.

xxxxx.yyyyy.zzzzz

다른 부분을 분해해 봅시다.

헤더

헤더 는 일반적으로 JWT인 토큰 유형과 HMAC SHA256 또는 RSA와 같이 사용 중인 서명 알고리즘의 두 부분으로 구성됩니다.

예를 들어:

{
  "alg": "HS256",
  "typ": "JWT"
}

그런 다음 이 JSON은 JWT의 첫 번째 부분을 형성하도록 인코딩된 Base64Url 입니다.

유효 탑재량

토큰의 두 번째 부분은 클레임을 포함하는 페이로드입니다. 클레임은 엔터티(일반적으로 사용자) 및 추가 데이터에 대한 설명입니다. 클레임에는 등록 , 공개  비공개 클레임 의 세 가지 유형이 있습니다 .

  • 등록된 클레임 : 필수는 아니지만 유용하고 상호 운용 가능한 클레임 집합을 제공하기 위해 권장되는 미리 정의된 클레임 집합입니다. 그 중 일부는 iss (발급자), exp (만료 시간), sub (제목), aud (대상) 및 기타 입니다.
  • JWT가 압축을 의미하는 한 클레임 이름은 단 3자입니다.
  • 공개 클레임 : JWT를 사용하는 사람들이 마음대로 정의할 수 있습니다. 그러나 충돌을 방지하려면 IANA JSON Web Token Registry 에서 정의하거나 충돌 방지 네임스페이스를 포함하는 URI로 정의해야 합니다.
  • 비공개 클레임 : 사용에 동의하고 등록된 클레임 이나 공개 클레임 이 아닌 당사자 간에 정보를 공유하기 위해 생성된 맞춤 클레임입니다.

페이로드의 예는 다음과 같습니다.

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

그런 다음 페이로드는 Base64Url 로 인코딩되어 JSON 웹 토큰의 두 번째 부분을 형성합니다.

서명된 토큰의 경우 이 정보는 변조로부터 보호되지만 누구나 읽을 수 있습니다. 암호화되지 않은 경우 JWT의 페이로드 또는 헤더 요소에 비밀 정보를 넣지 마십시오.

서명

서명 부분을 생성하려면 인코딩된 헤더, 인코딩된 페이로드, 비밀, 헤더에 지정된 알고리즘을 가져와서 서명해야 합니다.

예를 들어 HMAC SHA256 알고리즘을 사용하려는 경우 서명은 다음과 같은 방식으로 생성됩니다.

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

서명은 메시지가 도중에 변경되지 않았는지 확인하는 데 사용되며 개인 키로 서명된 토큰의 경우 JWT의 보낸 사람이 누구인지 확인할 수도 있습니다.

모두 합치다

출력은 HTML 및 HTTP 환경에서 쉽게 전달할 수 있는 점으로 구분된 3개의 Base64-URL 문자열이며 SAML과 같은 XML 기반 표준과 비교할 때 더 간결합니다.

다음은 이전 헤더와 페이로드가 인코딩되어 있고 비밀로 서명된 JWT를 보여줍니다. 

JWT를 사용하여 이러한 개념을 실행하고 싶다면 jwt.io 디버거 를 사용하여 JWT 를 디코딩, 확인 및 생성할 수 있습니다.

 

JSON 웹 토큰은 어떻게 작동합니까?

인증에서 사용자가 자격 증명을 사용하여 성공적으로 로그인하면 JSON 웹 토큰이 반환됩니다. 토큰은 자격 증명이므로 보안 문제를 방지하기 위해 세심한 주의를 기울여야 합니다. 일반적으로 토큰을 필요 이상으로 오래 보관해서는 안 됩니다.

또한 보안이 취약하기 때문에 민감한 세션 데이터를 브라우저 저장소에 저장해서는 안 됩니다.

사용자가 보호된 경로 또는 리소스에 액세스하려고 할 때마다 사용자 에이전트는 일반적으로 Bearer 스키마 를 사용하여 Authorization 헤더 에서 JWT를 보내야 합니다. 헤더의 내용은 다음과 같아야 합니다.

Authorization: Bearer <token>

이는 특정 경우에 상태 비저장 권한 부여 메커니즘이 될 수 있습니다. 서버의 보호 경로는 Authorization헤더에 유효한 JWT가 있는지 확인하고 JWT가 있는 경우 사용자는 보호된 리소스에 액세스할 수 있습니다. JWT에 필요한 데이터가 포함되어 있으면 특정 작업에 대해 데이터베이스를 쿼리해야 할 필요성이 줄어들 수 있지만 항상 그런 것은 아닙니다.

토큰이 Authorization헤더로 전송되면 CORS(Cross-Origin Resource Sharing)는 쿠키를 사용하지 않으므로 문제가 되지 않습니다.

다음 다이어그램은 JWT를 얻고 API 또는 리소스에 액세스하는 데 사용하는 방법을 보여줍니다.

  1. 애플리케이션 또는 클라이언트가 권한 부여 서버에 권한 부여를 요청합니다. 이것은 다른 권한 부여 흐름 중 하나를 통해 수행됩니다. 예를 들어, 일반적인 OpenID Connect 호환 웹 애플리케이션은 인증 코드 흐름/oauth/authorize 을 사용하여 엔드포인트를 통과합니다 .
  2. 권한이 부여되면 권한 서버는 애플리케이션에 액세스 토큰을 반환합니다.
  3. 애플리케이션은 액세스 토큰을 사용하여 보호된 리소스(예: API)에 액세스합니다.

서명된 토큰을 사용하면 토큰에 포함된 모든 정보가 변경할 수 없는 경우에도 사용자 또는 다른 당사자에게 노출됩니다. 즉, 토큰 안에 비밀 정보를 넣으면 안 됩니다.

JSON 웹 토큰을 사용해야 하는 이유는 무엇입니까?

SWT(Simple Web Tokens)  SAML(Security Assertion Markup Language Tokens )과 비교할 때 JSON 웹 토큰(JWT) 의 이점에 대해 이야기해 보겠습니다 .

JSON은 XML보다 덜 장황하기 때문에 인코딩될 때 크기도 작아져 JWT가 SAML보다 더 간결해집니다. 따라서 JWT는 HTML 및 HTTP 환경에서 전달하기에 좋은 선택입니다.

보안 측면에서 SWT는 HMAC 알고리즘을 사용하는 공유 비밀로만 대칭적으로 서명할 수 있습니다. 그러나 JWT 및 SAML 토큰은 서명을 위해 X.509 인증서 형식의 공개/개인 키 쌍을 사용할 수 있습니다. 모호한 보안 허점을 도입하지 않고 XML 디지털 서명으로 XML에 서명하는 것은 JSON 서명의 단순성과 비교할 때 매우 어렵습니다.

JSON 파서는 객체에 직접 매핑되기 때문에 대부분의 프로그래밍 언어에서 일반적입니다. 반대로 XML에는 자연스러운 문서 대 개체 매핑이 없습니다. 이렇게 하면 SAML 어설션보다 JWT로 작업하기가 더 쉽습니다.

사용에 관해서는 JWT가 인터넷 규모로 사용됩니다. 이는 여러 플랫폼, 특히 모바일에서 JSON 웹 토큰의 클라이언트 측 처리 용이성을 강조합니다.

 인코딩된 JWT와 인코딩된 SAML의 길이 비교

JSON 웹 토큰에 대해 자세히 읽고 이를 사용하여 자체 애플리케이션에서 인증을 시작하려면 Auth0에서 JSON 웹 토큰 랜딩 페이지 로 이동하십시오.

반응형
반응형

SSO(Single Sign-On) 구현을 위한 토큰(Token)의 활용

 


ID/PW 로그인
AccessToken / RefreshToken 생성
AccessToken 소멸하면 RefreshToken으로 인증서버에 AccessToken 재요청
RefreshToken 소멸시 재로그인
 * JWT(JSON Web Token)
 * Token은 Base64 Encoding으로 한다. 토큰에 서명(signiture)부분을 추가해서 서명에 비밀키를 사용. 

 

====================================================================

 

SSO(Single Sign-On)는 무엇인가?

SSO(Single Sign-On)은 한 번의(Single) 로그인 인증(Sign-On)으로 여러 개의 서비스를 추가적인 인증 없이 사용할 수 있는 기술이다. 인증은 하나의 시스템(인증 서버)에서 수행하고, 그 인증 서버가 서비스를 각각 담당하는 서버에 인증 정보를 알려주는 방식이다.




주로 다양한 서비스를 유사한 도메인 혹은 동일한 탑 레벨 도메인(TLD:Top Level Domain)을 서비스하는 엔터프라이즈 서비스 제공자들이 사용자에게 간편한 로그인을 제공하기 위해 사용한다.

예를 들면, 이런 흐름이다.
① www.samsung.com에서 로그인을 하면, 인증 서버 account.samsung.com으로 이동한다.
② account.samsung.com에서 로그인을 성공하면 다시 www.samsung.com으로 돌아온다.
③ 삼성의 다른 서비스에 접속하면, 별도의 추가 로그인 없이 이미 로그인된 상태로 서비스를 즐긴다.

같은 맥락으로 Gmail에 Google 계정으로 로그인을 하면, YouTube나 Google Drive는 별도 로그인 없이 Gmail 로그인에 사용한 구글 계정을 동일하게 사용하는 것도 SSO 기술이다.

SSO를 구현하기 위한 기술 요소는?

SSO를 구현하려 한다면 인증 서버를 준비하고, 이를 다양한 서비스들과 어떻게 인증 관련으로 연계할지 설계해야 한다. 인증 서버에서 인증을 성공적으로 마쳤다는 '증거'를 다른 서비스들이 어떻게 믿게 만들 것인지에 대한 기술적 고민도 필요하다.

기업 내 솔루션에서 SSO는 전통적으로는 모든 사용자(직원)의 인증 정보를 담고 있는 AD(Active Directory)이나 LDAP(Lightweight Directory Access Protocol)을 적용한 솔루션들을 많이 사용해왔다.

SSO의 직접적인 구현을 위해서 여러 가지 방법이 있겠지만 이 글은 인증 토큰(authentication token)을 사용한 SSO 방식에 대한 글이다. 여기서 토큰이란, 최초 인증이 성공한 사용자에게 일종의 증표로 인증 서버가 발급하는 정보다.

예전의 웹 개발에서는 로그인에 성공한 사용자는 웹 서버와 Session을 맺고, SessionID 정보를 쿠키로 받아, 그 쿠키를 로그인의 증표로 사용하였다. 모든 요청 헤더에 SessionID 쿠키를 넣고 웹 서버에 접속을 하면, 웹 서버는 서버에 보관한 Session 정보와 비교하여 유효하게 로그인한 사용자임을 확인하고 콘텐츠를 제공하는 방식이었다. 매번 요청마다 서버가 Session 정보를 확인해야 하는 부담, 서버가 Session 정보를 어디엔가(DB 혹은 Redis) 저장해야 하는 번거로움과 복잡한 구현 방식이 단점이라 할 수 있다.

이에 반해 토큰 방식은 Session 방식과 다르게 서버가 각각 로그인한 사용자의 세션 정보를 따로 보관하지 않는다. 한번 인증 토큰이 클라이언트에게 발급하면, 클라이언트는 추후 요청부터는 그 토큰을 포함하고, 서버는 클라이언트 요청에 포함된 토큰을 그때그때 확인할 뿐이다. 현재 Facebook, YouTube를 비롯한 소셜미디어, 포탈, 이커머스 서비스처럼 가입자 기반의 로그인 인증이 필요한 서비스들이 토큰 인증 방식을 많이 사용하고 있다.

초기에는 SSO가 저변화되면서 많은 서비스들이 SSO 상용 서비스에서 제공하는 SAML(Security Assertion Markup Language) 방식을 사용하였다. SAML은 XML 형태의 마크업으로, 간단한 정보 전달을 위해 많은 태그가 사용되는 비효율성이 있다. 그 이후부터는 SSO에서도 토큰을 사용하고 있다.


토큰을 사용한 SSO 서비스 다이어그램 

SSO에서 세션과 토큰을 어떻게 사용하는지 아래 다이어그램으로 이해해보자.



① 사용자는 Service1에 접속하여 로그인 버튼을 클릭한다.
② Service1은 인증 서비스(idP: Identity provider)로 해당 요청을 Redirect 한다.
③ 인증 서비스는 사용자에게 로그인 화면을 제공한다.
④ 사용자는 ID/PW (혹은 OAUTH2.0)을 입력한다.
⑤ 인증 서비스는 회원 DB와 비교하여 ID/PW가 올바르면 인증 토큰을 발급하며 Service1으로 돌려보낸다.
⑥ Service1은 발급된 토큰을 확인하고, 올바른 토큰이라면 사용자의 로그인 처리를 해준다.
⑦ 사용자는 Service2에 접속한다.
⑧ Service2는 이 사용자의 세션이 아직 유효한지 확인하고 유효하다면, Service2 용도의 토큰을 발급한다.
⑨ Service1은 발급된 토큰을 확인하고, 올바른 토큰이라면 사용자의 로그인 처리를 해준다.


여전히 세션이 필요한 이유는 한번 발급된 토큰만 믿을 수없기도 하고, 일반적으로 토큰은 짧은 유효 시간을 갖는데 비해, 서버에는 세션 정보를 오랫동안 보관하고 그 기간 내에 재접속한 사용자를 지원할 수 있기 때문이다.


유효 시간이 만료된 토큰 사용자가 다시 로그인하는 것은 불편하니, 다음과 같은 방법을 사용한다.

- 인증 서버는 ID/PW를 DB에서 확인하고, 정상 로그인이면 AccessToken과 RefreshToken을 발행한다.
- AccessToken은 exp가 짧다. 만료되면 RefreshToken으로 인증 서버에게 AccessToken를 재요청한다.
- RefreshToken은 exp가 상대적으로 길고, 인증 서버의 세션 정보를 포함한다.
- AccessToken 재요청을 받은 인증 서버는 RefreshToken과 세션 정보를 비교 후 재발급해준다.
- RefreshToken 마저 유효 시간이 지나면, 사용자는 다시 ID/PW 로그인을 해야 한다.

한번 로그인했던 Facebook이나 YouTube의 로그인이 상당 기간 필요 없는 것은 위의 방법을 사용하기 때문이다. 브라우저의 쿠키와 temporary internet folder를 삭제하면 모든 토큰은 삭제된다. 때에 따라 AccessToken을 cookie에 저장하고, cookie는 브라우저가 닫히면 삭제되도록 설정할 수도 있다.


토큰에는 어떤 정보가 있고 어떻게 확인하나?

여기에서의 핵심은 토큰이 어떤 정보를 가지고 있고, 각 Service1과 Service2가 유효한 토큰임을 어떻게 확인할 것인지에 대한 디자인이다. 토큰의 종류는 여러 가지이지만 예제에선 JWT(JSON Web Token)을 사용하였다.



① 인증 서버(idP)와 각 Service 서버들은 사전에 비밀키(private key)를 공유한다.
② ID/PW로 정상적인 인증이 확인되면, 인증 서버는 토큰에 이메일, 이름, 유효 시간 등을 입력하여 발급한다.
③ 토큰을 Base64 Encoding 한다. 암호화가 아닌 인코딩이기 때문에 내용은 누구나 알 수 있다.
④ 토큰에 서명(signature) 부분을 추가하여 위 변조를 방지한다. 서명에 비밀키를 사용한다.
⑤ HTTPS 보안 채널로 토큰 확인을 요청한다. 토큰이 유실되더라도 비밀키가 없는 해커는 내용을 변조할 수 없다.
⑥ Service 서버는 비밀키로 토큰 변조 여부를 확인하고, email 등의 사용자 정보 확인 후, 인증 처리를 해준다.

이 방식의 장점은 가벼운 토큰을 사용하여 인증 처리 작업을 하는 서비스들이 부담을 갖지 않는 구조이고, 비밀키 없이는 토큰을 변조하지 못한다는 보안성이다.

단점은 아무리 HTTPS로 토큰을 보낸다고 하더라도, 중간자 공격 등으로 토큰을 훔친 해커는 토큰을 변조하지 않고 그대로 사용한다면, 로그인한 사용자와 동일하게 보일 수 있다는 보안 취약점이다. 그래서 User-Agent 혹은 IP 주소를 확인한다거나, 추가적인 여러 가지 보완책을 마련해야 한다. Naver 서비스의 경우, AccessToken이 유효하더라도 사용자의 IP 주소가 바뀌면 다시 로그인을 하도록 하는 것도 이런 이유 때문이다.


SSO(Single Sign-On) 구현을 위한 토큰(Token)의 활용 : https://brunch.co.kr/@sangjinkang/36

반응형

+ Recent posts