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