Access-Control-Allow-Origin 와일드 카드 하위 도메인, 포트 및 프로토콜


312

모든 하위 도메인, 포트 및 프로토콜에 CORS를 사용하려고합니다.

예를 들어 http://sub.mywebsite.com:8080/ 에서 https://www.mywebsite.com/으로 XHR 요청을 실행할 수 있기를 원합니다. *

일반적으로 원점 일치 요청을 활성화하고 싶습니다 (및 제한).

//*.mywebsite.com:*/*

답변:


207

DaveRandom의 답변을 바탕으로 , 나는 또한 Access-Control-Allow-Origin재 작성 규칙을 사용하지 않고 동일한 결과 ( 현재 특정 프로토콜 + 도메인 + 포트로 동적으로 설정 됨)를 생성하는 약간 더 간단한 Apache 솔루션을 발견했습니다 .

SetEnvIf Origin ^(https?://.+\.mywebsite\.com(?::\d{1,5})?)$   CORS_ALLOW_ORIGIN=$1
Header append Access-Control-Allow-Origin  %{CORS_ALLOW_ORIGIN}e   env=CORS_ALLOW_ORIGIN
Header merge  Vary "Origin"

그리고 그게 다야.

모든 하위 도메인 외에 상위 도메인 (예 : mywebsite.com)에서 CORS를 활성화하려는 사용자는 첫 번째 줄의 정규 표현식을 다음과 같이 간단히 바꿀 수 있습니다.

^(https?://(?:.+\.)?mywebsite\.com(?::\d{1,5})?)$.

참고 : 사양 준수 및 올바른 캐싱 동작을 Vary: Origin위해 비 CORS 요청 및 허용되지 않은 출처의 요청에 대해서도 CORS 지원 리소스에 대한 응답 헤더를 항상 추가 하십시오 ( 예제 참조 ).


1
우리는 거의 (Vary Origin이 아님)이었으며 방문자가 동일한 글꼴을 사용하여 여러 하위 도메인 사이를 이동할 때 나쁜 행동을했습니다. 글꼴과 access-control-origin 헤더도 캐시되었습니다. 요청이 허용 된 도메인 중 하나에서 온 경우 "Access-Control-Allow-Origin *"를 사용합니다. 어쩌면 이것은 이전에 없었던 "Vary Origin"으로 해결되었을 수도 있습니다 ... 이제는 추가되었습니다.
Erik Melkersson

2
주요 도메인 'mywebsite.com'에서는 작동하지 않습니다.
생물 .info

1
@pgmann, //Apache conf는 슬래시로 구분 된 정규 표현식을 사용하지 않기 때문에이 문맥에서 벗어날 필요 가 없습니다. Regexr은 슬래시가 구분 기호로 특별한 의미를 갖기 때문에 불평합니다.
Noyo

1
The 'Access-Control-Allow-Origin' header contains multiple values '^(https?://(?:.+.)?aerofotea.com(?::d{1,5})?)$', but only one is allowed. Origin 'http://local.aerofotea.com' is therefore not allowed access.
Aero Wang

3
이 코드를 어디에 배치합니까? .htaccess 또는 아파치 가상 호스트 설정?
Glen

252

CORS 사양은 전부 또는 아무것도 아닙니다. 그것은 단지 지원 *, null또는 정확한 프로토콜 + 도메인 + 포트 : http://www.w3.org/TR/cors/#access-control-allow-origin-response-header

서버는 정규식을 사용하여 오리진 헤더의 유효성을 검사해야하며 Access-Control-Allow-Origin 응답 헤더에서 오리진 값을 에코 할 수 있습니다.


7
@Dexter "null"은 "null"원점에 대한 응답으로 사용될 수 있습니다 (예 : file : // 스킴에서 CORS 요청을 할 때).
monsur

130
CORS 스펙이 OP의 정확한 유스 케이스를 지원하지 않을 것이라는 것은 매우 근시안적입니다 .
aroth

6
@aroth : 실제로이 스펙은 구현이 원하는 매칭 구문 을 사용할 수 있도록 허용하지 않습니다 . 이 유스 케이스를 지원하지 않는 구현에 대해서는 단지 근시안적입니다 . 즉, 서버에 지정하는 것은 ACAO 값이 아니라 후자는 프로토콜 세부 사항입니다. 내 가정은 원점을 되 찾아야하는 보안 시나리오가 있다고 가정하지만 순진한 구현은 "확인"이라고 말하여 작동합니다.
tne

3
2015 년 업데이트 :이 답변은 불완전하며 캐싱 문제를 일으킬 수 있으므로 유해한 것으로 간주해야합니다. 올바른 구현 (Apache의 경우) 및 설명은 아래의 답변을 참조하십시오 : stackoverflow.com/a/27990162/357774 . TNE가 지적 하듯 또한, @aroth은 사양 실제로 수행 : 영업의 정확한 사용 사례 수 w3.org/TR/cors/#resource-implementation을 . 이 답변에서 알 수 있듯이 구현하는 것은 서버에 달려 있습니다. 이것은 위에서 언급 한 답변에서 볼 수 있듯이 3 줄로 수행 할 수 있습니다.
Noyo

19
@Noyo-그때 나는 원래의 의미를 명확히 할 것이다. CORS 사양은 CORS를 구현 하는 모든 서버가 OP의 정확한 유스 케이스 에 대한 자동 내장 지원을 제공하기 위해 엄격하게 요구 하지는 않는다는 것은 매우 근거리입니다 . 사용자 정의 PHP 코드를 사용하여 자신의 shim을 작성하기 위해 각 개별 사용자에게 맡겨 두거나, 규칙을 다시 작성하거나, 무엇을했는지는 조각화, 버그 및 재해에 대한 레시피입니다. 서버 개발자는 그보다 더 잘 알아야합니다. 그렇지 않은 경우 CORS 사양에 따라야합니다.
aroth

59

편집 : 이 대신 @Noyo의 솔루션을 사용하십시오 . 로드시 더 단순하고 명확하며 성능이 훨씬 뛰어납니다.

역사적 목적만을위한 오리지널 답변 왼쪽.


나는이 문제를 해결하고 Apache와 작동하는 재사용 가능한 .htaccess (또는 httpd.conf) 솔루션을 생각해 냈습니다.

<IfModule mod_rewrite.c>
<IfModule mod_headers.c>
    # Define the root domain that is allowed
    SetEnvIf Origin .+ ACCESS_CONTROL_ROOT=yourdomain.com

    # Check that the Origin: matches the defined root domain and capture it in
    # an environment var if it does
    RewriteEngine On
    RewriteCond %{ENV:ACCESS_CONTROL_ROOT} !=""
    RewriteCond %{ENV:ACCESS_CONTROL_ORIGIN} =""
    RewriteCond %{ENV:ACCESS_CONTROL_ROOT}&%{HTTP:Origin} ^([^&]+)&(https?://(?:.+?\.)?\1(?::\d{1,5})?)$
    RewriteRule .* - [E=ACCESS_CONTROL_ORIGIN:%2]

    # Set the response header to the captured value if there was a match
    Header set Access-Control-Allow-Origin %{ACCESS_CONTROL_ORIGIN}e env=ACCESS_CONTROL_ORIGIN
</IfModule>
</IfModule>

그냥 설정 ACCESS_CONTROL_ROOT루트 도메인에 블록의 상단에 변수를 그리고 그것은 메아리 Origin:에서 클라이언트에 요청 헤더 값 다시 Access-Control-Allow-Origin:는 도메인과 일치하는 경우 응답 헤더 값을.

참고 또한 당신이 사용할 수 sub.mydomain.com는 AS ACCESS_CONTROL_ROOT그것은에 기원을 제한합니다 sub.mydomain.com*.sub.mydomain.com(도메인 루트가 될 필요가 없습니다 그것을 즉). 변경 가능한 요소 (프로토콜, 포트)는 정규식의 URI 일치 부분을 수정하여 제어 할 수 있습니다.


22

허용 된 답변을 따라갈 수 없기 때문에이 질문에 대답하고 있습니다.

  1. 정규식 그룹화는 성능 적중 이며 필요하지 않습니다.
  2. 기본 도메인과 일치 할 수 없으며 하위 도메인에서만 작동합니다.

예를 들어 http://mywebsite.com에 CORS 헤더를 보내지 않지만 http://somedomain.mywebsite.com/에 대해서는 작동합니다 .

SetEnvIf Origin "http(s)?://(.+\.)?mywebsite\.com(:\d{1,5})?$" CORS=$0

Header set Access-Control-Allow-Origin "%{CORS}e" env=CORS
Header merge  Vary "Origin"

사이트를 활성화하려면 위의 Apache 구성에서 "mywebsite.com"대신 사이트를 배치하면됩니다.

여러 사이트를 허용하려면

SetEnvIf Origin "http(s)?://(.+\.)?(othersite\.com|mywebsite\.com)(:\d{1,5})?$" CORS=$0

배포 후 테스트 :

다음 컬 응답에는 변경 후 "Access-Control-Allow-Origin"헤더가 있어야합니다.

curl -X GET -H "Origin: http://examplesite1.com" --verbose http://examplesite2.com/query

12

PHP 전용 솔루션이 필요했기 때문에 누군가가 필요로하는 경우를 대비하여. "* .example.com"과 같은 허용 된 입력 문자열을 사용하고 입력이 일치하면 요청 헤더 서버 이름을 반환합니다.

function getCORSHeaderOrigin($allowed, $input)
{
    if ($allowed == '*') {
        return '*';
    }

    $allowed = preg_quote($allowed, '/');

    if (($wildcardPos = strpos($allowed, '*')) !== false) {
        $allowed = str_replace('*', '(.*)', $allowed);
    }

    $regexp = '/^' . $allowed . '$/';

    if (!preg_match($regexp, $input, $matches)) {
        return 'none';
    }

    return $input;
}

다음은 phpunit 데이터 제공자의 테스트 사례입니다.

//    <description>                            <allowed>          <input>                   <expected>
array('Allow Subdomain',                       'www.example.com', 'www.example.com',        'www.example.com'),
array('Disallow wrong Subdomain',              'www.example.com', 'ws.example.com',         'none'),
array('Allow All',                             '*',               'ws.example.com',         '*'),
array('Allow Subdomain Wildcard',              '*.example.com',   'ws.example.com',         'ws.example.com'),
array('Disallow Wrong Subdomain no Wildcard',  '*.example.com',   'example.com',            'none'),
array('Allow Double Subdomain for Wildcard',   '*.example.com',   'a.b.example.com',        'a.b.example.com'),
array('Don\'t fall for incorrect position',    '*.example.com',   'a.example.com.evil.com', 'none'),
array('Allow Subdomain in the middle',         'a.*.example.com', 'a.bc.example.com',       'a.bc.example.com'),
array('Disallow wrong Subdomain',              'a.*.example.com', 'b.bc.example.com',       'none'),
array('Correctly handle dots in allowed',      'example.com',     'exampleXcom',            'none'),

1
+1, preg_quote()올바른 방법이기 때문에 사용하도록 편집 됨 ( .DNS 이름에 유효한 정규 표현식 메타 문자 preg_quote()
일지라도

1
none사양에 따라 헤더에 대해 의미 적으로 유효한 값이 아니거나 (또는 ​​적어도 의미하는 바를 수행하지 않음) 명확히해야합니다 . 따라서 return null;해당 분기에 대해 더 의미가있을 수 있으며이 경우 클라이언트에 헤더를 보내면 안되므로 호출자가 확인해야합니다.
DaveRandom

preg_quote()* 기호를 인용하므로 str_replace()예를 들어 고아 "\"를 남깁니다.
Christoffer Bubach

1
이것은 유용합니다. 내 사이트가 ajax에는 "www"가 있지만 permalink 구조에는 없다는 것을 깨달을 때까지 CORS 문제에 시간을 보냈습니다. 귀하의 솔루션이 문제의 위치를 ​​이해하고 나를 위해 해결하는 데 도움이되었습니다.
Sol

3

Access-Control-Allow-Origin.htaccess에서 설정하면 다음 작업 만 수행되었습니다.

SetEnvIf Origin "http(s)?://(.+\.)?domain\.com(:\d{1,5})?$" CRS=$0
Header always set Access-Control-Allow-Origin "%{CRS}e" env=CRS

나는 여러 가지 다른 제안 키워드를 시도 Header append, Header set, 아무도 일하지 키워드가 오래된 또는 유효하지 않은 경우 내가 아무 생각이 없지만, SO에 많은 답변에 제안 의 nginx .

내 완전한 해결책은 다음과 같습니다.

SetEnvIf Origin "http(s)?://(.+\.)?domain\.com(:\d{1,5})?$" CRS=$0
Header always set Access-Control-Allow-Origin "%{CRS}e" env=CRS
Header merge Vary "Origin"

Header always set Access-Control-Allow-Methods "GET, POST"
Header always set Access-Control-Allow-Headers: *

# Cached for a day
Header always set Access-Control-Max-Age: 86400

RewriteEngine On

# Respond with 200OK for OPTIONS
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ $1 [R=200,L]

2

"쿠키 도메인"(www.domain.tld)에서 글꼴을 읽을 때 정적 "쿠키가없는"도메인에서 Font Awesome과 비슷한 문제가 발생했으며이 게시물이 우리의 영웅이었습니다. 여기를 참조하십시오 : 어떻게 '누락 간 리소스 공유 (CORS) 응답 헤더'webfont 문제를 해결할 수 있습니까?

copy / paste-r 유형 (및 소품을 제공하기 위해)에 대해서는 모든 기부금에서 이것을 모아서 사이트 루트의 .htaccess 파일 맨 위에 추가했습니다.

<IfModule mod_headers.c>
 <IfModule mod_rewrite.c>
    SetEnvIf Origin "http(s)?://(.+\.)?(othersite\.com|mywebsite\.com)(:\d{1,5})?$" CORS=$0
    Header set Access-Control-Allow-Origin "%{CORS}e" env=CORS
    Header merge  Vary "Origin"
 </IfModule>
</IfModule>

매우 안전하고 우아합니다. 그것을 좋아하십시오 : 당신은 자원 도둑 / 핫 링크 유형의 서버 대역폭을 열 필요가 없습니다.

소품 : @Noyo @DaveRandom @ pratap-koritala

(이 답변을 수락 된 답변에 대한 의견으로 남기려고했지만 아직 그렇게 할 수는 없습니다)



0

원래 답변은 Apache 2.4 이전의 답변이었습니다. 그것은 나를 위해 작동하지 않았다. 다음은 2.4에서 작동하도록 변경 한 내용입니다. 이것은 yourcompany.com 의 모든 하위 도메인에 적용 됩니다.

SetEnvIf Host ^((?:.+\.)*yourcompany\.com?)$    CORS_ALLOW_ORIGIN=$1
Header append Access-Control-Allow-Origin  %{REQUEST_SCHEME}e://%{CORS_ALLOW_ORIGIN}e    env=CORS_ALLOW_ORIGIN
Header merge  Vary "Origin"

0

고아 가 정규식에서 끝나서 실제 호스트 (프로토콜 또는 포트에주의를 기울이지 않음) 만 비교 하기 위해 Lars의 답변을 약간 수정 \해야했으며 localhost프로덕션 도메인 이외의 도메인 을 지원하고 싶었습니다 . 따라서 $allowed매개 변수를 배열로 변경했습니다 .

function getCORSHeaderOrigin($allowed, $input)
{
    if ($allowed == '*') {
        return '*';
    }

    if (!is_array($allowed)) {
        $allowed = array($allowed);
    }

    foreach ($allowed as &$value) {
        $value = preg_quote($value, '/');

        if (($wildcardPos = strpos($value, '\*')) !== false) {
            $value = str_replace('\*', '(.*)', $value);
        }
    }

    $regexp = '/^(' . implode('|', $allowed) . ')$/';

    $inputHost = parse_url($input, PHP_URL_HOST);

    if ($inputHost === null || !preg_match($regexp, $inputHost, $matches)) {
        return 'none';
    }

    return $input;
}

다음과 같이 사용법 :

if (isset($_SERVER['HTTP_ORIGIN'])) {
    header("Access-Control-Allow-Origin: " . getCORSHeaderOrigin(array("*.myproduction.com", "localhost"), $_SERVER['HTTP_ORIGIN']));
}

0

내 경우에는 각도를 사용하여

내 HTTP 인터셉터에서

with Credentials: true.

요청 헤더에

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.