การเข้าถึง - การควบคุม - อนุญาต - Origin หลายโดเมน Origin?


1049

มีวิธีการอนุญาตให้ข้ามหลายโดเมนโดยใช้Access-Control-Allow-Originส่วนหัวหรือไม่

ฉันรู้เรื่อง*นี้ แต่มันเปิดเกินไป ฉันต้องการอนุญาตโดเมนเพียงสองสามข้อ

ตัวอย่างเช่นสิ่งนี้:

Access-Control-Allow-Origin: http://domain1.example, http://domain2.example

ฉันลองใช้รหัสด้านบนแล้ว แต่ดูเหมือนจะไม่ทำงานใน Firefox

เป็นไปได้หรือไม่ที่จะระบุหลายโดเมนหรือติดอยู่กับโดเมนเดียว?



3
การใช้ Firefox ล่าสุดไม่ได้คั่นด้วยเครื่องหมายจุลภาคหรือโดเมนแยกพื้นที่ทำงาน การจับคู่กับรายชื่อโดเมนและการวางโฮสต์เดียวไว้ในส่วนหัวยังคงมีความปลอดภัยที่ดีขึ้นและทำงานได้อย่างถูกต้อง
Daniel W.

1
หากคุณกำลังดิ้นรนกับ HTTPS นี้ผมพบว่าวิธีการแก้ปัญหา
Alex W

7
หมายเหตุสำคัญ : การอนุญาตให้สร้างเฉพาะโดเมนในAccess-Control-Allow-Originส่วนหัวไม่ได้หมายความว่าโดเมนอื่นไม่สามารถทริกเกอร์วิธีในจุดสิ้นสุดนี้ (เช่นวิธี REST API) หมายความว่าต้นกำเนิดที่ไม่อนุญาตไม่สามารถใช้ผลลัพธ์เป็น javascript ได้ (เบราว์เซอร์จะทำให้แน่ใจได้) สำหรับการ จำกัด การเข้าถึงปลายทางสำหรับโดเมนที่ระบุให้ใช้ตัวกรองคำขอฝั่งเซิร์ฟเวอร์ที่ส่งคืน HTTP 401 สำหรับโดเมนที่ไม่อนุญาต
klues

1
คุณควรต่อท้ายVary: Originหัวข้อเมื่อคุณต้องการใช้หลาย ๆ URL ดู: fetch.spec.whatwg.org/#cors-protocol-and-http-caches
Null

คำตอบ:


861

เสียงเหมือนวิธีที่แนะนำให้ทำคือให้เซิร์ฟเวอร์ของคุณอ่านส่วนหัว Origin จากไคลเอ็นต์เปรียบเทียบกับรายการโดเมนที่คุณต้องการอนุญาตและหากตรงกับนั้นให้สะท้อนค่าของOriginส่วนหัวกลับไปที่ไคลเอ็นต์เป็นAccess-Control-Allow-Originหัวในการตอบสนอง

ด้วย.htaccessคุณสามารถทำเช่นนี้

# ----------------------------------------------------------------------
# Allow loading of external fonts
# ----------------------------------------------------------------------
<FilesMatch "\.(ttf|otf|eot|woff|woff2)$">
    <IfModule mod_headers.c>
        SetEnvIf Origin "http(s)?://(www\.)?(google.com|staging.google.com|development.google.com|otherdomain.example|dev02.otherdomain.example)$" AccessControlAllowOrigin=$0
        Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
        Header merge Vary Origin
    </IfModule>
</FilesMatch>

41
สิ่งนี้ตรงกับสิ่งที่ W3C แนะนำ - w3.org/TR/cors/#access-control-allow-origin-response-hea
Simon B.

153
ปัญหาของฉันกับคำตอบนี้คือมันไม่ได้ช่วยฉันจริงๆเพราะเราใช้ CDN และแน่นอนว่าเราไม่สามารถควบคุมวิธีการตั้งค่าส่วนหัว CDN แบบเป็นโปรแกรม
BT

6
ตัวอย่างจริง (Nginx) ในคำตอบของฉันด้านล่าง - stackoverflow.com/a/12414239/6084
mjallday

71
หากแคชหรือ CDN เป็นข้อกังวลให้ใช้ส่วนหัว Varyเพื่อแจ้งแคช / CDN เพื่อเก็บการตอบกลับแยกต่างหากสำหรับค่าส่วนหัวคำขอ Origin ที่แตกต่างกัน คุณจะใส่หัวข้อเช่น "Vary: Origin" ในการตอบกลับของคุณ จากนั้นแคช / CDN รู้ว่าควรส่งการตอบกลับหนึ่งครั้งไปยังคำขอที่มีส่วนหัว "Origin: foo.example.com " และการตอบกลับที่แตกต่างจากคำขอที่มีหัวข้อ "Origin: bar.example.com "
Sean

10
@saturdayplace หากคุณสามารถเข้าถึงส่วนหัว Origin คุณจะผ่าน CORS
พอลเดรเปอร์

222

อีกวิธีที่ฉันใช้ใน PHP:

$http_origin = $_SERVER['HTTP_ORIGIN'];

if ($http_origin == "http://www.domain1.com" || $http_origin == "http://www.domain2.com" || $http_origin == "http://www.domain3.com")
{  
    header("Access-Control-Allow-Origin: $http_origin");
}

12
ทำไมไม่ใช้วิธีการที่แนะนำในstackoverflow.com/a/1850482/11635 [และอย่าส่งสัญลักษณ์ตัวแทนเพียงต้นกำเนิดที่ร้องขอ] นี่เป็นเพียงการอนุญาตมากขึ้นโดยไม่ประสบความสำเร็จอะไรอีกแล้ว?
Ruben Bartelink

15
header('Access-Control-Allow-Origin: *')บางครั้งมีการพูดว่าไม่สามารถใช้สัญลักษณ์เสริมหากธงประจำตัวเป็นจริง - เกิดขึ้นเมื่อheader('Access-Control-Allow-Credentials: true')อาจ ดังนั้นดีกว่าที่จะอนุญาตให้กำเนิด$http_originเองถ้าตรงตามเงื่อนไข
Rakib

6
แทนที่บรรทัดสุดท้ายด้วยheader("Access-Control-Allow-Origin: " . $http_origin);เพื่อให้สามารถใช้งานได้
François Romain

2
รหัสนี้ดูเหมือนว่ามีข้อบกพร่องซึ่งหากไม่มีการรับรู้ส่วนหัว HTTP_ORIGIN จะไม่มีการตั้งค่าการควบคุมการอนุญาตให้เข้าถึงได้เลยปล่อยให้สคริปต์เปิดกว้าง
สตีเฟ่นอาร์

9
@StephenR จริง ๆ แล้ว "wide close" จะมีความแม่นยำมากขึ้นเนื่องจากจุดประสงค์นี้คือการเปิดสคริปต์ไปยังโดเมนอื่น ๆ )
Kaddath

113

สิ่งนี้ใช้ได้กับฉัน:

SetEnvIf Origin "^http(s)?://(.+\.)?(domain\.example|domain2\.example)$" origin_is=$0 
Header always set Access-Control-Allow-Origin %{origin_is}e env=origin_is

เมื่อใส่เข้าไป.htaccessมันจะทำงานได้อย่างแน่นอน


24
ทางออกที่ดีที่สุดสำหรับฉัน แต่ฉันเพิ่มการสนับสนุนพอร์ต (เช่นlocalhost: 3000เพื่อการพัฒนา): SetEnvIf Origin "^ http (s)?: // (. + \.)? (localhost | stackoverflow.com | example1.com) ( : [0-9] +)? $ "origin_is = $ 0
vszurma

2
จากคำตอบหลาย ๆ คำตอบรอบ ๆ stackoverflow นี่เป็นคำตอบที่ใช้ได้
Meetai.com

ฉันต้องการที่จะเพิ่มHeader set Access-Control-Allow-Credentials trueสำหรับสิ่งนี้เพื่อให้ทำงานได้เหมือนคำตอบของ @George
99 ปัญหา - ไวยากรณ์ไม่ใช่หนึ่ง

ทำงานได้อย่างแน่นอนเมื่อฉันใช้ Origin แต่ในบางกรณี Origin ไม่มีให้บริการในบางคำขอและเป็นเบราว์เซอร์ที่เฉพาะเจาะจงเช่นกัน แล้วฉันตัดสินใจที่จะใช้แทนReferer Originการใช้Refererงาน แต่ปัญหาคือมันชุดกลับ URL แบบเต็มไปAccess-Control-Allow-Originผมต้องการที่จะตัดชื่อโดเมนออกจากและกำหนดให้Referer Access-Control-Allow-Originบางอย่างเช่นผลลัพธ์ของสิ่งนี้ - echo http://example.com/index.php/ab/cd | cut -d'/' -f1,2,3ในคำสั่ง bash เป็นไปได้ไหมที่จะทำเช่นเดียวกันในไฟล์ (apache) conf ความคิดใด ๆ
3AK

1
มันไม่ได้ผลสำหรับฉัน มีข้อผิดพลาดรหัส 500 เสมอเมื่อฉันเพิ่ม 2 บรรทัด ใช้จริง PHP 5.6.15
BoCyrill

91

ฉันมีปัญหาเดียวกันกับ woff-font หลายโดเมนย่อยต้องเข้าถึง หากต้องการอนุญาตให้ใช้โดเมนย่อยฉันได้เพิ่มสิ่งนี้ใน httpd.conf ของฉัน:

SetEnvIf Origin "^(.*\.example\.com)$" ORIGIN_SUB_DOMAIN=$1
<FilesMatch "\.woff$">
    Header set Access-Control-Allow-Origin "%{ORIGIN_SUB_DOMAIN}e" env=ORIGIN_SUB_DOMAIN
</FilesMatch>

สำหรับหลายโดเมนคุณสามารถเปลี่ยน regex SetEnvIfได้


4
ทำเคล็ดลับ เพียงให้แน่ใจว่าคุณปรับการแสดงออกปกติได้อย่างถูกต้อง ฉันต้องการที่จะเพิ่มเครื่องหมายคำถามเพื่อให้โดเมนของตัวเองเช่น(.*\.?example\.org)สำหรับและexample.com sub.example.com
trkoch

3
มีความคิดเห็นเกี่ยวกับวิธีการปรับใช้กับ IIS 7 หรือไม่
Mark

นั่นไม่ใช่การเอาชนะจุดประสงค์หรือไม่ อะไรจะป้องกันผู้ใช้ที่ประสงค์ร้ายไม่ให้ปลอมค่าส่วนหัวของ Origin
Grégory Joseph

1
@ GrégoryJoseph Access-Control-Allow-Origin ไม่ได้เกี่ยวกับการซ่อนทรัพยากรจากคนที่สามารถขอได้ เกี่ยวกับการป้องกันไซต์ที่เป็นอันตรายไม่ให้ผู้ใช้ปลายทางโทรหาไซต์ของคุณ ในกรณีของไฟล์แบบอักษรสิ่งนี้สามารถ จำกัด การเชื่อมโยงแบบอักษรร้อนแรงได้อย่างมีประสิทธิภาพเท่านั้นเหตุใดพวกเขา (mozilla / firefox) จึงไม่ได้ทำแบบเดียวกันกับทรัพยากรอื่น ๆ (js, css ฯลฯ ) อยู่นอกเหนือฉัน
Tracker1

@trkoch มีข้อผิดพลาดใน regex subexample.comของคุณก็ยังจะช่วยให้ คุณควรเปลี่ยนเป็น:((.*\.)?example\.org)
bluesmoon

65

ต่อไปนี้เป็นวิธีการสะท้อนส่วนหัว Origin กลับมาหากตรงกับโดเมนของคุณกับ Nginx สิ่งนี้มีประโยชน์หากคุณต้องการแสดงแบบอักษรหลายโดเมนย่อย:

location /fonts {
    # this will echo back the origin header
    if ($http_origin ~ "example.org$") {
        add_header "Access-Control-Allow-Origin" $http_origin;
    }
}

ไม่เข้าใจว่าสิ่งนี้แตกต่างจาก: add_header Access-Control-Allow-Origin *; สนใจที่จะอธิบาย?
Anoyz

สิ่งนี้จะส่งคืนส่วนหัวที่อนุญาตให้เบราว์เซอร์ส่งการร้องขอจากโดเมนที่ระบุเท่านั้น ถ้าฉันเดาฉันจะบอกว่าเบราว์เซอร์สามารถอนุญาตเนื้อหาจากโดเมนอื่นที่โหลดบนหน้านั้นเพื่อเข้าถึงเซิร์ฟเวอร์เป็นอย่างอื่น
mjallday

7
@Anoyz สำหรับสิ่งหนึ่งที่อาจมีการรักษาความปลอดภัยขั้นสูงที่ไม่อนุญาตให้ "อนุญาต *" แต่ชื่อโฮสต์ที่ระบุและการจับคู่สำหรับหัวข้อการอนุญาต ตัวอย่างที่นี่ถ้าคุณต้องการส่งข้อมูลการให้สิทธิ์ข้ามโดเมนคุณไม่สามารถใช้ "อนุญาต *"
TCC

3
เป็น.ใน example.org ตีความว่าเป็นค่าใด ๆ ตั้งแต่นี้คือการแสดงออกปกติ? ในกรณีนี้สิ่งนี้จะอนุญาตตัวอย่าง TLD ที่กำหนดเองโดยไม่ตั้งใจได้หรือไม่
stickj

1
regex ที่ถูกต้องควรเป็น"^example\.org$"เพราะคุณต้องทำให้แน่ใจว่าแฮ็กเกอร์ไม่สามารถส่งผ่าน regex ของคุณด้วยsubdomainexample.org(ใช้^) หรือexample.orgevil(ใช้$) หรือexamplezorg(หลบหนี\.)
#:

27

นี่คือสิ่งที่ฉันทำสำหรับแอปพลิเคชัน PHP ซึ่ง AJAX ร้องขอ

$request_headers        = apache_request_headers();
$http_origin            = $request_headers['Origin'];
$allowed_http_origins   = array(
                            "http://myDumbDomain.example"   ,
                            "http://anotherDumbDomain.example"  ,
                            "http://localhost"  ,
                          );
if (in_array($http_origin, $allowed_http_origins)){  
    @header("Access-Control-Allow-Origin: " . $http_origin);
}

หากเซิร์ฟเวอร์ของฉันอนุญาตให้ส่งคำขอต้นฉบับให้คืนค่า$http_originตัวเองเป็นค่าAccess-Control-Allow-Originส่วนหัวแทนที่จะส่งคืน*อักขระตัวแทน


20

มีข้อเสียอย่างหนึ่งที่คุณควรระวัง: ทันทีที่คุณส่งไฟล์ไปยัง CDN (หรือเซิร์ฟเวอร์อื่น ๆ ที่ไม่อนุญาตให้ใช้สคริปต์) หรือหากไฟล์ของคุณถูกแคชบนพร็อกซีให้เปลี่ยนการตอบสนองตาม 'Origin' ส่วนหัวคำขอจะไม่ทำงาน


4
คุณช่วยอธิบายรายละเอียดเกี่ยวกับเรื่องนี้หรือชี้เราไปที่ไหนสักแห่งที่เราสามารถหาข้อมูลเพิ่มเติมได้หรือไม่? ฉันต้องการทำสิ่งนั้นกับ Limelight และฉันหวังว่าคุณจะผิด หนึ่งในผู้ชำนาญการด้านเทคนิคของเรากล่าวว่าตราบใดที่เซิร์ฟเวอร์เมล็ดพันธุ์ CDN ของเราส่งส่วนหัว CDN เองก็จะส่ง ยังไม่ได้ทดสอบ
BT

12
หากแคชหรือ CDN เป็นข้อกังวลให้ใช้ส่วนหัว Vary เพื่อแจ้งแคช / CDN เพื่อเก็บการตอบกลับแยกต่างหากสำหรับค่าส่วนหัวคำขอ Origin ที่แตกต่างกัน คุณจะใส่หัวข้อเช่น "Vary: Origin" ในการตอบกลับของคุณ จากนั้นแคช / CDN รู้ว่าควรส่งการตอบกลับหนึ่งครั้งไปยังคำขอที่มีส่วนหัว "Origin: foo.example.com " และการตอบกลับที่แตกต่างจากคำขอที่มีหัวข้อ "Origin: bar.example.com "
Sean

Vary: Origin Akamai ไม่ได้รับการสนับสนุนซึ่งเป็นหนึ่งใน CDN ที่ใหญ่ที่สุดในนั้น ... รายละเอียดเพิ่มเติมที่นี่เช่นกัน
Brad Parks

20

สำหรับหลายโดเมนใน.htaccess:

<IfModule mod_headers.c>
    SetEnvIf Origin "http(s)?://(www\.)?(domain1.example|domain2.example)$" AccessControlAllowOrigin=$0$1
    Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
    Header set Access-Control-Allow-Credentials true
</IfModule>

4
ตัวอย่างนี้ทำงานได้อย่างสมบูรณ์แบบสำหรับฉัน แต่ฉันไม่เข้าใจว่ามันทำอะไร: D
Karl Adler

2
สิ่งนี้ใช้ได้ผลกับฉันแม้ว่าฉันจะต้องเพิ่ม '^' เช่น ... SetEnvIf Origin "^ http (s)?: // (www \.)?
gypsyDev

มันจะสวยมากเช่นเดียวกับstackoverflow.com/a/14034228/209139 เป็นเพียงไวยากรณ์. htaccess ที่อ่านยากกว่า PHP มาก Header set Vary Originคงจะเป็นส่วนเสริมที่ดีสำหรับคำตอบนี้
TRiG

1
ขอบคุณมากสำหรับความช่วยเหลือของคุณ
Cool Perfectionist

2
ผมได้มีการเปลี่ยนแปลงไปAccessControlAllowOrigin=$0$1 AccessControlAllowOrigin=$0มิฉะนั้นจะใช้ไม่ได้กับ HTTPS ต้นกำเนิด http://example.comออกมาอย่างถูกต้อง แต่https://example.comออกมาhttps://example.comsพร้อมกับพิเศษsในตอนท้าย
TRiG

17

สำหรับผู้ใช้ Nginx ให้อนุญาต CORS สำหรับหลายโดเมน ฉันชอบตัวอย่างของ @ marshall แม้ว่าคำตอบของเขาจะตรงกับโดเมนเดียวเท่านั้น เพื่อให้ตรงกับรายการโดเมนและโดเมนย่อย regex นี้ทำให้ง่ายต่อการทำงานกับแบบอักษร:

location ~* \.(?:ttf|ttc|otf|eot|woff|woff2)$ {
   if ( $http_origin ~* (https?://(.+\.)?(domain1|domain2|domain3)\.(?:me|co|com)$) ) {
      add_header "Access-Control-Allow-Origin" "$http_origin";
   }
}

สิ่งนี้จะสะท้อนเฉพาะส่วนหัว "Access-Control-Allow-Origin" ที่ตรงกับรายการโดเมนที่ระบุ


คิดว่าคุณต้องล็อค regex ท้ายด้วย \ z เพราะไม่เช่นนั้น domain3.com.badhacker.com จะอนุญาตให้เข้าถึงได้
dft

@dft เรากำหนด $ ณ จุดสิ้นสุดซึ่งทำเช่นนั้น
Adriano Rosa

ขออภัยฉันหมายถึงในตัวอย่างส่วนสำคัญโพสต์จริงโดย @AdrianoRosa ทำสิ่งเดียวกันกับ \ z
dft


13

ต่อไปนี้เป็นวิธีแก้ปัญหาสำหรับเว็บแอป Java ตามคำตอบจาก yesthatguy

ฉันใช้ Jersey REST 1.x

กำหนดค่า web.xml ที่ต้องระวัง Jersey REST และ CORSResponseFilter

 <!-- Jersey REST config -->
  <servlet>    
    <servlet-name>JAX-RS Servlet</servlet-name>
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param> 
        <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
        <param-value>true</param-value>
    </init-param>
    <init-param>
      <param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
      <param-value>com.your.package.CORSResponseFilter</param-value>
    </init-param>   
    <init-param>
        <param-name>com.sun.jersey.config.property.packages</param-name>
        <param-value>com.your.package</param-value>
    </init-param>        
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>JAX-RS Servlet</servlet-name>
    <url-pattern>/ws/*</url-pattern>
  </servlet-mapping>

นี่คือรหัสสำหรับ CORSResponseFilter

import com.sun.jersey.spi.container.ContainerRequest;
import com.sun.jersey.spi.container.ContainerResponse;
import com.sun.jersey.spi.container.ContainerResponseFilter;


public class CORSResponseFilter implements ContainerResponseFilter{

@Override
public ContainerResponse filter(ContainerRequest request,
        ContainerResponse response) {

    String[] allowDomain = {"http://localhost:9000","https://my.domain.example"};
    Set<String> allowedOrigins = new HashSet<String>(Arrays.asList (allowDomain));                  

    String originHeader = request.getHeaderValue("Origin");

    if(allowedOrigins.contains(originHeader)) {
        response.getHttpHeaders().add("Access-Control-Allow-Origin", originHeader);

        response.getHttpHeaders().add("Access-Control-Allow-Headers",
                "origin, content-type, accept, authorization");
        response.getHttpHeaders().add("Access-Control-Allow-Credentials", "true");
        response.getHttpHeaders().add("Access-Control-Allow-Methods",
                "GET, POST, PUT, DELETE, OPTIONS, HEAD");
    }

    return response;
}

}

ลิงก์ด้านบนหมดอายุแล้วคุณสามารถเพิ่มใหม่หรืออัปเดตคำตอบพร้อมรายละเอียดเพิ่มเติมขอบคุณ
RajKumar Samala

ฉันได้เพิ่มรายละเอียดหวังว่าจะช่วยได้
duvo

12

ดังกล่าวข้างต้นAccess-Control-Allow-Originควรไม่ซ้ำกันและVaryควรตั้งเป็นOriginหากคุณอยู่หลัง CDN (เครือข่ายการจัดส่งเนื้อหา)

ส่วนที่เกี่ยวข้องของการกำหนดค่า Nginx ของฉัน:

if ($http_origin ~* (https?://.*\.mydomain.example(:[0-9]+)?)) {
  set $cors "true";
}
if ($cors = "true") {
  add_header 'Access-Control-Allow-Origin' "$http_origin";
  add_header 'X-Frame-Options' "ALLOW FROM $http_origin";
  add_header 'Access-Control-Allow-Credentials' 'true';
  add_header 'Vary' 'Origin';
}

มีset $corsความหมายบางอย่างที่ซ่อนเร้นอยู่หรือเฉพาะเจาะจงกับ conifg ของคุณเท่านั้น ดูเหมือนว่ามันจะถูกละไว้ด้วยกันได้ครั้งที่สองif
mikezter

ถูกต้องมันสามารถละเว้นได้หากเป็นเงื่อนไขเดียวที่คุณทดสอบเพื่อตั้งค่าส่วนหัวฉันมีหลายอย่างในการกำหนดค่าของฉัน
hernvnc

9

บางทีฉันผิด แต่เท่าที่ฉันเห็นAccess-Control-Allow-Originมี"origin-list"พารามิเตอร์เป็น

โดยนิยามorigin-listคือ:

origin            = "origin" ":" 1*WSP [ "null" / origin-list ]
origin-list       = serialized-origin *( 1*WSP serialized-origin )
serialized-origin = scheme "://" host [ ":" port ]
                  ; <scheme>, <host>, <port> productions from RFC3986

และจากนี้ผมเถียงต้นกำเนิดที่แตกต่างกันมีการยอมรับและควรเป็นพื้นที่ที่แยกออกจากกัน


2
ดูเหมือนว่าจะเป็นการตีความข้อมูลจำเพาะที่ถูกต้อง ที่กล่าวว่าข้อมูลจำเพาะไม่ได้รับการสนับสนุนอย่างเต็มที่จากเบราว์เซอร์ปัจจุบัน (ตัวอย่างเช่นฉันเพิ่งทดสอบสิ่งนี้บน Firefox 17.0 และยืนยันว่าจะไม่ทำงาน)
Rick Riensche

7
ล ธ สเปคส่วน5.1 Access-Control-Allow-Origin Response Headerรัฐว่าต้นกำเนิดรายการเป็นข้อ จำกัด : แทนที่จะปล่อยให้รายการพื้นที่ที่คั่นของต้นกำเนิดของมันเป็นอย่างใดอย่างหนึ่งที่มาเดียวหรือสตริง "null ว่า"
maxpolk

2
ดังที่ฉันได้กล่าวถึงในความคิดเห็นเกี่ยวกับคำตอบของฉันนั่นเป็นส่วนหนึ่งของหมายเหตุผู้ดำเนินการไม่ใช่ข้อกำหนดของ RFC 2119 คำตอบ 'ถูกต้อง' อย่างแน่นอนคือการใช้ค่าที่คั่นด้วยช่องว่าง ปัญหาก็คือว่าการใช้งานไม่สมบูรณ์และดังนั้นคำตอบ 'ถูกต้อง' ไม่จำเป็นต้องทำงาน มันควร แต่ไม่ อย่างไรก็ตามในอนาคตเมื่อการใช้งานดีขึ้นอาจมีการเปลี่ยนแปลง
Bob Aman

8

สำหรับแอปพลิเคชัน ExpressJS คุณสามารถใช้:

app.use((req, res, next) => {
    const corsWhitelist = [
        'https://domain1.example',
        'https://domain2.example',
        'https://domain3.example'
    ];
    if (corsWhitelist.indexOf(req.headers.origin) !== -1) {
        res.header('Access-Control-Allow-Origin', req.headers.origin);
        res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
    }

    next();
});

นี้จะช่วยให้สายอื่น ๆ โดยเรียกร้องต่อไป ...
Ievgen Naida

@IevgenNaida งั้นเหรอ? มีปัญหาอะไร
eyecatchUp

7

ฉันพยายามตั้งค่านี้สำหรับโดเมนที่ใช้ HTTPS ดังนั้นฉันจึงคิดว่าฉันจะแบ่งปันวิธีแก้ปัญหา ฉันใช้คำสั่งต่อไปนี้ในไฟล์ httpd.confของฉัน:

    <FilesMatch "\.(ttf|otf|eot|woff)$">
            SetEnvIf Origin "^http(s)?://(.+\.)?example\.com$" AccessControlAllowOrigin=$0
            Header set Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
    </FilesMatch>

เปลี่ยนexample.comเป็นชื่อโดเมนของคุณ เพิ่มภายในนี้<VirtualHost x.x.x.x:xx>ของคุณในhttpd.confไฟล์ โปรดสังเกตว่าหากคุณVirtualHostมีคำต่อท้ายพอร์ต (เช่น:80) คำสั่งนี้จะไม่ใช้กับ HTTPS ดังนั้นคุณจะต้องไปที่/ etc / apache2 / sites-available / default-sslและเพิ่มคำสั่งเดียวกันในไฟล์นั้น ของ<VirtualHost _default_:443>ส่วน

เมื่ออัปเดตไฟล์กำหนดค่าแล้วคุณจะต้องเรียกใช้คำสั่งต่อไปนี้ในเทอร์มินัล:

a2enmod headers
sudo service apache2 reload

ฉันชอบตัวเลือกนี้และรวม / แก้ไขกับการใช้งานที่ @George มี บางครั้งเซิร์ฟเวอร์ไม่มี a2enmod ให้ใช้ดังนั้นสิ่งที่คุณต้องทำคือตรวจสอบ httpd.conf หลักของคุณเพื่อดูว่าบรรทัด: LoadModule headers_module modules / mod_headers.so นั้นไม่ได้แสดงความคิดเห็น
Mike Kormendy

ที่มาของฉันมีหมายเลขพอร์ตดังนั้นฉันจึงปรับเปลี่ยนนิพจน์ทั่วไปเพื่อรวม: ^http(s)?://(.+\.)?example\.com(:\d+)?$
indiv

5

หากคุณมีปัญหากับแบบอักษรให้ใช้:

<FilesMatch "\.(ttf|ttc|otf|eot|woff)$">
    <IfModule mod_headers>
        Header set Access-Control-Allow-Origin "*"
    </IfModule>
</FilesMatch>

3

แนวทางที่ยืดหยุ่นมากขึ้นคือการใช้นิพจน์ของ Apache 2.4 คุณสามารถจับคู่กับโดเมนพา ธ และตัวแปรคำขออื่น ๆ แม้ว่าการตอบกลับที่ส่งจะเป็นไปตลอดเวลา*ผู้ร้องขอเพียงรายเดียวเท่านั้นที่ได้รับการตอบรับนั้นเป็นผู้ตอบสนองความต้องการอยู่แล้ว การใช้Originส่วนหัวคำขอ (หรืออื่น ๆ ) ในนิพจน์ทำให้ Apache รวมโดยอัตโนมัติในVaryส่วนหัวของการตอบสนองดังนั้นการตอบสนองนั้นจะไม่ถูกนำมาใช้ซ้ำสำหรับแหล่งกำเนิดที่แตกต่างกัน

<IfModule mod_headers.c>
    <If "%{HTTP:Host} =~ /\\bcdndomain\\.example$/i && %{HTTP:Origin} =~ /\\bmaindomain\\.example$/i">
        Header set Access-Control-Allow-Origin "*"
    </If>
</IfModule>

2
ฉันมาที่นี่เพราะเบราว์เซอร์บางตัวไม่ยอมรับ*ข้อมูลรับรองเช่นล็อกอิน *ดังนั้นมันจะดีกว่าถ้าคุณผ่านการจับคู่ชื่อโฮสต์แทน
KeitelDOG

@KeitelDOG คนจะจับต้นกำเนิดที่ถูกต้องได้อย่างไรและส่งมันกลับมาเมื่อมีต้นกำเนิดหลายจุดแทนที่จะทำซ้ำรหัสสำหรับแต่ละโดเมน? ดูเหมือนว่าอาจเป็นไปได้ด้วยการแสดงออก แต่เอกสารไม่ชัดเจนสำหรับฉัน
Walf

ในความเป็นจริงปัญหาที่แท้จริงของฉันเป็นเพราะ laravel ไม่ส่งคืนAccess-Control-Allow-Originส่วนหัวสำหรับOPTIONSคำขอ preflight ที่ตรวจสอบส่วนหัวเพื่อดูว่าเซิร์ฟเวอร์อนุญาตจุดกำเนิดนี้หรือไม่ ฉันได้รับการแก้ไขแล้ว ดังนั้น*ไม่ใช่ปัญหาที่แท้จริงสำหรับฉัน แต่ยังคงเป็นเบราว์เซอร์บางคนไม่ยอมรับการ*มีสิทธิดังนั้นเมื่อ app เว็บจะส่งคำขอข้ามกำเนิดพวกเขาจะต้องระบุHTTP_ORIGINส่วนหัวที่คุณอาจเข้าถึงแบบไดนามิกที่มีตัวแปรOriginใน.htaccessสำหรับ Apache หรือ$_SERVER['HTTP_ORIGIN'];ใน PHP วิธีแก้ปัญหาของคุณดีไปเพราะอนุญาตให้ทุกจุดกำเนิด แต่ปลอดภัยน้อยกว่า
KeitelDOG

แต่สิ่งที่ควรจำไว้ 2 ประการคือ 1) การจัดหา*ให้ทุกสิ่ง 2) HOST นั้นแตกต่างจาก ORIGIN HOST คือ 'เป้าหมายเป้าหมาย' ที่ส่งผ่านไปยังส่วนหัวคำขอ แต่ ORIGIN เป็นที่ส่งคำขอไปยังINITIAL HOST TARGET HOSTดังนั้นในรหัสของคุณORIGIN HOSTจะถูกละเว้นและไม่เคยใช้ ดูคำตอบข้างต้นและคุณจะเห็นว่าพวกเขาใช้ค่าที่จะเพิ่มพวกเขาในORIGIN Access-Control-Allow-Origin
KeitelDOG

@KeitelDOG *ไม่อนุญาตให้ทุกคนเพราะใช้Originหัวข้อการร้องขอในการแสดงออกเป็นสาเหตุของ Apache จะผสานมันโดยอัตโนมัติในVaryส่วนหัวของการตอบสนองถ้าผู้ใดใช้req_novary('Origin')(มีแนวโน้มที่ไม่พึงประสงค์) เบราว์เซอร์รู้ว่าพวกเขาอาจได้รับการตอบสนองที่แตกต่างกันสำหรับสิ่งที่แตกต่างกันOriginและถ้าค่าที่ส่งไม่ผ่านการทดสอบAccess-Control-Allow-Originส่วนหัวจะไม่ถูกตั้งค่า
Walf

3

รหัส PHP:

$httpOrigin = isset($_SERVER['HTTP_ORIGIN']) ? $_SERVER['HTTP_ORIGIN'] : null;
if (in_array($httpOrigin, [
    'http://localhost:9000', // Co-worker dev-server
    'http://127.0.0.1:9001', // My dev-server
])) header("Access-Control-Allow-Origin: ${httpOrigin}");
header('Access-Control-Allow-Credentials: true');

2

HTTP_ORIGIN ไม่ได้ใช้โดยเบราว์เซอร์ทั้งหมด HTTP_ORIGIN ปลอดภัยแค่ไหน? สำหรับฉันมันว่างเปล่าใน FF
ฉันมีเว็บไซต์ที่อนุญาตให้เข้าถึงไซต์ของฉันส่งผ่าน ID ไซต์จากนั้นฉันตรวจสอบฐานข้อมูลของฉันสำหรับบันทึกด้วยรหัสนั้นและรับค่าคอลัมน์ SITE_URL (www.yoursite.com)

header('Access-Control-Allow-Origin: http://'.$row['SITE_URL']);

แม้ว่าการส่งผ่าน ID ไซต์ที่ถูกต้องการร้องขอจะต้องมาจากโดเมนที่แสดงในฐานข้อมูลของฉันที่เชื่อมโยงกับ ID ไซต์นั้น


2

ต่อไปนี้เป็นตัวเลือกเพิ่มเติมสำหรับ Apache ซึ่งมีคำจำกัดความแบบอักษรล่าสุดและที่วางแผนไว้บางส่วน:

<FilesMatch "\.(ttf|otf|eot|woff|woff2|sfnt|svg)$">
    <IfModule mod_headers.c>
        SetEnvIf Origin "^http(s)?://(.+\.)?(domainname1|domainname2|domainname3)\.(?:com|net|org)$" AccessControlAllowOrigin=$0$1$2
        Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
        Header set Access-Control-Allow-Credentials true
    </IfModule>
</FilesMatch>

2

เพื่ออำนวยความสะดวกในการเข้าถึงหลายโดเมนสำหรับบริการ ASMX ฉันได้สร้างฟังก์ชันนี้ในไฟล์ global.asax:

protected void Application_BeginRequest(object sender, EventArgs e)
{
    string CORSServices = "/account.asmx|/account2.asmx";
    if (CORSServices.IndexOf(HttpContext.Current.Request.Url.AbsolutePath) > -1)
    {
        string allowedDomains = "http://xxx.yyy.example|http://aaa.bbb.example";

        if(allowedDomains.IndexOf(HttpContext.Current.Request.Headers["Origin"]) > -1)
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", HttpContext.Current.Request.Headers["Origin"]);

        if(HttpContext.Current.Request.HttpMethod == "OPTIONS")
            HttpContext.Current.Response.End();
    }
}

วิธีนี้ช่วยให้ CORS สามารถจัดการOPTIONSกริยาได้เช่นกัน


2

ตัวอย่างโค้ด PHP สำหรับการจับคู่โดเมนย่อย

if( preg_match("/http:\/\/(.*?)\.yourdomain.example/", $_SERVER['HTTP_ORIGIN'], $matches )) {
        $theMatch = $matches[0];
        header('Access-Control-Allow-Origin: ' . $theMatch);
}

2

สำหรับการคัดลอก / วางที่ค่อนข้างง่ายสำหรับแอปพลิเคชั่น. NET ฉันเขียนสิ่งนี้เพื่อเปิดใช้งาน CORS จากภายใน global.asaxไฟล์ รหัสนี้เป็นไปตามคำแนะนำที่ให้ไว้ในคำตอบที่ยอมรับในปัจจุบันซึ่งสะท้อนให้เห็นถึงแหล่งกำเนิดใดก็ตามที่อยู่ในคำขอในการตอบกลับ สิ่งนี้จะบรรลุถึง '*' โดยไม่ต้องใช้

สาเหตุของการทำเช่นนี้คือมันเปิดใช้งานคุณสมบัติ CORS อื่น ๆรวมถึงความสามารถในการส่ง AJAX XMLHttpRequest ด้วยแอตทริบิวต์ 'withCredentials' ที่ตั้งค่าเป็น 'จริง'

void Application_BeginRequest(object sender, EventArgs e)
{
    if (Request.HttpMethod == "OPTIONS")
    {
        Response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
        Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
        Response.AddHeader("Access-Control-Max-Age", "1728000");
        Response.End();
    }
    else
    {
        Response.AddHeader("Access-Control-Allow-Credentials", "true");

        if (Request.Headers["Origin"] != null)
            Response.AddHeader("Access-Control-Allow-Origin" , Request.Headers["Origin"]);
        else
            Response.AddHeader("Access-Control-Allow-Origin" , "*");
    }
}

1

และอีกหนึ่งคำตอบใน Django ในการมีมุมมองเดียวอนุญาตให้ CORS จากหลายโดเมนนี่คือรหัสของฉัน:

def my_view(request):
    if 'HTTP_ORIGIN' in request.META.keys() and request.META['HTTP_ORIGIN'] in ['http://allowed-unsecure-domain.com', 'https://allowed-secure-domain.com', ...]:
        response = my_view_response() # Create your desired response data: JsonResponse, HttpResponse...
        # Then add CORS headers for access from delivery
        response["Access-Control-Allow-Origin"] = request.META['HTTP_ORIGIN']
        response["Access-Control-Allow-Methods"] = "GET" # "GET, POST, PUT, DELETE, OPTIONS, HEAD"
        response["Access-Control-Max-Age"] = "1000"  
        response["Access-Control-Allow-Headers"] = "*"  
        return response

1

เกตเวย์ AWS Lambda / API

สำหรับข้อมูลเกี่ยวกับวิธีกำหนดค่าต้นกำเนิดหลายจุดบน Serverless AWS Lambda และ API Gateway - แม้ว่าจะเป็นโซลูชันที่ค่อนข้างใหญ่สำหรับบางสิ่งที่ควรรู้สึกว่าตรงไปตรงมา - ดูที่นี่:

https://stackoverflow.com/a/41708323/1624933


ไม่สามารถกำหนดค่าต้นกำเนิดหลายรายการใน API เกตเวย์ได้ในขณะนี้ไม่สามารถดูได้ที่นี่: https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-cors-console.html ) แต่เป็นข้อเสนอแนะ (ใน คำตอบข้างต้น) คือ:

  • ตรวจสอบส่วนหัวของต้นฉบับที่ส่งโดยเบราว์เซอร์
  • ตรวจสอบกับบัญชีขาวของต้นกำเนิด
  • หากตรงกันให้ส่งคืน Origin ที่เข้ามาเป็นส่วนหัว Access-Control-Allow-Origin มิฉะนั้นส่งคืนตัวยึดตำแหน่ง (ต้นกำเนิดเริ่มต้น)

วิธีแก้ปัญหาง่ายๆคือทำให้ทุกอย่าง (*) เป็นเช่นนี้:

exports.handler = async (event) => {
    const response = {
        statusCode: 200,
        headers: {
            "Access-Control-Allow-Origin": "*",
            "Access-Control-Allow-Credentials" : true // Required for cookies, authorization headers with HTTPS
        },
        body: JSON.stringify([{

แต่การทำเช่นนี้จะดีกว่าในด้าน API เกตเวย์ (ดูลิงก์ที่ 2 ด้านบน)


2
Access-Control-Allow-Credentials: trueใช้สัญลักษณ์แทนAccess-Control-Allow-Origin: *ไม่ได้ ตั้งค่าเฉพาะ<origin>แทน
ทอม

@Tom ใช่แล้วไม่แน่ใจว่าทำไมที่อยู่ในนั้นฉันจำไม่ได้ แต่ฉันอาจคัดลอกมาจากค่าเริ่มต้นที่เพิ่มเข้ามาใน AWS? ขอบคุณสำหรับการชี้ให้เห็นว่า
timhc22

0

คำตอบการสนับสนุนของ Google ในการแสดงโฆษณาผ่าน SSLและไวยากรณ์ใน RFC นั้นดูเหมือนจะบ่งบอกว่าคุณสามารถเว้นวรรคคั่น URL ได้ ไม่แน่ใจว่ารองรับได้ดีแค่ไหนในเบราว์เซอร์ที่แตกต่างกัน


'การแสดงโฆษณาผ่าน ssl' ลิงก์ไปยังข้อมูลจำเพาะw3.org/TR/cors/#access-control-allow-origin-response-headerซึ่งเพิ่มหมายเหตุ "ในทางปฏิบัติการผลิตรายการแหล่งกำเนิดหรือโมฆะมีข้อ จำกัด มากกว่า แทนที่จะยอมให้มีรายการของต้นกำเนิดที่คั่นด้วยช่องว่างมันอาจเป็นจุดกำเนิดเดียวหรือสตริง "null"
spazm

ในขณะที่เป็นสิ่งสำคัญที่จะต้องทราบรายละเอียดนั้นเมื่อสเปคบอกว่า "ในทางปฏิบัติ" มันไม่ได้หมายความว่ามันเป็นเพียงที่ถูกต้องที่จะทำอย่างนั้น หมายความว่าหากคุณทำเช่นนั้นคุณอาจพบปัญหาเนื่องจากผู้ใช้งานส่วนใหญ่ใช้ข้อมูลจำเพาะไม่ถูกต้องหรือไม่สมบูรณ์ ข้อมูลจำเพาะไม่อนุญาตให้มีรายการของต้นกำเนิดที่คั่นด้วยช่องว่างซึ่งคุณสามารถดูได้ที่นี่ใน EBNF ภายใต้origin-list: tools.ietf.org/html/rfc6454#section-7.1
Bob Aman

0

หากคุณลองตัวอย่างโค้ดจำนวนมากเช่นฉันเพื่อให้มันทำงานโดยใช้ CORS มันมีค่าที่จะกล่าวถึงว่าคุณต้องล้างแคชก่อนเพื่อลองใช้งานได้จริงคล้ายกับปัญหาเช่นเมื่อภาพเก่ายังคงปรากฏแม้ว่าจะเป็น ลบบนเซิร์ฟเวอร์ (เพราะยังคงถูกบันทึกไว้ในแคชของคุณ)

ตัวอย่างเช่นCTRL + SHIFT + DELใน Google Chrome เพื่อลบแคชของคุณ

สิ่งนี้ช่วยฉันในการใช้รหัสนี้หลังจากลองใช้.htaccessวิธีแก้ปัญหาที่บริสุทธิ์มากมายและนี่ดูเหมือนจะเป็นงานเดียว

    Header add Access-Control-Allow-Origin "http://google.com"
    Header add Access-Control-Allow-Headers "authorization, origin, user-token, x-requested-with, content-type"
    Header add Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS"

    <FilesMatch "\.(ttf|otf|eot|woff)$">
        <IfModule mod_headers.c>
            SetEnvIf Origin "http(s)?://(www\.)?(google.com|staging.google.com|development.google.com|otherdomain.com|dev02.otherdomain.net)$" AccessControlAllowOrigin=$0
            Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
        </IfModule>
    </FilesMatch>

นอกจากนี้โปรดทราบว่ามีการแพร่กระจายอย่างกว้างขวางว่าโซลูชันจำนวนมากบอกว่าคุณต้องพิมพ์Header set ...แต่ก็เป็นHeader add ...เช่นนั้น หวังว่านี่จะช่วยให้คนที่มีปัญหาเหมือนกันบางชั่วโมงเหมือนฉัน


0

คำตอบด้านล่างเป็นคำเฉพาะสำหรับ C # แต่แนวคิดควรใช้กับแพลตฟอร์มที่แตกต่างกันทั้งหมด

ในการอนุญาตคำขอ Cross Origin จาก web api คุณจะต้องอนุญาตคำขอ Option ให้กับแอปพลิเคชันของคุณและเพิ่มคำอธิบายประกอบด้านล่างในระดับตัวควบคุม

[EnableCors (UrlString, ส่วนหัว, วิธีการ)] ตอนนี้ต้นกำเนิดสามารถส่งผ่านได้เป็นสตริงเท่านั้น ดังนั้นหากคุณต้องการที่จะส่งมากกว่าหนึ่ง URL ในคำขอผ่านมันเป็นค่าคั่นด้วยเครื่องหมายจุลภาค

UrlString = " https: //a.hello.com,https: //b.hello.com "


0

สามารถระบุแหล่งกำเนิดเดียวได้สำหรับส่วนหัว Access-Control-Allow-Origin แต่คุณสามารถตั้งค่าต้นกำเนิดในการตอบสนองของคุณตามคำขอ นอกจากนี้อย่าลืมตั้งค่าส่วนหัวแตกต่างกันไป ใน PHP ฉันจะทำสิ่งต่อไปนี้:

    /**
     * Enable CORS for the passed origins.
     * Adds the Access-Control-Allow-Origin header to the response with the origin that matched the one in the request.
     * @param array $origins
     * @return string|null returns the matched origin or null
     */
    function allowOrigins($origins)
    {
        $val = $_SERVER['HTTP_ORIGIN'] ?? null;
        if (in_array($val, $origins, true)) {
            header('Access-Control-Allow-Origin: '.$val);
            header('Vary: Origin');

            return $val;
        }

        return null;
    }

  if (allowOrigins(['http://localhost', 'https://localhost'])) {
      echo your response here, e.g. token
  }

-2

นอกจากนี้เรายังสามารถตั้งค่านี้ในไฟล์ Global.asax สำหรับแอปพลิเคชัน Asp.net

protected void Application_BeginRequest(object sender, EventArgs e)
    {

    // enable CORS
    HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "https://www.youtube.com");

    }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.