쏙에는 커뮤니티 기능이 있습니다. 여기에 글을 남기고 댓글을 달며 우리 학교 학생들끼리 자유롭게 소통할 수 있죠.
커뮤니티 기능을 개발할 때 중요하게 고려해야 하는 점 중 하나는 바로 <b>보안</b>입니다.
커뮤니티 기능을 사용할 때 어떤 정보들이 서버를 오고가는지 살펴보며, 쏙이 사용자의 개인정보를 보호하기 위한 방법이 무엇인지 알아볼까요?
로그인
우선 커뮤니티를 사용하려면 로그인을 해야합니다.
쏙의 커뮤니티에서는 구글 로그인 방식을 제공하고 있습니다.
자체 회원가입 없이 구글 계정으로만 로그인을 지원하는 이유는 무엇일까요?
oAuth 2.0
OAuth 2.0을 사용한다면 대부분의 로그인, 개인정보 관리 책임을 타사(구글)에게 위임할 수 있게 됩니다.
쉽게 말하면 회원 기능의 관리를 구글에게 맡기는 거죠.
이렇게 되면 우선 회원가입 절차가 간편해집니다. 따로 아이디와 비밀번호를 입력해서 가입하지 않아도 기존에 가입해둔 구글 계정으로 바로 가입하고 로그인할 수 있습니다.
무엇보다 쏙처럼 소규모 프로젝트에서 자체 인증 서버를 구축하여 로그인 기능을 구현할 경우 보안이 상대적으로 취약할 수 밖에 없습니다.
구글과 같은 대기업에게 로그인 기능을 대신 맡기게 되면 비교적 높은 수준의 보안을 적용받을 수 있습니다.
oAuth의 구성요소는 다음과 같이 나눌 수 있습니다 (관심 없으면 지나가세요)
- Client : OAuth 2.0을 사용해 서드파티 로그인 기능을 구현할 자사 또는 개인 애플리케이션 서버(쏙 서비스)
- Recource Owner : 서드파티 애플리케이션(구글 등)에 이미 개인정보를 저장하고 있으며 Client가 제공하는 서비스를 이용하려는 사용자
- Resource Server : 사용자의 개인정보를 가지고있는 애플리케이션 (Google, Facebook, Kakao 등) 서버. Client는 Token을 이 서버로 넘겨 개인정보를 응답 받을 수 있음
- Authorization Server : 권한을 부여해주는 서버, 사용자는 이 서버로 ID, PW를 넘겨 Authorization Code를 발급 받을 수 있음 Client는 이 서버로 Authorization Code을 넘겨 Token을 발급 받을 수 있다.
회원정보 저장
이제 로그인된 사용자의 구글 계정에서 회원정보를 가져오게 됩니다.
신규 사용자인지 여부를 확인하고, 만약 신규 사용자라면 데이터베이스에 사용자의 회원정보를 저장하는 과정이 진행됩니다.
이러한 정보 유출을 방지 하기 위해서 로그인이 진행될 때, 사전에 승인된 도메인(사이트 주소)에서만 정상 진행되도록 설정되어 있습니다.
만약 공격자가 악성 코드가 포함된 타 도메인에서 로그인 작업을 요청할 경우 아예 사용자의 정보가 전송되지 않습니다.\
또한, 다른 사람이 내 회원 정보를 마음대로 수정하는 것을 방어하기 위해 데이터베이스에 쓰기 요청이 들어오면 현재 로그인된 사용자와 정보를 수정하려는 대상 사용자가 일치할 경우에만 요청을 승인합니다.
match /users/{userId}/{documents=**} { allow read, write: if request.auth != null && request.auth.uid == userId }
게시글 관리 권한
이제 로그인을 마쳤으니 커뮤니티에 게시글을 올려볼까요?
게시글 페이지에서는 글 작성자와 현재 사용자가 일치할 경우 상단에 삭제와 수정이 가능한 툴바가 표시되는데요.
공격자는 자신이 쓴 글이 아니지만 페이지의 HTML 소스코드를 임의로 편집해 아래와 같이
display:none
으로 숨겨진 툴바를 display:block
등으로 바꾸어 보이게 할 수 있습니다.
이러한 방식으로 만약 자신이 쓴 글을 다른 사람이 마음대로 수정하거나 삭제할 수 있다면 다양한 문제가 발생할 수 있습니다.이를 방지하기 위해 쏙은 데이터베이스 접근 권한을 제한하고 있습니다.
수정하거나 삭제하려는 대상 글의 작성자와 현재 로그인된 사용자가 일치하는지를 확인해 일치하지 않을 경우 모든 요청을 거부하도록 되어 있습니다.
match /board/{docID}/{documents=**} { allow read, write: if request.auth != null && request.auth.uid == get(/databases/$(database)/documents/board/$(docID)).data.userId; }
만약 공격자가 이러한 방식으로 공격을 시도할 경우
FirebaseError: Missing or insufficient permissions.
오류가 개발자 콘솔에 표시되고 수정이나 삭제 작업은 진행되지 않습니다.
댓글