추가 HTTP 요청 헤더 추가

파볼 드로타
Pavol Drotar

HTTP 요청에는 User-Agent, Content-Type과 같은 헤더가 포함됩니다. 브라우저에서 연결하는 헤더 외에도 Android 앱은 EXTRA_HEADERS 인텐트 추가 항목을 통해 쿠키 또는 리퍼러와 같은 헤더를 추가할 수 있습니다. 보안상의 이유로 Chrome은 인텐트가 실행되는 방식과 위치에 따라 일부 추가 헤더를 필터링합니다.

클라이언트와 서버의 소유자가 동일하지 않으므로 교차 출처 요청에는 추가 보안 레이어가 필요합니다. 이 가이드에서는 Chrome 맞춤 탭(브라우저 탭에서 URL을 여는 앱에서 실행된 인텐트)을 통해 이러한 요청을 실행하는 방법을 설명합니다. Chrome 83까지는 개발자가 맞춤 탭을 실행할 때 헤더를 추가할 수 있었습니다. 승인되지 않은 헤더는 보안 위험을 야기하므로 버전 83부터는 Chrome에서 승인 목록에 추가된 교차 출처 헤더를 제외한 모든 헤더를 필터링하기 시작했습니다. Chrome 86부터 서버와 클라이언트가 디지털 애셋 링크를 사용하여 관련되어 있는 경우 승인되지 않은 헤더를 교차 출처 요청에 연결할 수 있습니다. 이 동작은 다음 표에 요약되어 있습니다.

Chrome 버전 CORS 헤더 허용
Chrome 83 이전 승인 목록, 승인되지 않음
Chrome 83~85 승인 목록
Chrome 86 이상 디지털 애셋 링크가 설정된 경우 승인 목록에 추가됨, 승인되지 않음

표 1. 승인되지 않은 CORS 헤더 필터링

이 도움말에서는 서버와 클라이언트 간에 확인된 연결을 설정하고 이를 사용하여 승인 목록과 승인되지 않은 http 헤더를 전송하는 방법을 설명합니다. 코드의 맞춤 탭 인텐트에 추가 헤더 추가로 건너뛰어도 됩니다.

배경

승인 목록에 추가된 CORS 요청 헤더와 승인되지 않은 CORS 요청 헤더 비교

교차 출처 리소스 공유 (CORS)는 출처가 다른 웹 애플리케이션이 다른 출처의 리소스를 요청할 수 있게 해줍니다. CORS 승인 목록에 추가된 헤더 목록은 HTML 표준에서 유지관리됩니다. 승인 목록에 있는 헤더의 예는 다음 표에 나와 있습니다.

헤더 설명
수락-언어 고객이 이해하는 자연어를 광고합니다.
콘텐츠 언어 대상 언어 설명
콘텐츠 유형 리소스의 미디어 유형을 나타냅니다.

표 2: 승인된 CORS 헤더 예

승인 목록에 포함된 헤더는 민감한 사용자 정보를 포함하지 않고 서버가 잠재적으로 위험한 작업을 실행할 가능성이 낮기 때문에 안전한 것으로 간주됩니다.

승인되지 않은 헤더의 예는 다음 표에 나와 있습니다.

헤더 설명
Bearer-token 서버에서 클라이언트를 인증
출처 요청의 출처를 나타냅니다.
쿠키 서버에서 설정한 쿠키를 포함합니다.

표 3: 승인되지 않은 CORS 헤더의 예

HTML 표준에서는 승인되지 않은 헤더를 CORS 요청에 첨부하지 않는 것이 좋습니다. 서버는 교차 출처 요청에는 승인 목록에 있는 헤더만 포함한다고 가정합니다. 교차 출처 도메인에서 승인되지 않은 헤더를 전송하면 악성 서드 파티 앱이 Chrome (또는 다른 브라우저)에서 저장하고 요청에 첨부하는 사용자 쿠키를 오용하는 헤더를 만들 수 있습니다. 이 쿠키는 이전에는 불가능했던 악성 서버 트랜잭션을 인증할 수 있습니다.

CORS 승인 목록의 헤더를 맞춤 탭 요청에 연결

맞춤 탭은 맞춤설정된 브라우저 탭에서 웹페이지를 실행하는 특별한 방법입니다. 맞춤 탭 인텐트는 CustomTabsIntent.Builder()를 사용하여 만들 수 있습니다. BundleBrowser.EXTRA_HEADERS 플래그와 함께 사용하여 이러한 인텐트에 헤더를 연결할 수도 있습니다.

CustomTabsIntent intent = new CustomTabsIntent.Builder(session).build();

Bundle headers = new Bundle();
headers.putString("bearer-token", "Some token");
headers.putString("redirect-url", "Some redirect url");   
intent.intent.putExtra(Browser.EXTRA_HEADERS, headers);

intent.launchUrl(Activity.this, Uri.parse("http://www.google.com"));

Google에서는 언제든지 승인 목록의 헤더를 맞춤 탭 CORS 요청에 연결할 수 있습니다. 하지만 Chrome은 기본적으로 승인되지 않은 헤더를 필터링합니다. 브라우저마다 동작이 다를 수 있지만 개발자는 일반적으로 승인되지 않은 헤더가 차단되는 것을 예상해야 합니다.

승인되지 않은 헤더를 맞춤 탭에 포함하는 지원되는 방법은 먼저 디지털 액세스 링크를 사용하여 교차 출처 연결을 확인하는 것입니다. 다음 섹션에서는 이를 설정하고 필수 헤더로 맞춤 탭 인텐트를 실행하는 방법을 설명합니다.

맞춤 탭 인텐트에 추가 헤더 추가

승인되지 않은 헤더가 맞춤 탭 인텐트를 통해 전달되도록 하려면 작성자가 두 애플리케이션을 모두 소유하고 있는지 확인하는 Android와 웹 애플리케이션 사이에 디지털 애셋 링크를 설정해야 합니다.

공식 가이드에 따라 디지털 애셋 링크를 설정합니다. 링크 관계에는 'Delegate_permission/common.use_as_origin'을 사용합니다. 이는 링크가 확인되면 두 앱이 모두 동일한 출처에 속한다는 것을 나타냅니다.

추가 헤더가 있는 맞춤 탭 인텐트 만들기

맞춤 탭 인텐트를 만드는 방법에는 여러 가지가 있습니다. 라이브러리를 빌드 종속 항목에 추가하여 androidX에서 사용할 수 있는 빌더를 사용할 수 있습니다.

MULTI_LINE_CODE_PLACEHOLDER_1

인텐트를 빌드하고 헤더를 추가합니다.

MULTI_LINE_CODE_PLACEHOLDER_2

맞춤 탭 연결은 앱과 Chrome 탭 간에 CustomTabsSession를 설정하는 데 사용됩니다. 앱과 웹 앱이 동일한 출처에 속하는지 확인하려면 세션이 필요합니다. 디지털 애셋 링크가 올바르게 설정된 경우에만 인증이 통과됩니다.

CustomTabsClient.warmup()를 호출하는 것이 좋습니다. 이를 통해 브라우저 애플리케이션이 백그라운드에서 사전 초기화되고 URL 열기 프로세스의 속도가 빨라집니다.

MULTI_LINE_CODE_PLACEHOLDER_3

유효성 검사 후 인텐트를 실행하는 콜백 설정

CustomTabsCallback가 세션에 전달되었습니다. 출처 인증에 성공하면 이전에 만든 CustomTabsIntent를 실행하도록 onRelationshipValidationResult()를 설정합니다.

MULTI_LINE_CODE_PLACEHOLDER_4

맞춤 탭 서비스 연결 바인딩

서비스를 결합하면 서비스가 시작되고 연결의 onCustomTabsServiceConnected()가 결국 호출됩니다. 서비스를 적절하게 바인딩 해제하는 것을 잊지 마세요. 결합 및 결합 해제는 일반적으로 onStart()onStop() 활동 수명 주기 메서드에서 실행됩니다.

// Bind the custom tabs service connection.
// Call this in onStart()
CustomTabsClient.bindCustomTabsService(this,
    CustomTabsClient.getPackageName(MainActivity.this, null), connection);

// …
// Unbind the custom tabs service.
// Call this in onStop().
unbindService(connection);

데모 애플리케이션 코드

맞춤 탭 서비스에 관한 자세한 내용은 여기를 참고하세요. 작동하는 예시 앱은 android-browser-helper GitHub 저장소를 참조하세요.

요약

이 가이드에서는 맞춤 탭 CORS 요청에 임의의 헤더를 추가하는 방법을 설명했습니다. 승인된 헤더를 모든 맞춤 탭 CORS 요청에 연결할 수 있습니다. 승인되지 않은 헤더는 일반적으로 CORS 요청에서 안전하지 않은 것으로 간주되며 Chrome은 기본적으로 이를 필터링합니다. 원본이 동일하고 디지털 애셋 링크로 확인된 클라이언트와 서버에서만 연결할 수 있습니다.