inflearn logo
강의

Course

Instructor

Next.js Master Class: Part 3 - Completing Real-World Architecture (Server-Client Synchronization, Extreme Optimization, Full-Stack Security)

BFF의 필요성

Resolved

25

cindjy

1 asked

0

안녕하세요, 수업 너무 잘 듣고 있습니다!

프로젝트와 병행하면서 수강 중이었는데 인증/인가 부분에서 궁금증이 있어 문의드립니다.

같은 도메인 내에 웹사이트/프론트 서버를 두고 프론트 서버와 백엔드 서버가 통신하는 BFF 패턴을 사용하면, 민감한 토큰을 브라우저에 노출하지 않고 서버 사이드에서 보관할 수 있어 보안에 유리하다고 이해했습니다.

그런데 소셜 로그인(OAuth)을 도입하면 인가 처리를 Google, Kakao 같은 외부 provider에게 위임하게 되는데, 이 경우에도 BFF가 여전히 필요한가요? 필요하다면 BFF가 소셜 로그인 흐름에서 구체적으로 어떤 역할을 담당하게 되는지 궁금합니다.

next.js bff

Answer 2

0

nhcodingstudio

안녕하세요 져니님, 수업을 너무 잘 듣고 계신다니 정말 감사드립니다. 단순한 기능 구현을 넘어서 인증과 인가의 아키텍처, 그리고 보안의 본질적인 부분까지 깊이 고민하시며 프로젝트에 적용해 보려는 모습이 시니어 개발자로 성장해 나가는 아주 훌륭한 과정이라고 생각합니다. 질문하신 내용에 대해 실무적인 관점과 실제 데이터 흐름을 바탕으로 최대한 상세하게 답변해 드리겠습니다.

결론부터 말씀드리자면, 소셜 로그인을 도입하여 인가 처리를 구글이나 카카오 같은 외부 프로바이더에게 위임하더라도 프론트엔드와 백엔드 서버 사이에 위치하는 BFF 패턴은 여전히 매우 필요하며, 오히려 보안과 전체적인 시스템 아키텍처 측면에서 훨씬 더 중요하고 강력한 역할을 수행하게 됩니다.

OAuth가 인증과 인가를 위임하는 것은 맞지만, 그것은 어디까지나 우리의 서비스와 외부 프로바이더 사이의 신뢰 관계를 구축하는 문제일 뿐, 최종적으로 브라우저와 우리의 서비스 간에 이루어지는 통신을 어떻게 안전하게 보호할 것인가는 여전히 우리가 직접 설계하고 해결해야 할 핵심 과제이기 때문입니다.

실무 케이스의 전체적인 흐름을 따라가며 BFF가 구체적으로 어떤 역할을 하는지 살펴보겠습니다. 사용자가 브라우저에서 구글 로그인 버튼을 클릭하면, 브라우저가 직접 구글 서버와 통신하는 것이 아니라 먼저 우리의 BFF 서버로 요청을 보냅니다. 그러면 BFF가 사용자를 구글의 로그인 페이지로 리다이렉트 시키고, 사용자가 로그인을 완료하면 구글은 다시 우리의 BFF 서버로 인가 코드를 전달하게 됩니다.

여기서 OAuth 2.0 스펙이 정의하는 클라이언트의 두 가지 종류인 퍼블릭 클라이언트(Public Client)와 기밀 클라이언트(Confidential Client)의 개념이 중요해집니다. 브라우저처럼 모든 코드가 외부로 노출되는 환경을 퍼블릭 클라이언트라고 하고, 서버처럼 비밀키를 안전하게 숨길 수 있는 환경을 기밀 클라이언트라고 부릅니다. 만약 프론트엔드에서 직접 소셜 로그인을 처리한다면, 외부 프로바이더에게 인증 토큰을 받아오기 위해 반드시 필요한 클라이언트 시크릿 값 등이 브라우저의 네트워크 탭이나 자바스크립트 소스 코드에 그대로 노출되는 치명적인 보안 취약점이 발생하게 됩니다.

물론 최근에는 프론트엔드 같은 퍼블릭 클라이언트에서도 시크릿 없이 인가 코드를 안전하게 교환할 수 있는 PKCE(Proof Key for Code Exchange) 방식이 표준으로 자리 잡고 있기는 합니다. 하지만 PKCE를 사용하더라도 결국 발급받은 '액세스 토큰' 자체를 브라우저 어딘가에 저장해야 한다는 근본적인 보안 취약점은 고스란히 남게 됩니다. 따라서 이 과정을 BFF를 통해 처리하면, 브라우저는 단순히 화면 이동만 담당하고 실제 인가 코드를 사용해 토큰을 발급받는 민감한 네트워크 통신은 클라이언트 시크릿이 안전하게 숨겨진 서버 사이드, 즉 BFF 내부에서만 진행되므로 보안 수준이 비약적으로 상승합니다.

이렇게 BFF가 구글이나 카카오로부터 액세스 토큰과 리프레시 토큰을 성공적으로 발급받은 이후의 흐름도 매우 중요합니다. 만약 이 토큰들을 그대로 브라우저로 내려보내서 로컬 스토리지 등에 저장하게 만든다면, 이는 악의적인 스크립트가 브라우저 내의 데이터를 탈취하는 크로스 사이트 스크립팅(XSS) 공격의 아주 좋은 먹잇감이 되어버립니다.

바로 이 지점에서 BFF가 아주 우아하고 견고한 해결책을 제공합니다. BFF는 프로바이더로부터 받은 토큰이나 혹은 이를 바탕으로 우리 내부 백엔드에서 새로 발급한 자체 토큰을 브라우저에 절대 넘기지 않고, 자신의 서버 메모리나 레디스 같은 외부 캐시 시스템, 혹은 안전한 세션 스토리지에 보관합니다. 그 대신 브라우저에는 자바스크립트 코드가 절대 접근할 수 없도록 HttpOnly 속성과 Secure 속성이 엄격하게 부여된 세션 쿠키만을 발급하여 내려줍니다.

이때 쿠키를 사용하게 되면 XSS 공격은 완벽하게 방어할 수 있지만, 대신 크로스 사이트 요청 위조(CSRF) 공격에 노출될 수 있다는 점을 함께 고려해야 합니다. 이를 방어하기 위해 쿠키에 SameSite=Strict (또는 환경에 따라 Lax) 속성을 부여하거나, CSRF 토큰을 활용하는 아키텍처를 추가로 구성하게 됩니다.

이후 사용자가 브라우저를 통해 마이페이지 정보를 요청하거나 결제를 시도하는 등 API를 호출할 때마다 이 안전한 쿠키가 브라우저에 의해 자동으로 서버로 전송됩니다. 요청을 받은 BFF는 쿠키를 확인하여 자신이 안전하게 보관하고 있던 진짜 만능 키인 액세스 토큰을 꺼낸 뒤, 실제 비즈니스 로직을 처리하는 다운스트림 백엔드 API 서버로 요청을 대리하여 전달하는 프록시 역할을 완벽하게 수행하게 됩니다.

사용자가 서비스를 이용하다 보면 필연적으로 액세스 토큰의 유효 기간이 만료되는 순간이 찾아옵니다. 이때 리프레시 토큰을 이용해 새로운 토큰을 재발급받는 로직은 생각보다 매우 까다롭습니다. 프론트엔드에서 여러 개의 컴포넌트가 동시다발적으로 API 요청을 보내는 상황에서 토큰이 만료되었다면, 수많은 요청이 동시에 갱신을 시도하게 되어 충돌이 발생하는 이른바 경쟁 상태(Race Condition)에 빠질 수 있습니다. 이를 막기 위해 프론트엔드의 Axios 인터셉터 등에서 뮤텍스 락을 걸거나 요청들을 큐(Queue)에 담아두고 순차적으로 처리해야 하는 등 복잡한 제어가 필요해집니다.

이러한 무겁고 복잡한 비즈니스 로직을 리액트 컴포넌트 같은 프론트엔드 영역에 두는 것은 관심사 분리 원칙에 크게 어긋납니다. 하지만 BFF 아키텍처에서는 프론트엔드가 토큰의 만료 여부를 전혀 신경 쓸 필요가 없습니다. 백엔드 API가 토큰 만료 에러를 반환하면, 중간에 있는 BFF가 이를 가로채서 백그라운드 환경에서 즉각적으로 토큰 갱신 로직을 전담하여 처리합니다. 새로운 토큰을 성공적으로 받아 자신의 스토리지를 업데이트한 후, 실패했던 원래의 요청을 다시 백엔드로 보내어 정상적인 응답을 받아낸 뒤 프론트엔드에게 매끄럽게 전달해 줍니다. 프론트엔드 코드는 토큰이라는 존재 자체를 모른 채 오로지 사용자에게 보여줄 사용자 인터페이스 렌더링에만 온전히 집중할 수 있게 되는 것입니다.

마지막으로 데이터 정규화(Normalization) 과정에서의 이점도 빼놓을 수 없습니다. 구글, 카카오, 네이버 등 여러 소셜 로그인을 연동하다 보면 각 프로바이더가 반환해 주는 사용자 정보의 데이터 구조와 필드 이름이 모두 제각각이라는 것을 알게 됩니다. 이 정제되지 않고 파편화된 원본 데이터를 프론트엔드가 직접 받아서 조건문을 남발하며 파싱하고 처리하는 것은 유지보수 측면에서 매우 비효율적입니다. BFF는 이렇게 다양한 형태로 들어오는 응답 데이터를 프론트엔드가 화면에 그리기 딱 좋은 하나의 통일된 규격으로 예쁘게 정제하고 조립하여 넘겨주는 역할을 수행하여 프론트엔드의 부담을 크게 덜어줍니다.

최근 실무에서 많이 활용되는 넥스트제이에스(Next.js)의 라우트 핸들러(Route Handlers)나 서버 액션(Server Actions), 혹은 노드제이에스(Node.js) 기반의 서버 환경을 활용하여 BFF를 구성하고 계신다면, 현재 져니님이 설계하고 나아가는 방향이 아키텍처적으로 아주 정확하다고 말씀드리고 싶습니다. 외부 프로바이더에게 인증을 위임하더라도, 발급받은 토큰의 전체적인 수명 주기 관리와 브라우저 환경의 보안이라는 가장 중요하고 무거운 책임을 BFF가 가장 안전한 위치에서 통제하게 되는 것입니다.

탄탄한 컴퓨터 공학적 기반 지식과 네트워크 흐름에 대한 이해를 바탕으로 아키텍처를 설계하고 계시니, 분명 구조적으로 아주 훌륭하고 견고한 프로젝트가 완성될 것이라 확신합니다. 프로젝트를 진행하시면서 더 깊이 있는 고민이 생기거나 궁금한 점이 있다면 언제든지 편하게 질문 남겨주시길 바랍니다. 져니님의 멋진 프로젝트 완성을 진심으로 응원합니다.

참고해주세요!

0

communityai8509

안녕하세요, 인프런 AI 인턴입니다.
져니님, 수업을 잘 듣고 계신다니 기쁩니다. 인증/인가 관련하여 BFF(Backend for Frontend) 패턴과 관련된 질문을 주셨네요.

BFF 패턴은 프론트엔드와 백엔드 사이에서 중개 역할을 하여 보안과 성능을 개선할 수 있는 패턴입니다. 이 패턴은 특히 민감한 데이터나 인증 토큰을 직접 브라우저에 노출시키지 않도록 도와줍니다.

소셜 로그인을 도입하면, 인가 처리를 외부 제공자에게 위임하게 됩니다. 하지만, BFF는 여전히 유용할 수 있습니다. 이유는 다음과 같습니다:

  1. 토큰 관리: BFF는 액세스 토큰이나 리프레시 토큰을 서버 사이드에서 안전하게 관리합니다. 이렇게 하면 브라우저에 토큰이 노출되지 않아 보안성이 높아집니다.

  2. 보안 레이어 추가: BFF는 외부 API에 대한 요청을 프록시하며, 민감한 데이터가 직접 클라이언트에 노출되는 것을 방지할 수 있습니다.

  3. 통합 에러 처리: 외부 제공자와의 통신 중 발생할 수 있는 에러를 통합적으로 처리하여 사용자 경험을 개선할 수 있습니다.

  4. 추상화 레이어: 프론트엔드 코드에서는 외부 제공자의 구체적인 API가 노출되지 않기 때문에, 클라이언트 코드를 심플하게 유지할 수 있습니다.

따라서, 소셜 로그인과 같은 외부 인가 시스템을 도입하더라도 BFF는 보안성을 높이고, 아키텍처를 깔끔하게 유지하는 데 효율적입니다.

더 많은 정보를 원하시거나 세부 문서가 필요하시면 Spring Security 프로젝트 페이지를 참고할 수도 있습니다: Spring Security project page.

도움이 되셨기를 바랍니다! 추가적인 질문이 있다면 언제든지 문의해주세요.

Part2 자료에 대한 질문입니다.

0

10

1

createPointTransactionOfLoading 에러

0

17

1

강의 일정

0

26

2

Notion 권한 승인 요청 드립니다.

0

21

1

강의와는 별개로...

0

35

3

안녕하세요 유튜브 보고 재밌을꺼 같아서 강의 결제해서 보고잇습니다.

0

28

2

노션 열기에 도움이 필요합니다.

0

34

2

노션 파일 권한

0

32

2

좋은 강의 자료 감사합니다.

0

33

2

유튜브 영상보고 강의 등록하였습니다.

0

31

2

강의 내용 실습관

0

33

1

노션 파일 없음

0

27

3

한국투자 증권

0

39

2

52번 강의 질문입니다.

0

29

2

https://youtu.be/ziTLbsE9Cbc 유튜브 노션 링크 권한 부탁드립니다.

0

29

2

풀라우트캐시 동작 원리에서 데이터 캐시 관련 질문

0

32

2

훅 내용 안뜸 오류

0

32

2

next.js 프로젝트

0

33

1

40. 결제/주문 생성 및 업데이트 API 구축 이후로의 영상강의는 없나요

0

33

2

디스코드 소통창구는 없어졌나요 ??

0

41

2

20번강좌에 대한 질문입니다.

0

32

2

17강 zustand store 서버에서 생성

1

50

1

next.js 를 2대이상 실행하는 경우 제공하는 cache 기능들은 어떻게 되나요?

0

68

2

76. 전문성 더하기: 놓치면 아쉬운 관련 기술들 수업 자료가 없어요.

0

53

2