Angular2 단일 페이지 앱과 ECS에서 실행되는 REST API로 구성된 시스템을 구축하고 있습니다. API는 .Net / Nancy 에서 실행 되지만 변경 될 수 있습니다.
Cognito를 사용해보고 싶습니다. 이것이 인증 워크 플로를 상상 한 방법입니다.
- SPA가 사용자를 로그인하고 JWT를받습니다.
- SPA는 모든 요청과 함께 JWT를 REST API로 보냅니다.
- REST API는 JWT가 인증되었는지 확인합니다.
내 질문은 3 단계에 관한 것입니다. 내 서버 (또는 오히려 상태 비 저장, 자동 확장,로드 밸런싱 된 Docker 컨테이너)가 토큰이 인증되었는지 확인할 수 있습니까? “서버”는 JWT 자체를 발행하지 않았기 때문에 자체 보안 비밀을 사용할 수 없습니다 ( 여기 의 기본 JWT 예제에 설명 됨 ).
Cognito 문서를 읽고 많이 봤지만 서버 측에서 JWT로 무엇을해야하는지에 대한 좋은 지침을 찾을 수 없습니다.
답변
내가 문서를 제대로 읽지 않은 것으로 밝혀졌습니다. 여기에 설명되어 있습니다 ( “웹 API에서 ID 토큰 및 액세스 토큰 사용”으로 스크롤).
API 서비스는 Cognito의 암호를 다운로드하고이를 사용하여 수신 된 JWT를 확인할 수 있습니다. 완전한.
편집하다
Groady의 코멘트 @ 포인트에 :하지만 어떻게 당신은 토큰의 유효성을 검사합니까? 이를 위해 jose4j 또는 nimbus (둘 다 Java) 와 같은 전투 테스트를 거친 라이브러리를 사용하고 처음부터 확인을 구현하지 마십시오.
다음 은 최근에 java / dropwizard 서비스에서 구현해야 할 때 시작된 nimbus를 사용하는 Spring Boot의 구현 예입니다.
답변
NodeJS에서 서명을 확인하는 방법은 다음과 같습니다.
var jwt = require('jsonwebtoken');
var jwkToPem = require('jwk-to-pem');
var pem = jwkToPem(jwk);
jwt.verify(token, pem, function(err, decoded) {
console.log(decoded)
});
// Note : You can get jwk from https://cognito-idp.{region}.amazonaws.com/{userPoolId}/.well-known/jwks.json
답변
인증 코드 부여 흐름 실행
다음과 같이 가정합니다.
- AWS Cognito에서 사용자 풀을 올바르게 구성하고
-
다음을 통해 가입 / 로그인하고 액세스 코드를 얻을 수 있습니다.
https://<your-domain>.auth.us-west-2.amazoncognito.com/login?response_type=code&client_id=<your-client-id>&redirect_uri=<your-redirect-uri>
브라우저가 다음으로 리디렉션되어야합니다. <your-redirect-uri>?code=4dd94e4f-3323-471e-af0f-dc52a8fe98a0
이제 해당 코드를 백엔드로 전달하고 토큰을 요청해야합니다.
POST https://<your-domain>.auth.us-west-2.amazoncognito.com/oauth2/token
- 사용자의 설정
Authorization
에 헤더를Basic
사용username=<app client id>
하고password=<app client secret>
AWS Cognito에 구성된 앱 클라이언트 당 - 요청 본문에 다음을 설정하십시오.
grant_type=authorization_code
code=<your-code>
client_id=<your-client-id>
redirect_uri=<your-redirect-uri>
성공하면 백엔드가 base64로 인코딩 된 토큰 세트를 수신해야합니다.
{
id_token: '...',
access_token: '...',
refresh_token: '...',
expires_in: 3600,
token_type: 'Bearer'
}
이제 문서 에 따르면 백엔드는 다음을 통해 JWT 서명을 검증해야합니다.
- ID 토큰 디코딩
- 로컬 키 ID (아이)와 공개 키드 비교
- 공개 키를 사용하여 JWT 라이브러리를 사용하여 서명을 확인합니다.
AWS Cognito는 각 사용자 풀에 대해 두 쌍의 RSA 암호화 키를 생성하므로 토큰을 암호화하는 데 사용 된 키를 파악해야합니다.
다음 은 JWT 확인을 보여주는 NodeJS 스 니펫입니다.
import jsonwebtoken from 'jsonwebtoken'
import jwkToPem from 'jwk-to-pem'
const jsonWebKeys = [ // from https://cognito-idp.us-west-2.amazonaws.com/<UserPoolId>/.well-known/jwks.json
{
"alg": "RS256",
"e": "AQAB",
"kid": "ABCDEFGHIJKLMNOPabc/1A2B3CZ5x6y7MA56Cy+6ubf=",
"kty": "RSA",
"n": "...",
"use": "sig"
},
{
"alg": "RS256",
"e": "AQAB",
"kid": "XYZAAAAAAAAAAAAAAA/1A2B3CZ5x6y7MA56Cy+6abc=",
"kty": "RSA",
"n": "...",
"use": "sig"
}
]
function validateToken(token) {
const header = decodeTokenHeader(token); // {"kid":"XYZAAAAAAAAAAAAAAA/1A2B3CZ5x6y7MA56Cy+6abc=", "alg": "RS256"}
const jsonWebKey = getJsonWebKeyWithKID(header.kid);
verifyJsonWebTokenSignature(token, jsonWebKey, (err, decodedToken) => {
if (err) {
console.error(err);
} else {
console.log(decodedToken);
}
})
}
function decodeTokenHeader(token) {
const [headerEncoded] = token.split('.');
const buff = new Buffer(headerEncoded, 'base64');
const text = buff.toString('ascii');
return JSON.parse(text);
}
function getJsonWebKeyWithKID(kid) {
for (let jwk of jsonWebKeys) {
if (jwk.kid === kid) {
return jwk;
}
}
return null
}
function verifyJsonWebTokenSignature(token, jsonWebKey, clbk) {
const pem = jwkToPem(jsonWebKey);
jsonwebtoken.verify(token, pem, {algorithms: ['RS256']}, (err, decodedToken) => clbk(err, decodedToken))
}
validateToken('xxxxxxxxx.XXXXXXXX.xxxxxxxx')
답변
비슷한 문제가 있었지만 API 게이트웨이를 사용하지 않았습니다. 제 경우에는 AWS Cognito Developer Authenticated identity route를 통해 얻은 JWT 토큰의 서명을 확인하고 싶었습니다.
여러 사이트의 많은 포스터와 마찬가지로 외부에서 즉, 서버 측 또는 스크립트를 통해 AWS JWT 토큰의 서명을 확인하는 데 필요한 비트를 정확히 맞추는 데 문제가있었습니다.
AWS JWT 토큰 서명 을 확인 하고 요점을 파악한 것 같습니다 . PyCrypto의 Crypto.Signature에서 pyjwt 또는 PKCS1_v1_5c를 사용하여 AWS JWT / JWS 토큰을 확인합니다.
네, 제 경우에는 파이썬 이었지만 노드에서도 쉽게 수행 할 수 있습니다 (npm install jsonwebtoken jwk-to-pem 요청).
나는 이것을 알아 내려고 할 때 나는 대부분 옳은 일을하고 있었지만 파이썬 딕셔너리 순서와 같은 뉘앙스가 있거나, 거기에 json 표현이 부족했기 때문에 주석에서 몇 가지 문제를 강조하려고했습니다.
바라건대 누군가 어딘가에 도움이 될 수 있습니다.
답변
짧은 대답 :
다음 끝점에서 사용자 풀에 대한 공개 키를 얻을 수 있습니다.이 공개 키를
https://cognito-idp.{region}.amazonaws.com/{userPoolId}/.well-known/jwks.json
사용하여 토큰을 성공적으로 디코딩하면 토큰이 유효하지 않으면 위조됩니다.
긴 답변 :
코크 릿을 통해 성공적으로 인증하면 액세스 및 ID 토큰을받습니다. 이제이 토큰이 변조되었는지 여부를 확인하려고합니다. 전통적으로 우리는 토큰이 유효한지 확인하기 위해 이러한 토큰을 인증 서비스 (처음에이 토큰을 발행 한)로 다시 보냅니다. 이러한 시스템 은 비밀 키를 사용하여 페이로드를 암호화하는 symmetric key encryption
것과 같은 알고리즘 HMAC
을 사용하므로이 시스템 만이이 토큰이 유효한지 여부를 알 수 있습니다.
기존 인증 JWT 토큰 헤더 :
{
"alg": "HS256",
"typ": "JWT"
}
여기서 사용되는 암호화 알고리즘은 대칭입니다 (HMAC + SHA256).
그러나 Cognito와 같은 최신 인증 시스템 은 공개 및 개인 키 쌍을 사용하여 페이로드를 암호화하는 asymmetric key encryption
것과 같은 알고리즘 RSA
을 사용합니다. 페이로드는 개인 키를 사용하여 암호화되지만 공개 키를 통해 디코딩 할 수 있습니다. 이러한 알고리즘을 사용하는 주요 이점은 토큰이 유효한지 여부를 알리기 위해 단일 인증 서비스를 요청할 필요가 없다는 것입니다. 누구나 공개 키에 접근 할 수 있기 때문에 누구나 토큰의 유효성을 확인할 수 있습니다. 유효성 검사로드는 상당히 분산되어 있으며 단일 실패 지점이 없습니다.
Cognito JWT 토큰 헤더 :
{
"kid": "abcdefghijklmnopqrsexample=",
"alg": "RS256"
}
이 경우에 사용되는 비대칭 암호화 알고리즘-RSA + SHA256
답변
cognito-jwt-verifier 는 최소한의 종속성으로 노드 / Lambda 백엔드의 AWS Cognito에서 얻은 JWT 토큰에 액세스하고 ID를 확인하는 작은 npm 패키지입니다.
면책 조항 : 나는 이것의 저자입니다. 나는 나를 위해 모든 상자를 체크하는 것을 찾을 수 없기 때문에 그것을 생각해 냈습니다.
- 최소한의 의존성
- 프레임 워크 불가지론
- JWKS (공개 키) 캐싱
- 테스트 범위
사용법 (자세한 예는 github repo 참조) :
const { verifierFactory } = require('@southlane/cognito-jwt-verifier')
const verifier = verifierFactory({
region: 'us-east-1',
userPoolId: 'us-east-1_PDsy6i0Bf',
appClientId: '5ra91i9p4trq42m2vnjs0pv06q',
tokenType: 'id', // either "access" or "id"
})
const token = 'eyJraWQiOiI0UFFoK0JaVE...' // clipped
try {
const tokenPayload = await verifier.verify(token)
} catch (e) {
// catch error and act accordingly, e.g. throw HTTP 401 error
}
답변
여기에서 Lambda 코드에서 통찰력을 얻을 수 있습니다.
https://github.com/awslabs/aws-support-tools/tree/master/Cognito/decode-verify-jwt
Golang에서
https://gist.github.com/tmaiaroto/e2ee5e88fc6ae035307d7c5ee71a99cf