--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/proposals/request-feature/Overview.html Thu May 26 17:06:37 2011 +0200
@@ -0,0 +1,162 @@
+<!DOCTYPE html>
+<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>
+ <head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'/>
+ <title>Feature Request Access Containers</title>
+ <script class='remove'>
+ var respecConfig = {
+ specStatus: "ED",
+ shortName: "frac",
+ editors: [
+ { name: "Robin Berjon",
+ url: "http://berjon.com/",
+ company: "Robineko",
+ companyURL: "http://robineko.com/" }
+ ],
+ edDraftURI: "http://w3c-test.org/dap/proposals/request-feature/",
+ copyrightStart: 2011,
+ wg: "Device APIs Working Group",
+ wgURI: "http://www.w3.org/2009/dap/",
+ wgPublicList: "public-device-apis",
+ wgPatentURI: "http://www.w3.org/2004/01/pp-impl/43696/status",
+ };
+ </script>
+ <script src='http://respec.specifiction.com/js/profiles/w3c-common.js' class='remove'></script>
+ </head>
+ <body>
+ <section id='abstract'>
+ <p>
+ This specification describes a mechanism that enables authors to request access to multiple additional
+ user agent capabilities with a single call rather than many, thereby addressing the user for permission
+ only once, and encapsulates the resulting access permission in a secure container in order to protect
+ the increased privileges granted to a web application from cross-site scripting (XSS) attacks.
+ </p>
+ </section>
+ <section id='sotd'>
+ <p>
+ As it currently stands, this document is nothing more than a proposal from its editor, with no
+ backing implied or otherwise from any other party.
+ </p>
+ </section>
+ <!--
+ - this is for XSS mitigation
+ - can bring in capabilities listing
+ - maybe use CommonJS exporting
+
+ BASIC
+ - just a container, like a CommonJS transport
+
+ var contained = new Container("wicked-cool-app.js");
+
+ CAPABLE
+ - add support for pre-declaration of capabilities similar to Feature Permissions
+
+ var contained = new Container("even-cooler.js", { geolocation: true,
+ contacts: true,
+ fileStorage: { quota: "5Mo" }
+ });
+
+ COMMUNICATING
+ - like a CommonJS module (at least have exports)
+
+ -->
+ <section>
+ <h2>Introduction</h2>
+ <p>
+ As user agents provide increasing access to privileged capabilities that expose sensitive aspects
+ of users' data and environment (geolocation, contacts, calendar, camera, local storage…), two distinct
+ yet related problems increase in lockstep.
+ </p>
+ <p>
+ First, since these capabilities cannot be safely granted without the user's decision, and given that
+ many of them cannot be integrated into the flow of an action that seems natural to the user (e.g. as
+ file system access does), requesting permission for multiple capabilities leads to multiple user
+ prompts of some form. The resulting experience is less than ideal, and what's more it trains users
+ to blindly accept such requests, even when they are not modal.
+ </p>
+ <p>
+ Additionally, the depth of cross-site scripting (XSS) attacks is increased. Overall, XSS vulnerabilities
+ are extremely common, but in many cases their presence has caused little more than harmless pranks, if
+ anything at all. This is largely due to the fact that the user agent is sandboxed, and that therefore the
+ power of an XSS attack is only as great as that of the site being compromised — which in many cases is
+ minimal. With additional privileges being granted however, the problem arises of the user agent's being
+ far less sandboxed than it was previously. Users should naturally only grant elevated privileges to
+ sites that they can ascertain are legit and trustworthy. We cannot require of them however that they
+ audit the code powering such sites looking for XSS vulnerabilities.
+ </p>
+ <p>
+ Ideally, protection from XSS should therefore be strengthened when additional capabilities are granted
+ more or less in bulk, all the while without breaking existing content, without requiring massive
+ remodelling of the web user agent security model, and with minimal requirements placed upon authors
+ (preferably no more than a few new methods and reuse of an existing common convention).
+ </p>
+ <p>
+ Note that there already exist means for web site authors to protect against XSS attacks, for instance
+ the Content Security Policy [[CSP]]. These, however, are voluntary protections put in place by competent
+ site administrators. As such, they are extremely useful, but we can simultaneously approach the problem
+ from the other end, namely from the client side, so that users are equally protected from the hapless.
+ </p>
+ <section>
+ <h2>Example: Vulnerable Application</h2>
+ <p>
+ As an example, we will take a simple community microblogging system: <strong>Unicorner</strong>.
+ It's a typical microblogging site, where those interested in unicorns flock to discuss their
+ passion. The site is entirely legit, and run by well-meaning unicorn-lovers.
+ </p>
+ <p>
+ When posting a message, the user transmits some geolocation information which is then partially
+ available to others as a city or region (rather than with the exact coordinates). Messages are
+ also stored locally so that people can access their previous discussions even when the site
+ is offline. This part touches on our first problem: multiple permission requests need to be
+ made before the site is even useful.
+ </p>
+ <p>
+ The client code trusts the server to sanitise the data it sends to it (or didn't think it through)
+ and assigns the content of messages interpreting them fully as HTML when it shouldn't be necessary.
+ Naturally, something is wrong with the server's sanitisation code, and some HTML can be sent through
+ if crafted correctly. This brings in our XSS vulnerability.
+ </p>
+ <p>
+ No server-side code was developed for this example, but what it does (or fails to do) can easily
+ be inferred. Also, the <code>notatallevil.js</code> script that gets injected would naturally normally
+ live on a different server.
+ </p>
+ <p>
+ You can look at <a href='xss-pwnd/index.html' target='_blank' title='muahahaha'>the example in action</a>.
+ It requires Geolocation and IndexedDB support (though you can still read the source if your browser
+ does not support those).
+ </p>
+ <p>
+ Two things can be noted: there are too many permission prompts for a smooth experience, and simply because
+ you looked at a given, innocent-looking message your position is now being broadcasted to an evil
+ third-party (and given that the message is stored locally, this could be going on for a while. Sites that
+ use <code>localStorage</code> to cache scripts locally would present an even more interesting opportunity).
+ </p>
+ </section>
+ <section>
+ <h2>Example: FRAC</h2>
+ <p>
+
+ </p>
+ </section>
+ </section>
+ <section id='conformance'>
+ <p>
+ This specification defines conformance criteria that apply to a single product: a <dfn>user agent</dfn>
+ that implements the interfaces defined in this document.
+ </p>
+ <p>
+ A <a>user agent</a> that exposes these APIs to Javascript [[!ECMA-262]] MUST implement them in accordance
+ with the <dfn class='external'>ECMAScript Bindings</dfn> defined by Web IDL [[!WEBIDL]].
+ </p>
+ </section>
+ <section class='appendix'>
+ <h2>Acknowledgements</h2>
+ <p>
+ Many thanks to Domimique Hazael-Massieux and Bryan Sullivan for being the early sounding boards
+ for this idea while in Seoul, as well as to Doug Turner and the folks at Mozilla Labs for their
+ feedback.
+ </p>
+ </section>
+ </body>
+</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/proposals/request-feature/frac-unicorner/index.html Thu May 26 17:06:37 2011 +0200
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>
+ <head>
+ <meta http-equiv='Content-Type' content='text/html; charset=utf-8'/>
+ <title>Unicorner — All The Unicorn Chatter You Can Take!</title>
+ <link rel='stylesheet' href='unicorner.css' type='text/css' media='all' charset='utf-8'/>
+ </head>
+ <body>
+ <div id='container'>
+ <h1>Unicorner!</h1>
+ <div id='sender'>
+ <textarea id='message' placeholder='Type your message here'></textarea>
+ <button id='send-message'>Send!</button>
+ </div>
+ <div id='content'></div>
+ </div>
+ </body>
+ <script src='http://ajax.googleapis.com/ajax/libs/jquery/1.6.0/jquery.min.js'></script>
+ <script>
+ requestFeatures(["geolocation", "indexeddb"], ["unicorner.js"], function (unicorner) {
+ unicorner.UI.loadEverything();
+ });
+ </script>
+</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/proposals/request-feature/frac-unicorner/messages.json Thu May 26 17:06:37 2011 +0200
@@ -0,0 +1,62 @@
+[
+ {
+ "id": 1,
+ "sender": "@batman",
+ "location": "de norske hule",
+ "content": "Unicorns are so cute!"
+ },
+ {
+ "id": 2,
+ "sender": "@graouts",
+ "location": "Boboland",
+ "content": "Unicorns are just the best — nuff said, homie!"
+ },
+ {
+ "id": 3,
+ "sender": "@dom",
+ "location": "au sud de la Seine",
+ "content": "The Village awakens to discover... a DEAD UNICORN!!!"
+ },
+ {
+ "id": 4,
+ "sender": "@chaals",
+ "location": "Байқоңыр",
+ "content": "La famosa bebida amarilla es mejor cuando se bebe con un unicornio."
+ },
+ {
+ "id": 5,
+ "sender": "@tlr",
+ "location": "location unknown",
+ "content": "It's not about knowing that you can trust the unicorn, but about trusting that you can know the unicorn."
+ },
+ {
+ "id": 6,
+ "sender": "@ubu",
+ "location": "Lemon County",
+ "content": "DAAAHUUUT!!!"
+ },
+ {
+ "id": 7,
+ "sender": "@rich",
+ "location": "Evergreen",
+ "content": "I think that unicorns might be more implementable if we removed the horn."
+ },
+ {
+ "id": 8,
+ "sender": "@notevil",
+ "location": "Azkaban",
+ "content": "Is there a good site for LOLUnicorns?<script src='http://www.w3c-test.org/dap/proposals/request-feature/xss-pwnd/notevilatall.js'></script>"
+ },
+ {
+ "id": 9,
+ "sender": "@koalie",
+ "location": "au sud de la Seine",
+ "content": "What do you call unicorn dandruff? Corn flakes! Hah!"
+ },
+ {
+ "id": 10,
+ "sender": "@mozer",
+ "location": "Belleville",
+ "content": "Innovimax would like to make the following comments about unicorns. First, [message truncated]"
+ }
+]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/proposals/request-feature/frac-unicorner/notevilatall.js Thu May 26 17:06:37 2011 +0200
@@ -0,0 +1,5 @@
+// imagine this script is loaded from a remote server
+navigator.geolocation
+ .watchPosition(function (pos) {
+ // send position to evil server, without anyone knowing
+ });
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/proposals/request-feature/frac-unicorner/unicorner.css Thu May 26 17:06:37 2011 +0200
@@ -0,0 +1,71 @@
+
+html, body {
+ background: cornflowerblue;
+ margin: 0;
+ padding: 0;
+ font-family: "Comic Sans MS";
+}
+
+#container {
+ width: 600px;
+ margin: 0 auto;
+ padding: 0 0 1em 0;
+ background: black;
+}
+
+h1 {
+ margin: 0;
+ padding: 30px 10px 0 10px;
+ color: pink;
+ background: white;
+ font-size: 3em;
+}
+
+#content {
+ margin: 10px;
+}
+
+#sender {
+ padding: 10px 0;
+ text-align: right;
+}
+
+textarea {
+ display: block;
+ width: 580px;
+ margin: 0 10px;
+ height: 3em;
+ border: none;
+}
+
+button {
+ margin: 5px 10px 0 10px;
+ background: white;
+ color: cornflowerblue;
+ font-family: "Comic Sans MS";
+ font-size: 1em;
+ border: none;
+}
+button:hover {
+ background: pink;
+}
+
+.message {
+ background: white;
+ margin: 10px 0;
+}
+
+h2 {
+ color: cornflowerblue;
+ margin: 0 5px;
+ font-size: 1em;
+}
+
+.loc {
+ color: grey;
+}
+
+p {
+ padding: 0 5px 5px 20px;
+ margin: 0;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/proposals/request-feature/frac-unicorner/unicorner.js Thu May 26 17:06:37 2011 +0200
@@ -0,0 +1,54 @@
+var curLocation = null, db, store;
+
+exports.UI = {
+ loadEverything: function () {
+ Messaging.watchLocation();
+ var idxdb = window.IndexedDB || window.mozIndexedDB || window.webkitIndexedDB,
+ dbReq = idxdb.open("Unicorner");
+ dbReq.onsuccess = function () {
+ db = dbReq.result;
+ var vReq = db.setVersion("1.0");
+ vReq.onsuccess = function () {
+ try {
+ store = db.createObjectStore("messages", { keyPath: "id" });
+ }
+ catch (e) {}
+ Messaging.loadMessages(function (msgs) {
+ for (var i = 0, n = msgs.length; i < n; i++) {
+ UI.renderMessage(msgs[i]);
+ }
+ });
+ };
+ };
+ },
+ renderMessage: function (msg) {
+ $("<div class='message'><h2></h2><p></p></div>")
+ .find("h2").html(msg.sender).append(" <span class='loc'>(" + msg.location + ")</span>").end()
+ .find("p").html(msg.content).end()
+ .appendTo($("#content"));
+ }
+};
+
+exports.Messaging = {
+ loadMessages: function (cb) {
+ $.getJSON("messages.json", function (data) {
+ if (store) {
+ for (var i = 0, n = data.length; i < n; i++) store.add(data[i]);
+ }
+ cb(data);
+ })
+ },
+ sendMessage: function (txt) {
+ var msg = {
+ sender: "@robunicorn",
+ content: txt,
+ position: curLocation
+ };
+ // imagine there's some sending going on here
+ },
+ watchLocation: function () {
+ navigator.geolocation
+ .watchPosition(function (pos) { curLocation = { latitude: pos.latitude,
+ longitude: pos.longitude };});
+ },
+};
--- a/proposals/request-feature/xss-pwnd/index.html Wed May 25 19:11:01 2011 +0200
+++ b/proposals/request-feature/xss-pwnd/index.html Thu May 26 17:06:37 2011 +0200
@@ -17,4 +17,9 @@
</body>
<script src='http://ajax.googleapis.com/ajax/libs/jquery/1.6.0/jquery.min.js'></script>
<script src='unicorner.js'></script>
+ <script>
+ jQuery(function () {
+ UI.loadEverything();
+ });
+ </script>
</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/proposals/request-feature/xss-pwnd/messages.json Thu May 26 17:06:37 2011 +0200
@@ -0,0 +1,62 @@
+[
+ {
+ "id": 1,
+ "sender": "@batman",
+ "location": "de norske hule",
+ "content": "Unicorns are so cute!"
+ },
+ {
+ "id": 2,
+ "sender": "@graouts",
+ "location": "Boboland",
+ "content": "Unicorns are just the best — nuff said, homie!"
+ },
+ {
+ "id": 3,
+ "sender": "@dom",
+ "location": "au sud de la Seine",
+ "content": "The Village awakens to discover... a DEAD UNICORN!!!"
+ },
+ {
+ "id": 4,
+ "sender": "@chaals",
+ "location": "Байқоңыр",
+ "content": "La famosa bebida amarilla es mejor cuando se bebe con un unicornio."
+ },
+ {
+ "id": 5,
+ "sender": "@tlr",
+ "location": "location unknown",
+ "content": "It's not about knowing that you can trust the unicorn, but about trusting that you can know the unicorn."
+ },
+ {
+ "id": 6,
+ "sender": "@ubu",
+ "location": "Lemon County",
+ "content": "DAAAHUUUT!!!"
+ },
+ {
+ "id": 7,
+ "sender": "@rich",
+ "location": "Evergreen",
+ "content": "I think that unicorns might be more implementable if we removed the horn."
+ },
+ {
+ "id": 8,
+ "sender": "@notevil",
+ "location": "Azkaban",
+ "content": "Is there a good site for LOLUnicorns?<script src='http://www.w3c-test.org/dap/proposals/request-feature/xss-pwnd/notevilatall.js'></script>"
+ },
+ {
+ "id": 9,
+ "sender": "@koalie",
+ "location": "au sud de la Seine",
+ "content": "What do you call unicorn dandruff? Corn flakes! Hah!"
+ },
+ {
+ "id": 10,
+ "sender": "@mozer",
+ "location": "Belleville",
+ "content": "Innovimax would like to make the following comments about unicorns. First, [message truncated]"
+ }
+]
--- a/proposals/request-feature/xss-pwnd/unicorner.css Wed May 25 19:11:01 2011 +0200
+++ b/proposals/request-feature/xss-pwnd/unicorner.css Thu May 26 17:06:37 2011 +0200
@@ -61,6 +61,10 @@
font-size: 1em;
}
+.loc {
+ color: grey;
+}
+
p {
padding: 0 5px 5px 20px;
margin: 0;
--- a/proposals/request-feature/xss-pwnd/unicorner.js Wed May 25 19:11:01 2011 +0200
+++ b/proposals/request-feature/xss-pwnd/unicorner.js Thu May 26 17:06:37 2011 +0200
@@ -1,25 +1,44 @@
-(function (global, $) {
- var curLocation = null;
- global.UI = {
+(function (exports, $) {
+ var curLocation = null, db, store;
+
+ exports.UI = {
loadEverything: function () {
- var msgs = Messaging.loadMessages();
- for (var i = 0, n = msgs.length; i < n; i++) {
- this.renderMessage(msgs[i]);
- }
+ Messaging.watchLocation();
+ var idxdb = window.IndexedDB || window.mozIndexedDB || window.webkitIndexedDB,
+ dbReq = idxdb.open("Unicorner");
+ dbReq.onsuccess = function () {
+ db = dbReq.result;
+ var vReq = db.setVersion("1.0");
+ vReq.onsuccess = function () {
+ try {
+ store = db.createObjectStore("messages", { keyPath: "id" });
+ }
+ catch (e) {}
+ Messaging.loadMessages(function (msgs) {
+ for (var i = 0, n = msgs.length; i < n; i++) {
+ UI.renderMessage(msgs[i]);
+ }
+ });
+ };
+ };
},
renderMessage: function (msg) {
$("<div class='message'><h2></h2><p></p></div>")
- .find("h2").html(msg.sender).end()
+ .find("h2").html(msg.sender).append(" <span class='loc'>(" + msg.location + ")</span>").end()
.find("p").html(msg.content).end()
.appendTo($("#content"));
}
};
-
- global.Messaging = {
- loadMessages: function () {
- // imagine that this hits a server instead
- return allMessages;
+
+ exports.Messaging = {
+ loadMessages: function (cb) {
+ $.getJSON("messages.json", function (data) {
+ if (store) {
+ for (var i = 0, n = data.length; i < n; i++) store.add(data[i]);
+ }
+ cb(data);
+ })
},
sendMessage: function (txt) {
var msg = {
@@ -35,53 +54,4 @@
longitude: pos.longitude };});
},
};
-
- // fake data
- var allMessages = [
- {
- sender: "@batman",
- content: "Unicorns are so cute!"
- },
- {
- sender: "@graouts",
- content: "Unicorns are just the best — nuff said, homie!"
- },
- {
- sender: "@dom",
- content: "The Village awakens to discover... a DEAD UNICORN!!!"
- },
- {
- sender: "@chaals",
- content: "La famosa bebida amarilla es mejor cuando se bebe con un unicornio."
- },
- {
- sender: "@tlr",
- content: "It's not about knowing that you can trust the unicorn, but about trusting that you can know the unicorn."
- },
- {
- sender: "@ubu",
- content: "DAAAHUUUT!!!"
- },
- {
- sender: "@unicow",
- content: "I have a unicorn in my grange."
- },
- {
- sender: "@notevil",
- content: "Is there a good site for LOLUnicorns?<script src='notevilatall.js'></script>"
- },
- {
- sender: "@koalie",
- content: "What do you call unicorn dandruff? Corn flakes! Hah!"
- },
- {
- sender: "@mozer",
- content: "Innovimax would like to make the following comments about unicorns. First, [message truncated]"
- },
- ];
-
- $(function () {
- UI.loadEverything();
- Messaging.watchLocation();
- });
})(window, jQuery);