JWT 토큰의 서버 측 처리를위한 모범 사례 [닫힌]


111

( 이것은 실제로 NodeJS 등에 국한되지 않고 자체 문제이기 때문에이 스레드 에서 생성되었습니다 )

인증을 사용하여 REST API 서버를 구현하고 있으며 사용자가 사용자 이름 / 암호를 사용하여 / login 끝점을 통해 로그인 할 수 있도록 JWT 토큰 처리를 성공적으로 구현했습니다. 그러면 서버 암호에서 JWT 토큰이 생성되어 서버로 반환됩니다. 고객. 그런 다음 토큰은 인증 된 각 API 요청에서 클라이언트에서 서버로 전달되며, 서버 암호는 토큰을 확인하는 데 사용됩니다.

그러나 진정으로 안전한 시스템을 만들기 위해 토큰의 유효성을 검사하는 방법과 정도에 대한 모범 사례를 이해하려고합니다. 토큰을 "검증"하려면 정확히 무엇을해야합니까? 서버 시크릿을 사용하여 서명을 확인할 수있는 것으로 충분합니까? 아니면 서버에 저장된 일부 데이터와 토큰 및 / 또는 토큰 페이로드를 교차 확인해야합니까?

토큰 기반 인증 시스템은 사용자의 암호를 얻는 것보다 토큰을 얻는 것이 동일하거나 더 어려운 경우 각 요청에서 사용자 이름 / 암호를 전달하는 것만 큼 안전합니다. 그러나 내가 본 예에서 토큰을 생성하는 데 필요한 유일한 정보는 사용자 이름과 서버 측 비밀입니다. 이것은 악의적 인 사용자가 서버 비밀에 대한 지식을 1 분 동안 얻는다고 가정하면 이제 모든 사용자 를 대신하여 토큰을 생성 할 수 있으므로 특정 사용자에게만 액세스 할 수있는 것은 아닙니다. 획득했지만 실제로 모든 사용자 계정에 적용됩니까?

이것은 저에게 질문을 던집니다.

1) JWT 토큰 유효성 검사는 토큰 자체의 서명을 확인하는 것으로 제한되어야합니까? 서버 비밀의 무결성에만 의존하거나 별도의 유효성 검사 메커니즘을 동반해야합니까?

  • 어떤 경우에는 / login 끝점을 통해 성공적으로 로그인하면 세션이 설정되는 토큰과 서버 세션을 함께 사용하는 것을 보았습니다. API 요청은 토큰의 유효성을 검사하고 토큰에있는 디코딩 된 데이터를 세션에 저장된 일부 데이터와 비교합니다. 그러나 세션을 사용한다는 것은 쿠키를 사용하는 것을 의미하며 어떤 의미에서는 토큰 기반 접근 방식을 사용하는 목적을 무효화합니다. 또한 특정 클라이언트에 문제를 일으킬 수 있습니다.

  • 공격자가 "유효한"토큰을 생성 할 수 있도록 서버 비밀이 손상 되더라도 / login 엔드 포인트를 통해 생성 된 정확한 토큰 만 보장하기 위해 서버가 현재 사용중인 모든 토큰을 Memcache 등에서 유지하는 것을 상상할 수 있습니다. 받아 들여질 것입니다. 이것이 합리적입니까, 아니면 중복 / 과잉입니까?

2) JWT 서명 검증이 토큰을 검증하는 유일한 수단 인 경우 서버 비밀의 무결성이 중단 점임을 의미합니다. 서버 비밀은 어떻게 관리해야합니까? 환경 변수에서 읽고 배포 된 스택 당 한 번 생성 (무작위 화?) 하시겠습니까? 주기적으로 갱신 또는 순환 (그렇다면 순환 전에 생성되었지만 순환 후에 유효성을 검사해야하는 기존 유효한 토큰을 처리하는 방법, 서버가 주어진 시간에 현재 및 이전 비밀을 유지하는 경우 충분할 수 있음) ? 다른 것?

아마도 나는 서버 비밀이 손상 될 위험에 관해서 지나치게 편집증적일 수 있습니다. 물론 모든 암호화 상황에서 해결해야하는보다 일반적인 문제입니다 ...


1
좋은 질문이 있습니다. Re : 질문 2. 서버 측에 보관 된 비밀 키와 동일한 문제가 있습니다. 어떤 종류의 해시 일치 또는 비대칭 암호 해독을 수행하는 경우-이것이 jwt에 서명하든 db에 저장된 cc 정보를 해독하든 관계없이 서버의 코드로 액세스 할 수있는 비밀 키가 있어야합니다. 그래서 도대체 어디에 보관합니까 ?? 내가 찾은 최고의 대답은 다음과 같습니다. pcinetwork.org/forum/index.php?threads/…- 아마도 jwt 키만큼 안전 할 것입니다.
jbd

jwt 토큰의 비밀 키는 무엇입니까? jwt 토큰 자체가 비밀이라고 생각하고 있습니다. 또는 비밀 키는 RSAPrivateKey privateKey??
kittu

3
이것은 얼마 전에 요청되었지만 누군가 유용하다고 생각할 것입니다. 제 경우에는 사용자별로 "비밀 키"가 있습니다. 따라서 사용자가 로그인 할 때마다 해당 비밀을 생성하고 사용자 레코드와 함께 DB에 저장합니다. 그 비밀을 사용하여 토큰을 검증합니다. 로그 아웃하면 해당 값을 지 웁니다. 이것은 이전에 생성 된 다른 토큰을 자동으로 무효화합니다.
Nelson Rodriguez

답변:


52

나는 내 응용 프로그램을 위해 토큰을 가지고 놀았습니다. 제가 전문가는 아니지만 그 문제에 대한 제 경험과 생각을 공유 할 수 있습니다.

JWT의 핵심은 본질적으로 무결성입니다. 서버에 제공된 토큰이 정품이고 서버에서 제공 한 것인지 확인하는 메커니즘을 서버에 제공합니다. 귀하의 비밀을 통해 생성 된 서명이이를 제공합니다. 예, 당신의 비밀이 어떻게 든 유출되면, 그 개인은 당신의 서버가 자신의 것으로 생각할 토큰을 생성 할 수 있습니다. 토큰 기반 시스템은 단순히 서명 확인 때문에 사용자 이름 / 암호 시스템보다 더 안전합니다. 그리고이 경우에 누군가가 당신의 비밀을 가지고 있다면, 당신의 시스템은 누군가가 가짜 토큰을 만드는 것보다 처리해야 할 다른 보안 문제를 가지고 있습니다.

페이로드의 경우 서명은 제공된 토큰이 서버에서 보낸 것과 똑같다는 것만 알려줍니다. 페이로드 콘텐츠가 유효하거나 애플리케이션에 적합한 지 확인하는 것은 분명히 귀하에게 달려 있습니다.

질문 :

1.) 내 제한된 경험에서 두 번째 시스템으로 토큰을 확인하는 것이 확실히 낫습니다. 서명을 확인하는 것만으로도 토큰이 암호로 생성되었음을 의미합니다. 생성 된 토큰을 일종의 DB (redis, memcache / sql / mongo 또는 기타 저장소)에 저장하는 것은 서버에서 생성 한 토큰 만 수락하도록하는 환상적인 방법입니다. 이 시나리오에서는 비밀이 유출 되더라도 생성 된 토큰이 어쨌든 유효하지 않으므로 그다지 중요하지 않습니다. 이것이 제가 시스템에서 취하는 접근 방식입니다. 생성 된 모든 토큰은 DB (redis)에 저장되고 각 요청에서 토큰을 수락하기 전에 DB에 있는지 확인합니다. 이런 식으로 토큰은 어떻게 든 야생으로 방출 된 토큰, 사용자 로그 아웃, 암호 변경, 비밀 변경 등과 같은 어떤 이유로 든 취소 될 수 있습니다.

2.) 이것은 제가 경험이 많지 않은 부분이며 보안 전문가가 아니기 때문에 여전히 적극적으로 연구하고있는 부분입니다. 리소스를 찾으면 여기에 게시하십시오! 현재 저는 디스크에서로드하는 개인 키를 사용하고 있지만 분명히 최상의 또는 가장 안전한 솔루션과는 거리가 멀습니다.


5
여기에 두 번째 점에 대한 좋은 답변은 다음과 같습니다 security.stackexchange.com/questions/87130/...
Bossliaw

1
헤더에서 토큰을 사용할 수 있으므로 토큰이 도난 당하고 악의적 인 사용자가 해당 토큰으로 로그인을 시도하면 어떻게됩니까 (사용자의 이메일 주소를 알고 있음)?
kittu

22
모든 JWT를 저장하면 JWT에 이점이 없으며 임의의 세션 ID를 사용하는 것이 좋습니다.
ColinM 2017

46

다음은 애플리케이션에서 JWT를 구현할 때 고려해야 할 몇 가지 사항입니다.

  • JWT 수명을 비교적 짧게 유지하고 수명이 서버에서 관리되도록합니다. 그렇지 않고 나중에 JWT에 더 많은 정보가 필요한 경우 2 가지 버전을 지원하거나 변경 사항을 구현하기 전에 이전 JWT가 만료 될 때까지 기다려야합니다. iatjwt 의 필드 만보고 exp필드를 무시하면 서버에서 쉽게 관리 할 수 ​​있습니다 .

  • JWT에 요청 URL을 포함하는 것이 좋습니다. 예를 들어 JWT를 endpoint /my/test/path에서 사용하려면 JWT 와 같은 필드를 포함 'url':'/my/test/path'하여이 경로에서만 사용되도록합니다. 그렇지 않은 경우 사람들이 다른 엔드 포인트에서 JWT를 사용하기 시작하는 것을 발견 할 수 있습니다. JWT에 큰 URL을 사용하면 JWT가 훨씬 커지고 상당히 커질 수 있으므로 대신 md5 (url)을 포함하는 것을 고려할 수 있습니다.

  • JWT가 API에서 구현되는 경우 각 사용 사례에서 JWT 만료를 구성 할 수 있어야합니다. 예를 들어 JWT의 10 가지 사용 사례에 대해 10 개의 엔드 포인트가있는 경우 각 엔드 포인트가 서로 다른 시간에 만료되는 JWT를 수락하도록 할 수 있습니다. 예를 들어 한 엔드 포인트에서 제공하는 데이터가 매우 민감한 경우 일부 엔드 포인트를 다른 엔드 포인트보다 더 많이 잠글 수 있습니다.

  • 특정 시간 후에 단순히 JWT를 만료하는 대신 다음 두 가지를 모두 지원하는 JWT를 구현하는 것이 좋습니다.

    • N 개 사용-만료되기 전에 N 번만 사용할 수 있으며
    • 일정 시간이 지나면 만료됩니다 (일회용 토큰이있는 경우 사용하지 않으면 영원히 살기를 원하지 않습니까?)
  • 모든 JWT 인증 실패는 JWT 인증이 실패한 이유를 설명하는 "오류"응답 헤더를 생성해야합니다. 예 : "만료 됨", "남은 사용 없음", "취소됨"등. 이는 구현자가 JWT가 실패한 이유를 알 수 있도록 도와줍니다.

  • JWT가 정보를 유출하고 해커에게 제어 수단을 제공 할 때 JWT의 "헤더"를 무시하는 것을 고려하십시오. 이것은 주로 alg헤더 의 필드 와 관련이 있습니다.이를 무시하고 헤더가 지원하려는 것으로 가정하면 해커가 None알고리즘 을 사용 하여 서명 보안 검사를 제거하는 것을 방지 할 수 있습니다 .

  • JWT에는 토큰을 생성 한 앱을 자세히 설명하는 식별자가 포함되어야합니다. 예를 들어, 두 개의 서로 다른 클라이언트 인 mychat 및 myclassifiedsapp에 의해 JWT가 생성되는 경우 각 클라이언트는 JWT의 "iss"필드에 해당 프로젝트 이름 또는 유사한 것을 포함해야합니다 (예 : "iss": "mychat").

  • JWT는 로그 파일에 기록되지 않아야합니다. JWT의 내용은 기록 할 수 있지만 JWT 자체는 기록 할 수 없습니다. 이렇게하면 개발자 또는 다른 사용자가 로그 파일에서 JWT를 가져와 다른 사용자 계정에 작업을 수행 할 수 없습니다.
  • 해커가 서명하지 않고 토큰을 생성하지 않도록 JWT 구현이 "없음"알고리즘을 허용하지 않는지 확인합니다. 이 클래스의 오류는 JWT의 "헤더"를 무시함으로써 완전히 피할 수 있습니다.
  • 강력하게 사용하는 것을 고려 iat(발행) 대신 exp하여 JWT를에 (만료). 왜? iat기본적으로 JWT가 생성 된시기를 의미 하므로 생성 날짜를 기준으로 JWT가 만료 될 때 서버에서 조정할 수 있습니다. exp20 년 후의 누군가가지나 가면 JWT는 기본적으로 영원합니다! JWT iat가 미래에 있을 경우 자동으로 만료 되지만 클라이언트의 시간이 서버 시간과 약간 일치하지 않는 경우 약간의 흔들림 (예 : 10 초)을 허용합니다.
  • json 페이로드에서 JWT를 생성하기위한 엔드 포인트 구현을 고려하고 모든 구현 클라이언트가이 엔드 포인트를 사용하여 JWT를 생성하도록합니다. 이를 통해 JWT를 한 곳에서 쉽게 생성하는 방법으로 원하는 보안 문제를 해결할 수 있습니다. 우리는 앱에서 바로이 작업을 수행하지 않았으며 이제 5 개의 서로 다른 클라이언트가 구현하는 데 시간이 필요하기 때문에 JWT 서버 측 보안 업데이트를 천천히 전달해야합니다. 또한 생성 엔드 포인트가 JWT가 생성 할 json 페이로드 배열을 수락하도록하면 클라이언트를 위해이 엔드 포인트로 들어오는 http 요청 수가 감소합니다.
  • 세션 별 사용도 지원하는 엔드 포인트에서 JWT가 사용되는 경우 요청을 충족하는 데 필요한 항목을 JWT에 넣지 마십시오. JWT가 제공되지 않을 때 엔드 포인트가 세션과 함께 작동하는지 확인하면이 작업을 쉽게 수행 할 수 있습니다.
  • 따라서 JWT는 일반적으로 일종의 userId 또는 groupId를 포함하고이 정보를 기반으로 시스템의 일부에 대한 액세스를 허용합니다. 특히 민감한 데이터에 대한 액세스를 제공하는 경우 앱의 한 영역에있는 사용자가 다른 사용자로 가장하는 것을 허용하지 않도록하십시오. 왜? JWT 생성 프로세스가 "내부"서비스에만 액세스 할 수있는 경우에도 개발자 또는 기타 내부 팀은 임의의 클라이언트 회사의 CEO와 같은 모든 사용자의 데이터에 액세스하기 위해 JWT를 생성 할 수 있습니다. 예를 들어 앱이 고객에게 재무 기록에 대한 액세스를 제공하는 경우 JWT를 생성하여 개발자는 모든 회사의 재무 기록을 가져올 수 있습니다! 그리고 해커가 어쨌든 내부 네트워크에 침입하면 똑같이 할 수 있습니다.
  • 어떤 방식 으로든 JWT가 포함 된 모든 URL을 캐시하도록 허용하려는 경우 다른 사용자의 권한이 JWT가 아닌 URL에 포함되어 있는지 확인하십시오. 왜? 사용자는 결국 데이터를 얻지 못할 수 있기 때문입니다. 예를 들어 슈퍼 사용자가 앱에 로그인하여 다음 URL을 요청한다고 가정 해 보겠습니다. /mysite/userInfo?jwt=XXX,이 URL이 캐시됩니다. 로그 아웃하고 몇 분 후 일반 사용자가 앱에 로그인합니다. 슈퍼 유저에 대한 정보와 함께 캐시 된 콘텐츠를 받게됩니다! 이는 특히 Akamai와 같은 CDN을 사용하고 일부 파일을 더 오래 유지하는 경우 클라이언트에서 덜 발생하고 서버에서 더 많이 발생하는 경향이 있습니다. 이는 URL에 관련 사용자 정보를 포함하고 캐시 된 요청의 경우에도 서버에서이를 확인하여 해결할 수 있습니다./mysite/userInfo?id=52&jwt=XXX
  • jwt가 세션 쿠키처럼 사용되도록 의도되고 jwt가 생성 된 동일한 시스템에서만 작동해야하는 경우 jwt에 jti 필드를 추가하는 것을 고려해야 합니다. 이것은 기본적으로 CSRF 토큰으로, 한 사용자의 브라우저에서 다른 사용자의 브라우저로 JWT를 전달할 수 없도록합니다.

1
당신 created_by이라고 부르는 것은 JWT에 이미 그것에 대한 클레임이 있으며 iss(발행자) 라고 합니다.
Fred

그래 좋은 지적이야-내가 업데이트 할게 ... 고마워!
Brad Parks

8

나는 내가 전문가라고 생각하지 않지만 Jwt에 대해 몇 가지 의견을 나누고 싶습니다.

  • 1 : Akshay가 말했듯이 토큰을 검증 할 두 번째 시스템을 보유하는 것이 좋습니다.

    a .: 처리 방식 : 생성 된 해시를 만료 시간과 함께 세션 저장소에 저장합니다. 토큰의 유효성을 확인하려면 서버에서 발급 한 것이어야합니다.

    b .: 사용 된 서명 방법을 확인해야하는 것이 하나 이상 있습니다. 예 :

    header :
    {
      "alg": "none",
      "typ": "JWT"
    }
    

JWT를 검증하는 일부 라이브러리는 해시를 확인하지 않고 이것을 받아들입니다. 즉, 토큰에 서명하는 데 사용 된 소금을 모른 채 해커가 자신에게 몇 가지 권한을 부여 할 수 있습니다. 항상 이런 일이 일어나지 않도록하십시오. https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/

c .: 세션 ID와 함께 쿠키를 사용하는 것은 토큰의 유효성을 검사하는 데 유용하지 않습니다. 누군가 람다 사용자의 세션을 가로 채고 싶다면 스니퍼 (예 : wireshark)를 사용해야합니다. 이 해커는 동시에 두 정보를 모두 가지고 있습니다.

  • 2 : 모든 비밀에 대해 동일합니다. 그것을 아는 방법은 항상 있습니다.

내가 처리하는 방식은 포인트 1.a와 연결되어 있습니다. : 무작위 변수와 혼합 된 비밀이 있습니다. 비밀은 모든 토큰에 대해 고유합니다.

그러나 진정으로 안전한 시스템을 만들기 위해 토큰의 유효성을 검사하는 방법과 정도에 대한 모범 사례를 이해하려고합니다.

가능한 최상의 보안을 원한다면 모범 사례를 맹목적으로 따르지 마십시오. 가장 좋은 방법은 수행중인 작업을 이해 한 다음 (질문을 보면 괜찮다고 생각합니다) 필요한 보안을 평가하는 것입니다. 그리고 Mossad가 귀하의 기밀 데이터에 액세스하기를 원하면 항상 방법을 찾을 것입니다. (이 블로그 게시물이 마음에 듭니다 : https://www.schneier.com/blog/archives/2015/08/mickens_on_secu.html )


모든 토큰에 대해 고유 한 비밀을 갖는 것이 좋은 점이지만 매번 고유 한 비밀을 어떻게 생성합니까? 나는 nimbus jwt 라이브러리를 사용하고 있습니다
kittu

1
아마도 사용자의 해시 암호를 사용하십시오.
momokjaaaaa

1
"다른 사람들이하는 것과 같은 방식으로 일을하지 않으면 사람들이 보안을 통해 방법을 찾는 것이 더 어려울 것입니다." 이것은 나에게 은둔을 통한 보안처럼 들립니다. 모범 사례는 가장 일반적인 위험을 실질적으로 완화하기 때문에 그렇게 불립니다.
Mnebuerquo 2017-06-05

@Mnebuerquo 난 완전히 당신과 동의, 그것을 쓴 사람은 ;-) 신뢰해서는 안
Deblaton 장 - 필립

1
그는 모범 사례를 맹목적으로 따르지 말아야하지만 옳습니다 . 모범 사례가 최고로 간주되는 이유를 이해하는 것이 좋습니다 . 모든 보안 설계 결정에는 보안과 유용성간에 균형이 있습니다. 이유를 이해하면 이러한 결정을 지능적으로 내릴 수 있습니다. (모범 사례 불구하고 다음 보관하기 때문에 사용자하지 않습니다.)
Mnebuerquo

3

여기에 좋은 답변이 많이 있습니다. 가장 관련성이 있다고 생각되는 몇 가지 답변을 통합하고 몇 가지 제안을 더 추가하겠습니다.

1) JWT 토큰 유효성 검사는 토큰 자체의 서명을 확인하는 것으로 제한되어야합니까? 서버 비밀의 무결성에만 의존하거나 별도의 유효성 검사 메커니즘을 동반해야합니까?

아니요, 토큰 비밀 손상과 관련이없는 이유 때문입니다. 사용자가 사용자 이름과 비밀번호를 통해 로그인 할 때마다 권한 부여 서버는 생성 된 토큰 또는 생성 된 토큰에 대한 메타 데이터를 저장해야합니다. 이 메타 데이터를 권한 부여 레코드로 생각하십시오. 지정된 사용자 및 응용 프로그램 쌍에는 항상 하나의 유효한 토큰 또는 권한 만 있어야합니다. 유용한 메타 데이터는 액세스 토큰과 관련된 사용자 ID, 앱 ID 및 액세스 토큰이 발급 된 시간 (기존 액세스 토큰을 취소하고 새 액세스 토큰을 발급 할 수 있음)입니다. 모든 API 요청에서 토큰에 적절한 메타 데이터가 포함되어 있는지 확인합니다. 각 액세스 토큰이 발행 된시기에 대한 정보를 유지해야합니다. 사용자가 계정 자격 증명이 손상된 경우 기존 액세스 토큰을 취소하고 다시 로그인하여 새 액세스 토큰을 사용할 수 있도록합니다. 그러면 액세스 토큰이 발급 된 시간 (생성 된 권한 부여 시간)으로 데이터베이스가 업데이트됩니다. 모든 API 요청에서 액세스 토큰의 발급 시간이 생성 된 권한 부여 시간 이후인지 확인합니다.

다른 보안 조치로는 JWT를 로깅하지 않고 SHA256과 같은 보안 서명 알고리즘이 필요했습니다.

2) JWT 서명 검증이 토큰을 검증하는 유일한 수단 인 경우 서버 비밀의 무결성이 중단 점임을 의미합니다. 서버 비밀은 어떻게 관리해야합니까?

서버 비밀이 손상되면 공격자가 모든 사용자에게 액세스 토큰을 발급 할 수 있으며, 1 단계에서 액세스 토큰 데이터를 저장한다고해서 서버가 이러한 액세스 토큰을 수락하지 못할 수도 있습니다. 예를 들어 사용자에게 액세스 토큰이 발급 된 후 나중에 공격자가 해당 사용자에 대한 액세스 토큰을 생성한다고 가정 해 보겠습니다. 액세스 토큰의 인증 시간이 유효합니다.

Akshay Dhalwala가 말했듯이, 서버 측 비밀이 손상되면 공격자가 내부 네트워크, 소스 코드 저장소 또는 둘 다를 손상했음을 의미하므로 처리해야 할 더 큰 문제가 있습니다.

그러나 손상된 서버 비밀의 손상을 완화하고 비밀을 소스 코드에 저장하지 않는 시스템에는 https://zookeeper.apache.org 와 같은 조정 서비스를 사용하는 토큰 비밀 순환이 포함됩니다.. 크론 작업을 사용하여 몇 시간마다 (액세스 토큰이 유효한 기간에 관계없이) 앱 비밀을 생성하고 업데이트 된 비밀을 Zookeeper에 푸시합니다. 토큰 시크릿을 알아야하는 각 애플리케이션 서버에서 ZK 노드 값이 변경 될 때마다 업데이트되는 ZK 클라이언트를 구성하십시오. 기본 및 보조 비밀을 저장하고 토큰 비밀이 변경 될 때마다 새 토큰 비밀을 기본으로 설정하고 이전 토큰 비밀을 보조로 설정합니다. 이렇게하면 기존의 유효한 토큰이 2 차 암호에 대해 유효성이 검사되므로 여전히 유효합니다. 보조 비밀이 이전 기본 비밀로 교체 될 때까지 보조 비밀로 발급 된 모든 액세스 토큰은 어쨌든 만료됩니다.


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.