Specify Multiple Subdomains with Access Control Origin

后端 未结 7 861
爱一瞬间的悲伤
爱一瞬间的悲伤 2021-02-13 17:57

I am trying to allow access to every subdomain on my site in order to allow cross subdomain AJAX calls. Is there a way to specify all subdomains of a site like *.example.c

相关标签:
7条回答
  • 2021-02-13 18:28

    Here's how I did it.

    The Origin header is specified by the browser and will contain the domain that requested the script on the other domain:

    Origin: http://www.websiteA.com
    

    Therefore you can "whitelist" multiple domains in your server-side script:

    $allowedOrigins = [
        "http://www.websiteA.com",
        "https://www.websiteB.com"
        // ... etc
    ];
    

    What you can then do is check if the $_SERVER["HTTP_ORIGIN"] global contains a domain within that whitelist:

    if (in_array($_SERVER["HTTP_ORIGIN"], $allowedOrigins)) {
    

    And set the Access-Control-Allow-Origin response header to whatever Origin header value was:

    header("Access-Control-Allow-Origin: " . $_SERVER["HTTP_ORIGIN"]);
    

    Full script:

    $allowedOrigins = [
        "http://www.websiteA.com",
        "https://www.websiteB.com"
        // ... etc
    ];
    
    if (in_array($_SERVER["HTTP_ORIGIN"], $allowedOrigins)) {
        header("Access-Control-Allow-Origin: " . $_SERVER["HTTP_ORIGIN"]);
    }
    
    0 讨论(0)
  • 2021-02-13 18:29
    //Function to be called first in php file.
    function CORS_HEADERS_HANDLER(){
      if (isset($_SERVER['HTTP_ORIGIN'])){
        switch($_SERVER['HTTP_ORIGIN']){
            //Handle an IP address and Port
          case 'http://1.2.3.4:4200':
            header('Access-Control-Allow-Origin: http://1.2.3.4:4200');
            break;
            //Handle an Website Domain (using https)
          case 'https://www.someSite.com':
            header('Access-Control-Allow-Origin: https://www.someSite.com');
            break;
            //Handle an Website Domain (using http)
          case 'http://www.someSite.com':
            header('Access-Control-Allow-Origin: http://www.someSite.com');
            break;
            //Catch if someone's site is actually the reject being cheeky
          case 'https://not.you':
            header('Access-Control-Allow-Origin: https://nice.try');
            break;
            //Handle a rejection passing something that is not the request origin.
          default:
            header('Access-Control-Allow-Origin: https://not.you');
            break;
        }
      }else{
        header('Access-Control-Allow-Origin: https://not.you');
      }
      header('Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE, OPTIONS');
      header('Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token');
      header('Access-Control-Allow-Credentials: true');
      header('Content-Type: application/json; charset=utf-8');
      header("Cache-Control: public,max-age=3600");
      //if its an options request you don't need to proceed past CORS request.
      if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
        die();
      }
    }
    
    0 讨论(0)
  • 2021-02-13 18:32

    If you want wildcard domain, i think this is more efficient

    if(isset($_SERVER['HTTP_ORIGIN']) && preg_match('!^http(s)?://([a-z0-9\-]+\.)?example.com$!is', $_SERVER['HTTP_ORIGIN']))
    {
        header('Access-Control-Allow-Origin: '.$_SERVER['HTTP_ORIGIN']);
    }
    
    0 讨论(0)
  • 2021-02-13 18:35

    While the answer works, it does defeat the purpose of the whole thing, since it allows requests from any host.

    I use something like:

    if(isset($_SERVER['HTTP_ORIGIN'])) {
      $origin = $_SERVER['HTTP_ORIGIN'];
      if($origin == 'https://sub1.my-website.com' OR $origin == 'https://sub2.my-website.com') {
        header("Access-Control-Allow-Origin: $origin");
      }
    }
    
    0 讨论(0)
  • 2021-02-13 18:39

    The solution to this issue is to use the $_SERVER['HTTP_ORIGIN'] variable to determine whether the request has come from an allowed domain, and then conditionally set the Access-Control-Allow-Origin like so:

    $allowed_domains = [/* Array of allowed domains*/];
    
    if (in_array($_SERVER['HTTP_ORIGIN'], $allowed_domains)) {
        header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']);
    }
    
    0 讨论(0)
  • 2021-02-13 18:39

    This was my challenge and solution:

    1 - Backend PHP on api.example.com.

    2 - Multiple JS front ends such as one.example.com, two.example.com etc.

    3 - Cookies needed to be passed both ways.

    4 - AJAX call from multiple front-ends to PHP backend on api.example.com

    5 - In PHP, I do not prefer to use $_SERVER["HTTP_ORIGIN"], not always reliable/safe in my opinion (I had some browsers where HTTP-ORIGIN was always empty).

    The normal way to do this in PHP with single front end domain is starting PHP code with:

    header('Access-Control-Allow-Origin: https://one.example.com');  
    header('Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token');  
    header('Access-Control-Allow-Credentials: true');  
    

    And in JS on one.example.com domain:

    jQuery.ajax({
        url: myURL,
        type: "POST",
        xhrFields: {withCredentials: true},
        dataType: "text",
        contentType: "text/xml; charset=\"utf-8\"",
        cache: false,
        headers: "",
        data: myCallJSONStr,
        success: function(myResponse) {.....}
    

    However, this is not workable as I am using multiple subdomains to call my API domain.

    And this solution will NOT work as I want to pass on cookies:

    header('Access-Control-Allow-Origin: *');  
    

    It conflicts with the pass on cookie setting on the JS site:

    xhrFields: {withCredentials: true}
    

    Here is what I did:

    1 - use GET parameter to pass the Subdomain. 2 - Hardcode the Main domain in PHP so only (all) Subdomains are allowed.

    This is the JS/JQuery AJAX part of my solution:

    function getSubDomain(){
        
        let mySubDomain = "";
        
        let myDomain = window.location.host;
        let myArrayParts = myDomain.split(".");
        if (myArrayParts.length == 3){
            mySubDomain = myArrayParts[0];
        }
        
        return mySubDomain;
        
    }
    

    And in the AJAX call:

        let mySubDomain = getSubDomain();
        if (mySubDomain != ""){
            myURL += "?source=" + mySubDomain + "&end"; //use & instead of ? if URL already has GET parameters
        }
        
        jQuery.ajax({
            url: myURL,
            type: "POST",
            xhrFields: {withCredentials: true},
            dataType: "text",
            contentType: "text/xml; charset=\"utf-8\"",
            cache: false,
            headers: "",
            data: myCallJSONStr,
            success: function(myResponse) {.....}
    

    Finally, the PHP part:

    <?php
    
    $myDomain = "example.com";
    $mySubdomain = "";
    
    if (isset($_GET["source"])) {
        $mySubdomain = $_GET["source"].".";
    }
    
    $myDomainAllowOrigin = "https://".$mySubdomain.$myDomain;
    $myAllowOrigin = "Access-Control-Allow-Origin: ".$myDomainAllowOrigin;
    
    //echo $myAllowOrigin;
    
    header($myAllowOrigin);  
    header('Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token');  
    header('Access-Control-Allow-Credentials: true');
    

    IMPORTANT, don't forget to set the cookies for all subdomains, in this case the domain for the cookie would be: .example.com (so with a dot in front of the main domain):

    <?php
    
        //////////////// GLOBALS /////////////////////////////////
        
        $gCookieDomain = ".example.com";
        $gCookieValidForDays = 90;
        
        //////////////// COOKIE FUNTIONS /////////////////////////////////
        
        function setAPCookie($myCookieName, $myCookieValue, $myHttponly){
            global $gCookieDomain;
            global $gCookieValidForDays;
            
            $myExpires = time()+60*60*24*$gCookieValidForDays;
            setcookie($myCookieName, $myCookieValue, $myExpires, "/", $gCookieDomain, true, $myHttponly);   
            
            return $myExpires;
        }
    

    This solution allows me to call the API on api.example.com from any subdomains on example.com.

    NB. for situation where there is only a single calling subdomain, I prefer using .htaccess for setting CORS instead of PHP. Here is an example of .htaccess (linux/apache) for only one.example.com calling api.example.com:

    <IfModule mod_headers.c>
        Header set Access-Control-Allow-Origin "https://one.example.com"
        Header set Access-Control-Allow-Headers "Origin, Content-Type, X-Auth-Token"
        Header set Access-Control-Allow-Credentials "true"
    </IfModule>
    

    And place this .htaccess in the root of api.example.com.

    0 讨论(0)
提交回复
热议问题