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