숙련된 개발자에게는 이 텍스트가 전혀 놀랍지 않을 수도 있지만, 제가 읽은 Rails의 CORS 설정에 관한 많은 글에서 랙-코어 사용, 모든 호스트의 API 액세스 허용, (선택적으로) 프로덕션에서는 (모든 호스트 허용과는) 다른 것을 고려해야 한다는 등의 내용을 담고 있다고 생각됩니다.
제안된 코드 는 항상 아래에 있는 것과 비슷했습니다:
config/initializers/cors.rb
Rails.application.config.middleware.insert_before 0, Rack::Cors do
허용하다
origins ''
resource '', headers: :any, methods: :any
end
end
안타깝게도 이러한 텍스트는 프로덕션에서 실제로 무엇을 해야 하는지에 대한 설명이 거의 없었습니다.
복사하여 붙여넣기해도 괜찮습니다(저는 가끔 회사에서 스택 오버플로를 복사하는 사람을 고용할 수 있다고 농담을 하곤 합니다.), '복사'와 '붙여넣기' 사이에 '생각하고 조정하는' 순간이 있습니다. 그래서 여기서 우리가 하는 일과 실제 작동 방식에 대해 조금 더 자세히 설명해 드리고자 합니다.
명예 이론에 대한 짧은 소개부터 시작해서 Rails 예제로 넘어가도 괜찮으시겠죠?
소개
처음부터 시작하겠습니다. 더 쉽게 설명하기 위해 소개를 세 부분으로 나누었습니다. 첫 번째 파트에서는 여기서 논의하는 내용의 핵심 용어인 오리진에 대해 간략하게 설명합니다. 두 번째는 SOP에 대한 간략한 설명입니다. 그리고 마지막 부분은 CORS
그 자체입니다.
오리진이란 무엇인가요?
MDN 웹 문서에 따르면
- 웹 콘텐츠의 오리진은 해당 콘텐츠에 액세스하는 데 사용되는 URL의 스키마(프로토콜), 호스트(도메인) 및 포트에 의해 정의됩니다. 스키마, 호스트, 포트가 모두 일치하는 경우에만 두 개체의 오리진이 동일합니다(출처)
꽤 명확해 보이지 않나요? 혹시 모를 경우를 대비하여 MDN의 두 가지 예를 분석해 보겠습니다.
http://example.com/app1/index.html
, http://example.com/app2/index.html
위의 두 가지의 기원이 같은 이유는 다음과 같습니다:
- 그들의 체계(http)는 동일합니다,
- 도메인(example.com)은 동일합니다,
- 포트(암시적)는 동일합니다.
http://www.example.com
, http://myapp.example.com
이 두 도메인의 출처가 다른 이유는 도메인(www.example.com
, myapp.example.com
)는 다릅니다.
충분히 이해하셨기를 바랍니다. 그렇지 않은 경우 MDN 웹 문서에서 더 많은 예제를 참조하세요.
SOP란 무엇인가요?
MDN 웹 문서에 따르면 (출처):
- 동일 출처 정책은 한 출처에서 로드된 문서 또는 스크립트가 다른 출처의 리소스와 상호 작용하는 방식을 제한하는 중요한 보안 메커니즘입니다. 잠재적으로 악의적인 문서를 격리하여 가능한 공격 경로를 줄이는 데 도움이 됩니다.
- 교차 출처 쓰기는 일반적으로 허용됩니다. 예를 들면 링크, 리디렉션, 양식 제출 등이 있습니다.
- 교차 출처 임베딩은 일반적으로 허용됩니다.
- 교차 출처 읽기는 일반적으로 허용되지 않지만 임베딩을 통해 읽기 액세스가 유출되는 경우가 종종 있습니다.
사용 CORS
를 사용하여 교차 출처 액세스를 허용합니다.
보시다시피 SOP의 정의에는 교차 출처 동작에 대한 내용이 많이 있습니다. 괜찮습니다. 이제 우리가 알아야 할 것은 동일한 오리진이 더 많은 권한을 가지며 CORS를 사용하여 교차 오리진에 대한 규칙을 완화할 수 있다는 것입니다. 이제 다음 섹션이 시작됩니다.
CORS란 무엇인가요?
MDN의 말을 근거로 합니다:
- CORS(교차 출처 리소스 공유)는 서버가 브라우저가 리소스 로드를 허용해야 하는 자체 출처가 아닌 다른 출처(도메인, 스키마 또는 포트)를 표시할 수 있도록 하는 HTTP 헤더 기반 메커니즘입니다. 또한 CORS는 서버가 실제 요청을 허용할지 확인하기 위해 브라우저가 교차 출처 리소스를 호스팅하는 서버에 '프리플라이트' 요청을 하는 메커니즘을 사용합니다. 이 프리플라이트에서 브라우저는 HTTP 메서드를 나타내는 헤더와 실제 요청에 사용될 헤더를 전송합니다. (출처).
그것만으로는 아직 충분하지 않습니다. 여기서 명시적으로 언급되지 않은 것은 사용 시 가장 중요한 헤더가 CORS
는 액세스-제어-허용-오리진
:
- 그리고
액세스-제어-허용-오리진
응답 헤더는 응답을 지정된 출처의 요청 코드와 공유할 수 있는지 여부를 나타냅니다(출처).
이 정도면 충분합니다. 실제로는 다음과 같이 구성할 때 CORS
를 사용하여 일반적으로 ACAO
헤더를 먼저 입력합니다.
실제 생활
정의에 관해서는 여기까지입니다. 다시 Rails와 실제 사례로 돌아가 보겠습니다.
레일즈에서 CORS를 구성하는 방법은 무엇인가요?
우리는 확실히 랙 코르를 사용할 것입니다 (우리가 들었던 것처럼). 다른 기사에서 가장 자주 제공되는 첫 번째 스니펫을 기억해 봅시다:
config/initializers/cors.rb
Rails.application.config.middleware.insert_before 0, Rack::Cors do
허용하다
origins ''
resource '', headers: :any, methods: :any
end
end
옵션의 수는 방대하거나 심지어 무한하지만 이 두 가지를 고려해 보겠습니다:
- 타사 브라우저 클라이언트에서 사용할 수 있는 API를 구축하고 있습니다,
- 일반적인 프론트엔드/백엔드를 분리하고 있으며 신뢰할 수 있는 클라이언트가 API에 액세스할 수 있도록 하려고 합니다.
타사 클라이언트가 액세스하는 빌딩 API
첫 번째 옵션에 직면한 경우 다음을 사용할 수 있습니다. 원산지
'*' - 다른 사람들이 API 상단에 클라이언트를 구축하기를 원하지만 그들이 누구인지 모르시죠?
일반적인 프론트엔드/백엔드 분리
후자를 개발하는 경우 모든 사람이 API에 교차 출처 요청을 하는 것을 원하지 않을 것입니다. 오히려 원할 수도 있습니다:
- 프로덕션 클라이언트가 프로덕션 API에 액세스할 수 있도록 허용합니다,
- 스테이징도 마찬가지입니다,
- 로컬호스트도 마찬가지입니다,
- 에서 FE 리뷰 앱이 스테이징에 액세스할 수 있도록 허용할 수 있습니다.
우리는 여전히 (우리가 들었던 대로) 랙 코르를 사용하겠지만, 우리 방식대로 할 것입니다.
2개의 환경 변수를 사용하겠습니다: 허용된_출처
문자 그대로의 출처 정의(별표 또는 실제 URL) 및 허용된_출처_regexps
패턴에 대해
config/initializers/cors.rb
냉동 문자열 리터럴: 참
toregexp = ->(문자열) { Regexp.new(문자열) }
hosts = [
*ENV.fetch('ALLOWEDORIGINS').split(','),
*ENV.fetch('ALLOWEDORIGINREGEXPS').split(';').map(&to_regexp)
]
Rails.application.config.middleware.insert_before 0, Rack::Cors do
허용하다
origins(*hosts)
리소스 '*',
메소드: %i[get post put patch delete options head],
headers: :any
end
end
여기서 무슨 일이 일어나고 있나요?
- 보시다시피, 환경 변수에 정의된 값을 다른 구분 기호로 나누고 있습니다. 이는 URL 정의 패턴에 세미콜론이 나타날 가능성이 적기 때문입니다.
- 리터럴 값은 바로 사용할 수 있지만 패턴을 실제 정규식 인스턴스로 매핑해야 합니다.
- 그런 다음 모든 것을 하나로 통합하고 이러한 호스트가 API에서 사용하는 화이트리스트 메소드를 통해 모든 리소스에 액세스할 수 있도록 허용합니다.
이를 통해 개발, 스테이징 및 프로덕션 환경에서 적절한 값을 정의할 수 있는 충분한 유연성을 확보할 수 있습니다.
결론
위의 모든 내용을 핵심 사항으로 요약해 보겠습니다:
- 환경 변수를 사용하여 구성
CORS
,
- 정규식을 사용하여 다양한 출처에서 스테이징 API에 액세스할 수 있도록 허용합니다(예: 리뷰 앱의 경우),
- 항상 '복사'와 '붙여넣기' 사이에 '생각 후 조정'을 넣으세요.
여기까지입니다. 좋은 하루 되세요! 🙂
자세히 읽어보세요:
타입스크립트를 사용해야 하는 이유는 무엇인가요?
2021년에 주목할 만한 뉴욕 스타트업 10곳