JWT 토큰의 서버 측 처리를위한 모범 사례 [닫힌]
( 이것은 실제로 NodeJS 국한되지 않고 등에 자체 문제이기 때문에이 스레드 에서 생성됨)
인증을 사용하여 REST API 서버를 구현하고 사용하여 사용자가 사용자 이름 / 암호를 사용하여 / 로그인 끝점을 통해 로그인 할 수 있도록 JWT 토큰 처리를 구현으로 구현했습니다. 그러면 서버 암호에서 JWT 토큰이 생성되어 서버로 반환됩니다. 고객. 그런 다음 토큰은 인증 된 각 API 요청에서 클라이언트에서 서버로 전달되고, 서버 암호는 토큰을 확인하는 데 사용됩니다.
그러나 진정으로 안전한 시스템을 만들기 위해 토큰의 유효성을 검사하는 방법과 정도에 대한 모범 사례를 이해합니다. 토큰을 "검증"하고 정확히 무엇을해야합니까? 서버 시크릿을 사용하여 서명을 확인할 수 있습니다. 아니면 서버에 저장된 일부 데이터와 토큰 및 / 또는 토큰 페이로드를 교차 확인해야합니까?
토큰 기반 인증 시스템은 사용자의 암호를 얻는 것보다 토큰을 얻는 것이 동일하거나 더 어려운 경우 각 요청에서 사용자 이름 / 암호를 전달하는 것만 큼 안전합니다. 그러나 내가 본 예에서 토큰을 생성하는 데 필요한 유일한 정보는 사용자 이름과 서버 측 비밀입니다. 이것은 악의적 인 사용자가 서버 비밀에 대한 지식을 1 분 동안 얻는다고 가정하면 이제 모든 사용자 를 특정 사용자에게만 액세스 할 수있는 것은 아닙니다. 금액했지만 모든 사용자 계정에 입증 되었습니까 ?
이 저에게 질문을 던집니다.
1) JWT 토큰 유효성 검사는 토큰 자체의 서명을 확인하고 제한해야합니까? 서버 비밀의 보장에만 의존하거나 별도의 유효성 검사를 수행해야합니까?
어떤 경우에는 / login 끝점을 통해 사용되는 것으로 로그인하면 세션이 설정되는 토큰과 세션을 함께 사용하는 것을 보았습니다. API 요청은 토큰의 유효성을 검사하고 토큰에있는 사용 된 데이터를 세션에 보존 일부 데이터와 비교합니다. 그러나 세션을 사용한다는 것은 쿠키를 사용하는 것을 의미하며 어떤 의미에서 토큰 기반 접근 방식을 사용하는 목적을 무효화합니다. 또한 특정 클라이언트에 문제를 수 있습니다.
공격자가 "유효한"토큰을 생성 할 수있는 서버 비밀이 손상 되더라도 / 로그인 엔드 포인트를 통해 생성 된 정확한 토큰 만 보장하기 위해 서버가 현재 사용중인 모든 토큰을 Memcache 등에서 유지하는 것을 상상할 수 있습니다. 받아 들여질 것입니다. 이것이 합리적입니까, 아니면 둘 / 과잉입니까?
2) JWT 유전자 서명이 존재하는 경우 고유 한 유일한 수단 인 서버 인 비밀의 무결성이 중단 점임을 의미합니다. 서버 비밀은 어떻게 관리해야합니까? 환경 변수에서 배포 된 스택 당 한 번 생성 (무작위 화?) 하시겠습니까? 주기적으로 순환 전에 또는 순환 (그렇다면 순환하기 전에 순환 순환 유효성을 검사해야하는 기존 토큰을 처리하는 방법, 서버가 주어진 시간에 현재 및 이전 비밀을 유지하는 경우 충분한 수 있음)? 다른 것?
아마도 나는 서버 비밀이 손상 될 위험에 대부분의 편집증적일 수 있습니다. 물론 모든 암호화 상황에서 해결해야하는 일반적인 문제입니다 ...
나는 내 응용 프로그램을 위해 토큰을 가지고 놀았습니다. 제가 전문가는 어떤 문제에 대한 제 경험과 생각을 공유 할 수 있습니다.
JWT의 핵심은 기본으로 무결성입니다. 서버에 소유 토큰이 정품이고 서버에서 제공 한 것인지 확인하는 서버에 제공됩니다. 귀하의 비밀을 통해 생성 된 서명이 제공됩니다. 예, 당신의 비밀이 어떻게 당신의 서버가 당신의 서버가 자신의 생각할 토큰을 생성 할 수 있습니다. 토큰 기반 시스템은 서명 확인 때문에 / 암호 시스템보다 더 안전합니다. 그리고이 경우 누군가가 당신의 비밀을 가지고 있고, 당신의 시스템은 누군가가 가짜 토큰을 만드는 것보다 처리해야 할 다른 보안 문제를 가지고 있습니다. (그런데도 비밀을 변경하는 것만으로도 이전 비밀로 만든 토큰이 이제는 유효하지 않게됩니다).
페이로드의 경우는 서명 토큰이 서버에서 보낸 것과 똑같다는 것이 알려집니다. 페이로드 콘텐츠가 유효하거나 애플리케이션에 있는지 확인하는 것이 분명히 귀하에게 달려 있습니다.
질문 :
1.) 내 낙서 경험에서 두 번째 시스템으로 토큰을 확인하는 것이 확실히 낫습니다. 서명을 확인하는 것만으로도 토큰이 암호로 생성된다는 의미입니다. 생성 된 토큰을 사용하지 않는 DB (redis, memcache / sql / mongo 또는 기타 저장소)에 저장하는 것은 서버에서 생성 된 토큰 만 허용됩니다. 이 시나리오에서는 비밀이 유출되는 것이지만, 그다지 중요하지 않습니다. 이것이 제가 시스템에서 취하는 접근 방식입니다. 생성 된 모든 토큰은 DB (redis)에 저장되고 각 요청에서 토큰을 수락하기 전에 DB에 있는지 확인합니다. 어떤 이런 식으로 토큰은 어떻게 든 야생으로 방출 된 토큰, 사용자 로그 아웃, 암호 변경, 비밀 변경 메시지 같은 어떤 이런 메시지 취소 될 수 있습니다.
2.) 이것은 많은지 않은 부분이며 보안 전문가가 아니기 때문에 여전히 적극적으로 연구하고있는 부분입니다. 리소스를 찾으면 여기에 게시하십시오! 현재 저는 디스크에서로드하는 개인 키를 사용하고 최상의 최선 또는 가장 안전한 솔루션과 거리가 멀습니다.
다음은 애플리케이션에서 JWT를 구현할 때 할 때 몇 가지 사항입니다.
JWT 수명을 짧게 유지하고 수명이 서버에서 관리합니다. 나중에 나중에 JWT에 더 많은 정보가 필요한 경우 2 가지 버전을 지원하거나 변경 사항을 구현하기 전에 이전 JWT가 종료 될 때까지 기다려야합니다.
iat
jwt 의 필드 만보 고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 번만 사용할 수 있으며
- 일정 시간이 지나면 만료됩니다 (1 회용 토큰이있는 경우 사용하지 않으면 영원히 살기를 원하지 않습니까?)
모든 JWT 인증 실패는 JWT 인증이 실패한 이유를 설명하는 "오류"응답 헤더를 생성해야합니다. 예 : "만료 됨", "남은 사용 없음", "취소됨"등. 이는 구현자가 JWT가 실패한 이유를 알 수 있도록 도와줍니다.
JWT의 "헤더"가 정보를 유출하고 해커에게 제어 수단을 제공하므로 무시하는 것을 고려하십시오. 이것은 대부분
alg
헤더 의 필드 와 관련이 있습니다.이를 무시하고 헤더가 지원하려는 것으로 가정합니다. 이렇게하면 해커None
가 서명 보안 검사를 제거하는 알고리즘 을 사용하려는 것을 방지 할 수 있습니다 .JWT에는 토큰을 생성 한 앱을 자세히 설명하는 식별자가 포함되어야합니다. 예를 들어, 두 개의 서로 다른 클라이언트 인 mychat 및 myclassifiedsapp에 의해 JWT가 생성되는 경우 각 클라이언트는 JWT의 "iss"필드에 프로젝트 이름 또는 이와 유사한 것을 포함해야합니다 (예 : "iss": "mychat").
- JWT는 로그 파일에 기록되지 않아야합니다. JWT의 내용은 기록 할 수 있지만 JWT 자체는 기록 할 수 없습니다. 이렇게하면 개발자 또는 다른 사용자가 로그 파일에서 JWT를 가져와 다른 사용자 계정에 작업을 수행 할 수 없습니다.
- 해커가 서명하지 않고 토큰을 생성하지 않도록 JWT 구현에서 "없음"알고리즘을 허용하지 않는지 확인하세요. 이 클래스의 오류는 JWT의 "헤더"를 무시함으로써 완전히 피할 수 있습니다.
- Strongly consider using
iat
(issued at) instead ofexp
(expiry) in your JWTs. Why? Sinceiat
basically means when was the JWT created, this allows you to adjust on the server when the JWT expires, based on the creation date. If someone passes in anexp
that's 20 years in the future, the JWT basically lives forever! Note that you automatically expire JWTs if theiriat
is in the future, but allow for a little bit of wiggle room (e.g 10 seconds), in case the client's time is slightly out of sync with the servers time. - 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를 전달할 수 없도록합니다.
나는 내가 전문가라고 생각하지 않지만 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 )
여기에 좋은 답변이 많이 있습니다. 가장 관련성이 높은 답변 중 일부를 통합하고 몇 가지 제안을 추가하겠습니다.
1) JWT 토큰 유효성 검사는 토큰 자체의 서명을 확인하는 것으로 제한되어야합니까? 서버 비밀의 무결성에만 의존하거나 별도의 유효성 검사 메커니즘을 수반해야합니까?
아니요, 토큰 비밀 손상과 관련이없는 이유 때문입니다. 사용자가 사용자 이름과 비밀번호를 통해 로그인 할 때마다 권한 부여 서버는 생성 된 토큰 또는 생성 된 토큰에 대한 메타 데이터를 저장해야합니다. 이 메타 데이터를 권한 부여 레코드로 생각하십시오. 지정된 사용자 및 응용 프로그램 쌍에는 항상 하나의 유효한 토큰 또는 권한 만 있어야합니다. 유용한 메타 데이터는 액세스 토큰과 관련된 사용자 ID, 앱 ID 및 액세스 토큰이 발급 된 시간 (기존 액세스 토큰 취소 및 새 액세스 토큰 발급 허용)입니다. 모든 API 요청에서 토큰에 적절한 메타 데이터가 포함되어 있는지 확인합니다. 각 액세스 토큰이 발행 된시기에 대한 정보를 유지해야합니다. 사용자가 계정 자격 증명이 손상된 경우 기존 액세스 토큰을 취소하고 다시 로그인하여 새 액세스 토큰을 사용할 수 있도록합니다. 그러면 액세스 토큰이 발급 된 시간 (생성 된 권한 부여 시간)으로 데이터베이스가 업데이트됩니다. 모든 API 요청에서 액세스 토큰의 발급 시간이 생성 된 권한 부여 시간 이후인지 확인합니다.
다른 보안 조치로는 JWT를 로깅하지 않고 SHA256과 같은 보안 서명 알고리즘이 필요했습니다.
2) JWT 서명 검증이 토큰을 검증하는 유일한 수단 인 경우 서버 비밀의 무결성이 중단 점임을 의미합니다. 서버 비밀은 어떻게 관리해야합니까?
서버 비밀이 손상되면 공격자가 모든 사용자에 대한 액세스 토큰을 발급 할 수 있으며 1 단계에서 액세스 토큰 데이터를 저장한다고해서 서버가 이러한 액세스 토큰을 수락하지 못할 수도 있습니다. 예를 들어 사용자에게 액세스 토큰이 발급 된 후 나중에 공격자가 해당 사용자에 대한 액세스 토큰을 생성한다고 가정합니다. 액세스 토큰의 인증 시간이 유효합니다.
Akshay Dhalwala가 말했듯이, 서버 측 비밀이 손상되면 공격자가 내부 네트워크, 소스 코드 저장소 또는 둘 다를 손상했음을 의미하므로 처리해야 할 더 큰 문제가 있습니다.
그러나 손상된 서버 비밀의 손상을 완화하고 비밀을 소스 코드에 저장하지 않는 시스템에는 https://zookeeper.apache.org 와 같은 조정 서비스를 사용하는 토큰 비밀 순환이 포함됩니다.. 크론 작업을 사용하여 몇 시간마다 (액세스 토큰이 유효한 기간 동안) 앱 암호를 생성하고 업데이트 된 암호를 Zookeeper에 푸시합니다. 토큰 시크릿을 알아야하는 각 애플리케이션 서버에서 ZK 노드 값이 변경 될 때마다 업데이트되는 ZK 클라이언트를 구성하십시오. 기본 및 보조 비밀을 저장하고 토큰 비밀이 변경 될 때마다 새 토큰 비밀을 기본으로 설정하고 이전 토큰 비밀을 보조로 설정합니다. 이렇게하면 기존의 유효한 토큰이 2 차 암호에 대해 유효성이 검사되므로 여전히 유효합니다. 보조 비밀이 이전 기본 비밀로 교체 될 때까지 보조 비밀로 발행 된 모든 액세스 토큰은 어쨌든 만료됩니다.
IETF에는 oAuth 워킹 그룹에서 진행중인 RFC가 있습니다. https://tools.ietf.org/id/draft-ietf-oauth-jwt-bcp-05.html 참조
참고 URL : https://stackoverflow.com/questions/30523238/best-practices-for-server-side-handling-of-jwt-tokens
'IT' 카테고리의 다른 글
ASP.NET에 대한 Comet 구현? (0) | 2020.08.15 |
---|---|
시맨틱 차이 유틸리티 (0) | 2020.08.15 |
C #의 'yield'키워드에 해당하는 Java가 있습니까? (0) | 2020.08.15 |
GCC 및 ld로 사용하지 않는 C / C ++ 기호를 제거하는 방법은 무엇입니까? (0) | 2020.08.14 |
Rails 및 HTTParty를 사용하여 API에 JSON 게시 (0) | 2020.08.14 |