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