EazyBank 애플리케이션 내부에는
서로 커뮤니케이션을 시도 중인
두 가지의 앱이 있습니다
첫 번째는 Angular 기반의 UI 애플리케이션이고
두 번째는
SpringBoard 기반 웹 애플리케이션입니다
다음 개선 사항으로 저희는
저희가 사용하는 OAuth2 프레임워크를
Angular 웹 애플리케이션이
SpringBoot 웹 앱과 소통하려 할 때마다 시행되도록 해야 합니다
그게 EazyBank 웹 애플리케이션에 시도할 수 있는
다음 개선 사항입니다
이 과정에는 실사용자가 관여하므로
당연히 OAuth2 프레임워크의
authorization code grant type flow를 사용해야 합니다
그런데 authorization code grant type flow를
Angular UI 애플리케이션에서 시행할 수 있을까요?
물론 시행할 수 없습니다
왜냐하면 이 UI 애플리케이션은
JavaScript 기반인데
이런 UI 애플리케이션은 코드에 들어 있는
secret 값을 숨길 수가 없기 때문입니다
왜냐하면 개발자나 해커는
누구나 브라우저의 소스 코드를 열어서
Angular 애플리케이션이 사용하고 있는
JavaScript 코드를 볼 수 있기 때문입니다
이러한 상황을 위해 저희는
인증 코드 flavor가 하나 더 있습니다
바로 PKCE입니다
그러면 여러분에게 PKCE flow를 소개해 드리겠습니다
여기서 보이듯이
PKCE는 약자입니다
풀네임은 Proof Key for Code Exchange입니다
왜 이 flow를 따라야 할까요?
PKCE 외의 또 다른 인증 코드 flow로는
공개 클라이언트입니다
여기에는 모바일 애플리케이션, 네이티브 애플리케이션
JavaScript 기반 애플리케이션, SPA(단일 페이지 애플리케이션)
이 있는데 이들은 클라이언트 secret 값이
코드 기반에 짜여 들어가 있다는 한계가 있습니다
이 한계를 넘기 위해 저희는
PKCE와 함께 authorization code flow를 이용하는 겁니다
그러면 이 PKCE가 어떻게
이 문제를 해결하도록 저희를 도울 건지 알아봅시다
PKCE 접근의 일환으로, 클라이언트 애플리케이션이
리소스 소유자인 실사용자를
인증 서버의 로그인 페이지로 리다이렉트할 때마다
내부에서 클라이언트 앱은
code_verifier라는 값을 생성할 겁니다
그리고 code_verifier로부터
code_challenge를 생성합니다
클라이언트는 code_verifier로부터
code_challenge를 생성하기 위하여
먼저 SHA256 해시 알고리즘을
무작위로 생성된 code_verifier에 대해 실행합니다
그리고 code_verifier의 해시 값을 얻었다면
클라이언트 애플리케이션은 그 해시 string을
Base64-URL 인코딩으로 변환합니다
Base64-URL 인코드 값이 code_challenge가 됩니다
그러면 클라이언트 애플리케이션은 code_verifier와
code_challenge를 얻게 됩니다
그러므로 code_verifier는 클라이언트가 무작위로 생성한 값이고
방금 말씀드린 과정을 거쳐서
code_verifier를 기반으로
code_challenge를 생성합니다
아주 초기 단계에 클라이언트 애플리케이션이
인증 코드를 얻으려 하고 있으며
액세스 토큰은 요청 중이 아닐 때
그때 인증 서버에 code challenge를 보낼 것입니다
code verifier와
code challenge를 둘 다 보내지는 않습니다
처음 단계에서는 code challenge만 보냅니다
그러면 인증 서버는 code challenge를 가져다가
저장소에 보관하고
클라이언트 애플리케이션에게는
code challenge에 대응하는 인증 코드를 보냅니다
그러면 이제 클라이언트 애플리케이션은
인증 코드를 얻게 됩니다
인증 서버는 클라이언트 애플리케이션에게
code challenge를 도로 전송하지는 않습니다
저장만 하고 있을 뿐입니다
다음 단계에서는 클라이언트 애플리케이션이
액세스 토큰을 얻으려 할 때마다
이번에는 code verifier 값을
첫 번째 단계에서 인증 서버가 발급했던
인증 코드와 함께 보냅니다
그 다음 인증 서버가 code verifier와
처음에 발급했던 인증 코드를
받게 됩니다
그 사이 인증 서버는
클라이언트 애플리케이션으로부터 받은
code verifier를 확인하고
SHA256 해시를 할 겁니다
code verifier의 해시 값을 얻었으면
이전에 받아서
저장하고 있었던
code challenge와 함께
인증 코드와 비교합니다
두 개가 모두 맞아야만
클라이언트 애플리케이션에게
액세스 토큰을 발급할 겁니다
여기를 보시면 PKCE의 가장 주된 장점은
처음 단계를 시행하는 클라이언트 애플리케이션이
어느 것이든 간에
액세스 토큰을 받는 것은 같은 애플리케이션이라는 점입니다
클라이언트 애플리케이션이
인증 코드를 받기 위한 첫 단계를
code challenge를 가지고 시행했다고 가정합시다
그리고 어떤 해커가
OAuth 서버에 제가 사용한
인증 코드를 훔치거나
인증 코드를 조작하려고 해도
소용이 없을 겁니다
왜냐하면 해커가 인증을 시도할 때마다
해커는 클라이언트 애플리케이션이
원래 code challenge를 연산하기 위해 사용했던
code verifier가 무엇인지 알아야 하기 때문입니다
그 code verifier가 없으면
해커는 인증 코드를 얻었어도
그걸 가지고 할 수 있는 게 아무것도 없습니다
그러므로 이 code verifier와 code challenge 시스템을 통해
클라이언트 애플리케이션이 공개 클라이언트임에도 불구하고
보안도 간접적으로 확보가 가능합니다
이 부분은 복잡해서 이해가 어려울 수 있습니다
그러므로 몇 분을 더 할애해서
PKCE를 이해하실 수 있도록 하겠습니다
첫 번째 단계를 봅시다
실사용자는 평소와 같이 공개 클라이언트에게
이러이러한 리소스에 접근하고 싶다고 합니다
그러면 공개 클라이언트는
인증 서버 로그인 페이지로 리다이렉트해 줄 테니
자격 증명을 해달라고
말합니다
증명이 완료되면
보안되어 있는 리소스를 드릴 수 있습니다
그리고 공개 클라이언트는
실사용자를 인증 서버 로그인 페이지로
리다이렉트하는 것과 동시에
code challenge를 클라이언트 ID와 함께
인증 서버에게 공유할 겁니다
인증 서버는 저장소에
받은 code challenge를
4단계에 발급할 인증 코드에 대응하여 저장합니다
클라이언트 애플리케이션이
인증 코드를 받았다면
이번에는 또 요청을 하여
인증 서버로부터 액세스 토큰을 발급받으려 합니다
성공적으로 액세스 토큰을 받기 위해서
클라이언트 애플리케이션은 클라이언트 ID를 보내야 합니다
code challenge를 계산할 때
사용했던 code verifier도 보내야 하죠
또한 4단계에 받았던
인증 코드도
code verifier와 함께 전송합니다
인증 서버에 이 정보를 모든 정보를
공개 클라이언트를 통해 보내는 것이 5단계입니다
그 동안 인증 서버는
code verifier를 가져다
클라이언트가 했던 것과 같은
해시 알고리즘을 통과시킬 겁니다
그리고 code verifier의 해시 값을 얻은 후에
처음 받았던 code challenge에
대조해 볼 것입니다
두 해시 값이 일치한다면
인증 서버는 공개 클라이언트에게
액세스 토큰을 발급해 줍니다
그 후에는 과정이 비슷해집니다
공개 클라이언트는 발급받은 액세스 토큰을
리소스 서버에 전송하여
리소스 서버로부터 응답을 받을 수 있습니다
여기를 보시면 이게 클라이언트 애플리케이션이 보내야 하는
값과 데이터들입니다
2단계와 3단계에서
인증 코드를 받으려 할 때는 클라이언트 ID
리다이렉트 URI, scope,
state,
resepone_type(응답 유형),
그리고 code challenge를 전송해야 합니다
code challenge 값은 클라이언트 애플리케이션이 무작위로 생성한
code verifier로부터 생성됩니다
그리고 code challenge와 함께
인증 서버에게 저희는
사용하는 challenge method이 무엇인지도 알려줘야 합니다
저희가 볼 대부분의 상황에서는 SHA256 해시 알고리즘을 사용하는데
이 정보는 S256으로 축약해서 보냅니다
그리고 클라이언트 애플리케이션이
5단계에서 인증 코드를 사용할 때
맨 처음 입력으로는
인증 코드를 보내며
클라이언트 ID와
클라이언트 secret도 함께 보냅니다
이때 secret은 선택 사항입니다
클라이언트 애플리케이션이 만약에
공개적이라면, 클라이언트 secret을 보내는 것은
필수가 아닙니다.
grant_type는 authorization_code이며
그 다음으로는 리다이렉트 URI를 보냅니다
마지막으로 클라이언트 애플리케이션이
code challenge 해시 값을 생성할 때 사용한
code verifier도 보내야 합니다
이것들이 클라이언트 애플리케이션이
인증 서버와 공유해야 하는 정보입니다
이해가 되셨길 바랍니다
PKCE는 원래
authorization code flow가
모바일 앱, SPA, JavaScript 애플리케이션 등의
공개 앱에서 사용될 때를 위해 개발되었습니다
그런데 최근 업계에서의 기업들은
PKCE의 더 큰 가능성을 보았습니다
왜냐하면 이 방법으로 접근한다면
인증 코드 injection 공격이나
인증 코드를 건드리려는 해커들을 막을 수 있기 때문입니다
그래서 최근에는 클라이언트 애플리케이션이
클라이언트 secret을 안전하게 저장할 능력이 있더라도
더 강력한 보안을 위하여
PKCE가 권장됩니다
그런데 클라이언트 애플리케이션이
클라이언트 secret을 저장하지 못한다면
secret 없이도 PKCE flow는 따라갈 수 있습니다
이해가 되셨길 바랍니다
다음 강의에서는 PKCE의 예시를
실험용 웹사이트에서 체험해 보겠습니다
이해하기 아주 쉬울 것 같습니다
들어주셔서 감사하며 다음 강의에서 뵙겠습니다
수고하셨습니다