intro parts to the document; better XSS example; FRAC example
authorRobin Berjon <robin@berjon.com>
Thu, 26 May 2011 17:06:37 +0200
changeset 17 d86e235b145f
parent 16 b795ba1b2493
child 18 997b3750dcd1
intro parts to the document; better XSS example; FRAC example
proposals/request-feature/Overview.html
proposals/request-feature/frac-unicorner/index.html
proposals/request-feature/frac-unicorner/messages.json
proposals/request-feature/frac-unicorner/notevilatall.js
proposals/request-feature/frac-unicorner/unicorner.css
proposals/request-feature/frac-unicorner/unicorner.js
proposals/request-feature/xss-pwnd/index.html
proposals/request-feature/xss-pwnd/messages.json
proposals/request-feature/xss-pwnd/unicorner.css
proposals/request-feature/xss-pwnd/unicorner.js
--- /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);