Home | History | Annotate | Download | only in articles
      1 <h1>Cross-Origin XMLHttpRequest</h1>
      2 
      3 
      4 <p id="classSummary">
      5 Regular web pages can use the
      6 <a href="http://www.w3.org/TR/XMLHttpRequest/">XMLHttpRequest</a>
      7 object to send and receive data from remote servers,
      8 but they're limited by the
      9 <a href="http://en.wikipedia.org/wiki/Same_origin_policy">same origin policy</a>.
     10 Extensions aren't so limited.
     11 An extension can talk to remote servers outside of its origin,
     12 as long as it first requests cross-origin permissions.</p>
     13 
     14 <h2 id="extension-origin">Extension origin</h2>
     15 <p>Each running extension exists within its own separate security origin. Without
     16 requesting additional privileges, the extension can use
     17 XMLHttpRequest to get resources within its installation. For example, if
     18 an extension contains a JSON configuration file called <code>config.json</code>,
     19 in a <code>config_resources</code> folder, the extension can retrieve the file's contents like
     20 this:</p>
     21 
     22 <pre>
     23 var xhr = new XMLHttpRequest();
     24 xhr.onreadystatechange = handleStateChange; // Implemented elsewhere.
     25 xhr.open("GET", chrome.extension.getURL('/config_resources/config.json'), true);
     26 xhr.send();
     27 </pre>
     28 
     29 <p>If the extension attempts to use a security origin other than itself,
     30 say http://www.google.com,
     31 the browser disallows it
     32 unless the extension has requested the appropriate cross-origin permissions.
     33 </p>
     34 
     35 <h2 id="requesting-permission">Requesting cross-origin permissions</h2>
     36 
     37 <p>By adding hosts or host match patterns (or both) to the
     38 <a href="declare_permissions.html">permissions</a> section of the
     39 <a href="manifest.html">manifest</a> file, the extension can request access to
     40 remote servers outside of its origin.</p>
     41 
     42 <pre>{
     43   "name": "My extension",
     44   ...
     45   <b>"permissions": [
     46     "http://www.google.com/"
     47   ]</b>,
     48   ...
     49 }</pre>
     50 
     51 <p>Cross-origin permission values can be fully qualified host names,
     52 like these:</p>
     53 
     54 <ul>
     55   <li> "http://www.google.com/" </li>
     56   <li> "http://www.gmail.com/" </li>
     57 </ul>
     58 
     59 <p>Or they can be match patterns, like these:</p>
     60 
     61 <ul>
     62   <li> "http://*.google.com/" </li>
     63   <li> "http://*/" </li>
     64 </ul>
     65 
     66 <p>
     67 A match pattern of "http://*/" allows HTTP access to all reachable domains.
     68 Note that here,
     69 match patterns are similar to <a href="match_patterns.html">content script
     70 match patterns</a>,
     71 but any path information following the host is ignored.</p>
     72 
     73 <p>Also note that access is granted both by host and by scheme. If an extension
     74 wants both secure and non-secure HTTP access to a given host or set
     75 of hosts, it must declare the permissions separately:</p>
     76 
     77 <pre>"permissions": [
     78   "http://www.google.com/",
     79   "https://www.google.com/"
     80 ]
     81 </pre>
     82 
     83 <h2 id="security-considerations">Security considerations</h2>
     84 
     85 <p>
     86 When using resources retrieved via XMLHttpRequest, your background page should
     87 be careful not to fall victim to <a
     88 href="http://en.wikipedia.org/wiki/Cross-site_scripting">cross-site
     89 scripting</a>.  Specifically, avoid using dangerous APIs such as the below:
     90 </p>
     91 <pre>background.html
     92 ===============
     93 var xhr = new XMLHttpRequest();
     94 xhr.open("GET", "http://api.example.com/data.json", true);
     95 xhr.onreadystatechange = function() {
     96   if (xhr.readyState == 4) {
     97     // WARNING! Might be evaluating an evil script!
     98     var resp = eval("(" + xhr.responseText + ")");
     99     ...
    100   }
    101 }
    102 xhr.send();
    103 
    104 background.html
    105 ===============
    106 var xhr = new XMLHttpRequest();
    107 xhr.open("GET", "http://api.example.com/data.json", true);
    108 xhr.onreadystatechange = function() {
    109   if (xhr.readyState == 4) {
    110     // WARNING! Might be injecting a malicious script!
    111     document.getElementById("resp").innerHTML = xhr.responseText;
    112     ...
    113   }
    114 }
    115 xhr.send();
    116 </pre>
    117 <p>
    118 Instead, prefer safer APIs that do not run scripts:
    119 </p>
    120 <pre>background.html
    121 ===============
    122 var xhr = new XMLHttpRequest();
    123 xhr.open("GET", "http://api.example.com/data.json", true);
    124 xhr.onreadystatechange = function() {
    125   if (xhr.readyState == 4) {
    126     // JSON.parse does not evaluate the attacker's scripts.
    127     var resp = JSON.parse(xhr.responseText);
    128   }
    129 }
    130 xhr.send();
    131 
    132 background.html
    133 ===============
    134 var xhr = new XMLHttpRequest();
    135 xhr.open("GET", "http://api.example.com/data.json", true);
    136 xhr.onreadystatechange = function() {
    137   if (xhr.readyState == 4) {
    138     // innerText does not let the attacker inject HTML elements.
    139     document.getElementById("resp").innerText = xhr.responseText;
    140   }
    141 }
    142 xhr.send();
    143 </pre>
    144 <p>
    145 Additionally, be especially careful of resources retrieved via HTTP.  If your
    146 extension is used on a hostile network, an network attacker (aka a <a
    147 href="http://en.wikipedia.org/wiki/Man-in-the-middle_attack">"man-in-the-middle"</a>)
    148 could modify the response and, potentially, attack your extension.  Instead,
    149 prefer HTTPS whenever possible.
    150 </p>
    151 
    152 <h3 id="interaction-with-csp">Interaction with Content Security Policy</h3>
    153 
    154 <p>
    155 If you modify the default <a href="contentSecurityPolicy.html">Content
    156 Security Policy</a> for apps or extensions by adding a
    157 <code>content_security_policy</code> attribute to your manifest, you'll need to
    158 ensure that any hosts to which you'd like to connect are allowed. While the
    159 default policy doesn't restrict connections to hosts, be careful when explicitly
    160 adding either the <code>connect-src</code> or <code>default-src</code>
    161 directives.
    162 </p>
    163