summaryrefslogtreecommitdiffstats
path: root/chrome/common/extensions/docs/static/xhr.html
blob: a7be123f6357a4a0a7ce7b819fd6aaf44aa7b710 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
<div id="pageData-name" class="pageData">Cross-Origin XMLHttpRequest</div>

<!-- BEGIN AUTHORED CONTENT -->
<p id="classSummary">
Regular web pages can use the
<a href="http://www.w3.org/TR/XMLHttpRequest/">XMLHttpRequest</a>
object to send and receive data from remote servers,
but they're limited by the
<a href="http://en.wikipedia.org/wiki/Same_origin_policy">same origin policy</a>.
Extensions aren't so limited.
An extension can talk to remote servers outside of its origin,
as long as it first requests cross-origin permissions.</p>

<p class="note">
<b>Note:</b>
Content scripts can't directly make cross-origin requests.
However, a content script can
send a message to its parent extension
that asks the extension to make a cross-origin request.
For an example of this technique, see the
<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/howto/contentscript_xhr">contentscript_xhr example</a>.
</p>

<h2 id="extension-origin">Extension origin</h2>
<p>Each running extension exists within its own separate security origin. Without
requesting additional privileges, the extension can use
XMLHttpRequest to get resources within its installation. For example, if
an extension contains a JSON configuration file called <code>config.json</code>,
in a <code>config_resources</code> folder, the extension can retrieve the file's contents like
this:</p>

<pre>
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = handleStateChange; // Implemented elsewhere.
xhr.open("GET", chrome.extension.getURL('/config_resources/config.json'), true);
xhr.send();
</pre>

<p class="caution">
<b>Bug note:</b>
Until <a href="http://crbug.com/41024">bug 41024</a> is fixed,
the preceding code won't work.
</p>

<p>If the extension attempts to use a security origin other than itself,
say http://www.google.com,
the browser disallows it
unless the extension has requested the appropriate cross-origin permissions.
</p>

<h2 id="requesting-permission">Requesting cross-origin permissions</h2>

<p>By adding hosts or host match patterns (or both) to the
<a href="manifest.html#permissions">permissions</a> section of the
<a href="manifest.html">manifest</a> file, the extension can request access to
remote servers outside of its origin.</p>

<pre>{
  "name": "My extension",
  ...
  <b>"permissions": [
    "http://www.google.com/"
  ]</b>,
  ...
}</pre>

<p>Cross-origin permission values can be fully qualified host names,
like these:</p>

<ul>
  <li> "http://www.google.com/" </li>
  <li> "http://www.gmail.com/" </li>
</ul>

<p>Or they can be match patterns, like these:</p>

<ul>
  <li> "http://*.google.com/" </li>
  <li> "http://*/" </li>
</ul>

<p>
A match pattern of "http://*/" allows HTTP access to all reachable domains.
Note that here,
match patterns are similar to <a href="match_patterns.html">content script
match patterns</a>,
but any path information following the host is ignored.</p>

<p>Also note that access is granted both by host and by scheme. If an extension
wants both secure and non-secure HTTP access to a given host or set
of hosts, it must declare the permissions separately:</p>

<pre>"permissions": [
  "http://www.google.com/",
  "https://www.google.com/"
]
</pre>

<h2 id="security-considerations">Security considerations</h2>

<p>
When using resources retrieved via XMLHttpRequest, your background page should
be careful not to fall victim to <a
href="http://en.wikipedia.org/wiki/Cross-site_scripting">cross-site
scripting</a>.  Specifically, avoid using dangerous APIs such as the below:
</p>
<pre>background.html
===============
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://api.example.com/data.json", true);
xhr.onreadystatechange = function() {
  if (xhr.readyState == 4) {
    // WARNING! Might be evaluating an evil script!
    var resp = eval("(" + xhr.responseText + ")");
    ...
  }
}
xhr.send();

background.html
===============
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://api.example.com/data.json", true);
xhr.onreadystatechange = function() {
  if (xhr.readyState == 4) {
    // WARNING! Might be injecting a malicious script!
    document.getElementById("resp").innerHTML = xhr.responseText;
    ...
  }
}
xhr.send();
</pre>
<p>
Instead, prefer safer APIs that do not run scripts:
</p>
<pre>background.html
===============
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://api.example.com/data.json", true);
xhr.onreadystatechange = function() {
  if (xhr.readyState == 4) {
    // JSON.parse does not evaluate the attacker's scripts.
    var resp = JSON.parse(xhr.responseText);
  }
}
xhr.send();

background.html
===============
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://api.example.com/data.json", true);
xhr.onreadystatechange = function() {
  if (xhr.readyState == 4) {
    // innerText does not let the attacker inject HTML elements.
    document.getElementById("resp").innerText = xhr.responseText;
  }
}
xhr.send();
</pre>
<p>
Additionally, be especially careful of resource retrieved via HTTP.  If your
extension is used on a hostile network, an network attacker (aka a <a
href="http://en.wikipedia.org/wiki/Man-in-the-middle_attack">"man-in-the-middle"</a>)
could modify the response and, potentially, attack your extension.  Instead,
prefer HTTPS whenever possible.
</p>

<!-- END AUTHORED CONTENT -->