동영상

F8 2015 세션부터 Jonathan Gross(조너선 그로스)와 Brent Dorman(브렌트 도먼)은 Facebook 로그인 통합의 보안을 강화하는 방법을 모색하고 있습니다.

앱 시크릿 코드

앱 시크릿 코드는 액세스 토큰을 생성하기 위해 일부 로그인 플로에서 사용되며 시크릿 코드 자체는 신뢰할 수 있는 사용자만 앱을 안전하게 사용할 수 있도록 합니다. 시크릿 코드를 사용하여 모든 앱 사용자 대신 API 요청을 수행할 수 있는 앱 액세스 토큰을 손쉽게 만들 수 있으므로 앱 시크릿 코드는 절대 손상되지 않아야 합니다.

그러므로 앱 시크릿 코드 또는 앱 액세스 토큰을 절대 코드에 포함해서는 안 됩니다.

최상의 보안을 제공하기 위해 앱의 서버에서만 직접 앱 액세스 토큰을 사용하는 것이 좋습니다. 네이티브 앱의 경우 앱에서 개발자의 서버와 통신한 다음, 서버에서 앱 액세스 토큰을 사용하여 Facebook에 API 요청을 보내는 것이 좋습니다. 이러한 이유로 앱 대시보드의 고급 설정에서 '앱 유형'이 Native/Desktop으로 설정되어 있으면 네이티브 앱에 바이너리의 앱 시크릿 코드 또는 앱 액세스 토큰이 포함되어 있다고 가정하고 앱 액세스 토큰으로 서명된 호출을 수행하지 못하도록 합니다. API는 액세스 토큰이 제공되지 않은 것처럼 작동합니다.

appsecret_proof를 통한 안전한 서버 측 호출

appsecret_proof 매개변수를 통해 서버 간에 이루어지는 Facebook API 호출에 서명하도록 하여 악성 코드와 스팸에 노출될 가능성을 줄일 수 있습니다. 앱 시크릿 코드 인증서는 액세스 토큰의 sha256 해시로, 앱 시크릿 코드를 키로 사용합니다. 앱 시크릿 코드는 앱 대시보드의 설정 > 기본에서 확인할 수 있습니다.

인증서 생성

다음의 코드 예시는 PHP에서의 호출을 나타냅니다.

$appsecret_proof= hash_hmac('sha256', $access_token.'|'.time(), $app_secret); 

일부 운영 체제와 프로그래밍 언어는 부동 소수점 타임스탬프를 반환합니다. 앱 시크릿 코드 인증서를 계산하기 전에 정수 값으로 변환하세요. 일부 프로그래밍 언어는 해시를 다이제스트 개체로 생성합니다. 해시를 16진수 개체로 표시하세요.

인증서 추가

결과를 appsecret_proof 매개변수로 추가합니다. 이때 appsecret_time은 앱 시크릿 코드를 각각의 호출에 해시할 때 사용하는 타임스탬프로 설정합니다.

curl \
  -F 'access_token=ACCESS-TOKEN' \
  -F 'appsecret_proof=APP-SECRET-PROOF' \
  -F 'appsecret_time=APP-SECRET-TIME' \
  -F 'batch=[{"method":"GET", "relative_url":"me"},{"method":"GET", "relative_url":"me/accounts"}]' \
  https://graph.facebook.com

타임스탬프가 표시된 앱 시크릿 코드 인증서는 5분이 지나면 만료된 것으로 간주되므로 각 그래프 API 호출을 보낼 때 새로운 인증서를 인라인으로 생성하는 것이 좋습니다.

인증서 요청

앱 대시보드의 설정 > 고급 섹션에서 보안 섹션으로 이동하여 앱 시크릿 코드 요청을 활성화하세요. 활성화된 경우 appsecret_proof가 포함된 API 호출만 허용됩니다.

단기 토큰 및 코드 플로를 통한 안전한 클라이언트 측 호출

일부 구성에서 앱은 여러 클라이언트에 걸쳐 장기 토큰을 재사용합니다. 이렇게 하지 마시고 대신 액세스 토큰 문서에 설명된 대로 코드 플로를 통해 생성된 단기 토큰을 사용하세요.

토큰 도용

토큰이 도용되는 과정을 이해하도록 네이티브 iOS 앱에서 API를 호출하려 한다고 가정하겠습니다. 그러나 이 앱에서는 직접 호출을 수행하는 대신 동일한 앱에서 소유한 서버와 통신한 다음 iOS SDK를 사용하여 생성된 토큰을 이 서버에 전달합니다. 그런 다음 서버에서 토큰을 사용하여 API를 호출합니다.

서버에서 토큰을 수신하는 데 사용하는 엔드포인트가 손상되었을 수 있고 완전히 다른 앱의 액세스 토큰을 전달할 수도 있습니다. 그러나 이와 같이 명백하게 안전하지 않은 상황으로부터 토큰을 보호하는 방법이 있습니다. 액세스 토큰은 현재 해당 토큰을 사용 중인 앱에서는 절대 전송하지 않으며, 대신 디버깅 엔드포인트를 사용하여 확인해야 합니다.

액세스 토큰 유효성을 정기적으로 확인

Facebook SDK를 사용하지 않을 경우 액세스 토큰이 유효한지 정기적으로 확인하세요. 액세스 토큰에는 정해진 만료일이 있지만 보안상의 이유로 토큰이 조기에 만료될 수 있습니다. 앱에서 Facebook SDK를 사용하지 않는다면 토큰의 유효성을 수시로 수동 검사(적어도 매일)하는 방법을 구현해 앱이 보안상의 이유로 조기에 만료된 토큰을 사용하지 않도록 하는 것이 매우 중요합니다.

State 매개변수

웹사이트에 Facebook 로그인 대화 상자를 사용하는 경우 state 매개변수는 사이트 간 요청 위조 공격으로부터 앱을 보호하는 고유 문자열입니다.

Strict 모드 활성화

Strict 모드에서는 부적절한 행위 주체가 리디렉션을 도용하지 못하도록 하여 앱을 안전하게 보호합니다. 모든 앱은 Strict 모드를 활성화해야 합니다.

앱 대시보드에서 Strict 모드를 설정하기 전에 Facebook 로그인 설정에서 다음 조치를 취해 현재 리디렉션 트래픽이 계속 작동하는지 확인합니다.

  • 앱에서 다이내믹 리디렉션 URI를 사용하는 경우 state 매개변수를 사용하여 다이내믹 정보를 제한된 수의 리디렉션 URI에 전달합니다. 그런 다음 각 제한된 리디렉션 URI를 유효한 OAuth 리디렉션 URI 리스트에 추가합니다.

  • 앱에서 제한된 수의 리디렉션 URI를 사용하는 경우 각 리디렉션 URI를 유효한 OAuth 리디렉션 URI 리스트에 추가합니다.

  • 앱에서 Facebook JavaScript SDK만 사용하는 경우 리디렉션 트래픽이 이미 보호되어 있습니다. 따라서 별도의 조치가 필요하지 않습니다.

이러한 조치를 취한 후 Strict 모드를 활성화하세요.

Strict 모드 작동 원리

Strict 모드에서는 유효한 OAuth 리디렉션 URI 리스트에서 정확히 일치하는 항목을 요구하여 리디렉션 URI가 도용되는 것을 방지합니다. 예를 들어 리스트에 www.example.com이 포함되어 있으면 Strict 모드에서는 www.example.com/token을 유효한 리디렉션으로 허용하지 않습니다. 또한 유효한 OAuth 리디렉션 URI 리스트에 없는 추가 쿼리 매개변수를 허용하지 않습니다.

HTTPS 사용

HTTPS에서는 암호화를 사용하므로 HTTP 대신 HTTPS를 인터넷 프로토콜로 사용합니다. HTTPS에서는 전송된 데이터를 비공개로 유지하고 도청 공격으로부터 보호합니다. 예를 들어 광고 또는 악성 코드를 도입하여 전송 중에 데이터가 조작되지 않도록 합니다.

2018년 10월 6일부터 모든 앱은 HTTPS를 사용해야 합니다.

Facebook 로그인에 사용하기 위해 JavaScript SDK 활성화하기

JavaScript SDK로 로그인 토글을 '예'로 설정하여 JavaScript SDK로 로그인하도록 지정하는 경우 SDK를 호스팅하는 페이지의 도메인이 JavaScript SDK에 허용된 도메인 리스트에 포함된 항목 중 하나와 일치해야 합니다. 이렇게 하면 승인된 도메인의 콜백에만 액세스 토큰이 반환됩니다. Facebook JavaScript SDK를 사용하는 인증 작업에는 https 페이지만 사용 가능합니다.

2021년 8월 10일까지 생성된 기존 JSSDK 통합의 경우 이 리스트는 현재 사용 방식에 따른 값으로 채워집니다. 따라서 별도의 조치가 필요하지 않습니다.

2021년 8월 10일 이후에 생성된 새로운 통합의 경우 이 리스트에 값을 추가해야 합니다.

앱의 JSSDK 도메인 필드가 *.으로 시작하는 URL을 포함하는 경우 추가 보안을 위해 절대 도메인 URL로 대체되도록 변경하시기 바랍니다.

리디렉션 URI 확인 작동 원리

오픈 리디렉션 공격은 부적절한 행위 주체가 로그인 요청에 권한 없는 redirect_uri 매개변수를 제공하여 액세스 토큰과 같은 민감한 정보가 리디렉션 URI의 쿼리 문자열 또는 프래그먼트를 통해 유출될 수 있는 경우에 발생합니다.

맞춤 설정 웹 통합의 경우 이러한 공격을 방지하기 위해 앱 설정에 권한 있는 리디렉션 URI를 제공해야 합니다. 로그인 요청이 처리되는 동안 redirect_uri 매개변수가 이 리스트에 있는 항목과 비교하여 확인됩니다. 모든 매개변수를 포함하여 전체 URI가 정확히 일치해야 합니다. 단, 선택적 state 매개변수의 값은 무시되므로 예외입니다.

앱 내 브라우저 및 JavaScript SDK

JavaScript SDK는 일반적으로 팝업 및 콜백을 사용하여 로그인을 완료합니다. 따라서 팝업을 제한하는 일부 앱 내 브라우저에서는 로그인이 실패할 수 있습니다. 이 경우 SDK가 자동으로 액세스 토큰을 사용하여 SDK를 호출한 페이지로의 리디렉션을 시도합니다. 이 리디렉션은 페이지의 전체 URI가 '유효한 OAuth 리디렉션 URI'에 나열되어 있는 경우에만 안전하게 수행될 수 있습니다.

웹 앱에서 앱 내 브라우저 시나리오가 중요하다면 '허용되는 도메인'에 로그인 페이지의 도메인을 추가하고 '유효한 OAuth 리디렉션 URI'에 전체 URI(경로 및 쿼리 매개변수 포함)를 추가해야 합니다. 앱에 로그인하는 URI에 여러 가지 버전이 있는 경우 '유효한 OAuth 리디렉션 URL' 리스트에 해당 항목 하나만 추가할 수 있도록 FB.login() 호출에 한 가지 옵션으로 fallback_redirect_uri를 수동으로 지정하면 됩니다.

Facebook 앱 설정 잠금

앱에서 사용하지 않는 인증 플로를 활성화 및/또는 비활성화하여 공격 범위를 최소화합니다.

  • 클라이언트 생성 토큰 또는 서버 제공 장기 토큰 대신 클라이언트에서 코드 생성 단기 액세스 토큰을 사용하세요. 코드 생성 단기 액세스 토큰 플로에서 앱 서버는 코드를 토큰으로 교환해야 합니다. 이는 브라우저에서 토큰을 얻는 것보다 더 안전합니다. 앱에서 보안을 더 강화하려면 가능할 때마다 이 플로를 사용해야 합니다. 앱에서 이 플로만 활성화하면 사용자의 컴퓨터에서 실행 중인 악성 코드가 악용할 액세스 토큰을 얻을 수 없습니다. 액세스 토큰 문서에서 자세히 알아보세요.

  • 앱에서 이 플로를 사용하지 않는 경우 클라이언트 OAuth 로그인을 비활성화하세요. 클라이언트 OAuth 로그인은 OAuth 클라이언트 토큰 플로를 사용하기 위한 전역 설정-해제 스위치입니다. 앱에서 Facebook 로그인 SDK를 포함하는 클라이언트 OAuth 플로를 사용하지 않는 경우 이 플로를 비활성화해야 합니다. 하지만 클라이언트 OAuth 로그인을 비활성화한 경우 액세스 토큰에 대한 권한을 요청할 수 없습니다. 이 설정은 앱 대시보드의 제품 > Facebook 로그인 > 설정 섹션에서 찾을 수 있습니다.

  • 웹 OAuth 플로를 비활성화하거나 리디렉션 허용 리스트를 지정하세요. 웹 OAuth 로그인 설정은 Facebook 웹 로그인 대화 상자를 사용하여 개발자의 웹사이트에 토큰을 반환하는 OAuth 클라이언트 토큰 플로를 활성화합니다. 이 설정은 앱 대시보드의 제품 > Facebook 로그인 > 설정 섹션에 있습니다. 맞춤 설정 웹 로그인 플로를 빌드하지 않거나 웹에서 Facebook 로그인 SDK를 사용하지 않는 경우 이 설정을 비활성화하세요.

  • HTTPS를 실행하세요. 이 설정에는 OAuth 리디렉션용 HTTPS가 필요하며, 여기에는 HTTPS 페이지에서만 발생하는 액세스 토큰을 반환하거나 요구하는 Facebook JavaScript SDK 호출이 필요합니다. 2018년 3월 이후에 새로 만든 모든 앱에는 이 설정이 기본적으로 포함되며, 2018년 10월 6일까지 기존의 모든 앱을 HTTPS URL만 사용하도록 마이그레이션해야 합니다. 대부분의 주요 클라우드 앱 호스트는 앱에 대한 TLS 인증서를 무료로 자동 구성해 줍니다. 앱을 자체 호스트하거나 호스팅 서비스에서 기본적으로 HTTPS를 제공하지 않는 경우 Let's Encrypt에서 도메인에 대한 무료 인증서를 얻을 수 있습니다.

  • 앱에서 이를 사용하지 않는 경우 포함(embed)된 브라우저 OAuth 플로를 비활성화하세요. 일부 데스크톱과 모바일 네이티브 앱에서는 포함(embed)된 웹 보기에서 OAuth 클라이언트 플로를 수행하여 사용자를 인증합니다. 앱에서 이를 수행하지 않으면 앱 대시보드의 제품 > Facebook 로그인 > 설정 섹션에서 해당 설정을 비활성화합니다.

  • 앱에서 이를 사용하지 않는 경우 모바일 SSO 플로를 비활성화하세요. 앱에서 iOS 또는 Android 로그인을 사용하지 않는 경우 설정 > 기본의 iOS 및 Android 섹션에서 'SSO' 설정을 비활성화하세요.

앱 대시보드에는 보안 문제를 일으킬 수 있는 공격 영역을 개발자가 차단할 수 있도록 하는 다음과 같은 여러 추가 설정이 있습니다.

  • 기본 > 앱 시크릿 코드 - 앱 시크릿 코드가 손상된 적이 있는 경우 여기에서 재설정할 수 있습니다.
  • 기본 > 앱 도메인 - 앱 대신 Facebook 로그인을 수행하는 데 사용할 수 있는 도메인과 하위 도메인을 잠그는 데 사용합니다.
  • 고급 > 앱 유형 - 모바일 또는 데스크톱용 네이티브 앱을 만들고 이 앱에 앱 시크릿 코드를 포함하는 경우, 이를 Native/Desktop으로 설정하여 앱이 디컴파일되지 않고 앱 시크릿 코드가 도난당하지 않도록 보호합니다.
  • 고급 > 서버 IP 허용 리스트 - 앱 시크릿 코드를 사용하여 그래프 API를 호출할 수 있는 IP 주소 리스트를 지정합니다. 이 범위 밖에서 앱 시크릿 코드를 사용하여 그래프 API를 호출하면 실패합니다. 사용자 액세스 토큰을 사용한 호출은 이 설정의 영향을 받지 않습니다.
  • 고급 > 업데이트 설정 IP 허용 리스트 - 이러한 앱 설정을 특정 범위로 수정할 수 있는 IP 주소를 잠급니다. 거주 지역의 브로드밴드에서 IP 허용 리스트를 설정합니다. IP 주소가 변경되면 앱 설정을 수정할 수 없게 됩니다.
  • 고급 > 업데이트 알림 이메일 - 앱 대시보드에서 앱 설정이 변경될 때마다 이메일 주소에 알립니다.
  • 고급 > 스트리밍 게시물 URL 보안 - 소유한 도메인으로 다시 연결되지 않는 URL을 앱에서 더 이상 공개하지 않도록 합니다. 이 기능은 유용하지 않을 수도 있습니다(특히 앱에서 다른 사이트에 링크를 공개하는 경우).