Thursday 30 June 2011
Permissions For Web Applications
Summary The permissions model we have evolved for Web applications so far is mostly on the right track; introducing Android-like bundling of permissions with "up front" permission grants would be a mistake.
Traditionally Web applications are untrusted, treated as potentially malicious, and hence "sandboxed" to deny them the ability to affect the user's system or access user data. As we add capabilities to the Web platform, we sometimes encounter situations where legitimate applications want functionality that must be denied to malicious applications. A natural solution is to ask the user whether such requests should be permitted. Long ago we learned that modal requests --- interrupting the application with a warning, and forcing the user to OK/Cancel before proceeding any further --- was ineffective for security, because users quickly learn to OK such warnings without even reading them. An alternative approach is "passive confirmation UI": for example, UI appears requesting a permission, but the user can ignore it and continue using the application, so users who don't read the message are less likely to grant permission by default. Firefox's geolocation permission UI is a good example of this.
The Permissions Bundle Model
That approach seems OK but as apps use more features that require permissions, there is a desire to not bombard users with lots of permission prompts, even passive ones. A number of people have proposed moving to an Android-like model. On stock Android systems, when the user starts using an application for the first time, they are presented with a list of permission requests; the user either grants them all or not. If permissions are denied, the app does not run, otherwise it runs with no further prompts.
Personally I think that is a terrible model. There are two main problems:
- There is no way for a user to know why an app needs the permissions. For example, Google Music requests, among others, "read phone state and identity", "display system-level alerts", "modify global system settings", and "send sticky broadcast" (whatever that is!). Why should it need to do those things just to play music? I have no idea. Remember that I haven't even been able to run the application yet. As a user, I just don't have the information I need to know whether the request is reasonable or not.
- If I don't grant the permissions, I can't use the app. Of course I want to use the app, since I downloaded it, so of course I am going to grant the permissions. It's the old OK/Cancel modal dialog all over again.
Someone should do a study where they promote a simple game app which requests absurdly overbroad permissions, and see how many users download the game but reject it at the permissions screen. I'll be amazed if it's more than tiny fraction of users. If so, the permissions screen should be removed, because it provides no security and interferes with usability.
Alternatives
The most important thing we can do is to remove the need to ask for permission to use a feature in the first place. We can often do this by carefully designing our APIs.
Implicit Permission Grants
Good old <input type="file"> accidentally invented an excellent permissions model for file I/O. The app asks the user to choose a file to load, and in the process the user implicitly grants the app permission to read that file! The same sort of approach works in other situations. For example, recently someone proposed that browsers offer permission UI to give an app access to the user's telephone number. Instead, <input type="tel"> could pop up a on-screen keyboard optimized for phone number entry, with access to the user's contacts database and perhaps a "my number" button. Then the application UI would contain "Enter your phone number: []" and the user would easily be able to do so --- or enter another number if they don't want to reveal their own.
Another example of this would be registering Web apps as content-type handlers. Instead of asking for permission to do that, we should simply let any Web app register as any content-type handler. However, when the user downloads content that could be handled by a Web app, then we would prompt the user to choose which app to use, highlighting their last-chosen application and secondarily any newly registered app. (Android does something like this.)
Ask Forgiveness, Not Permission
In many cases the actions of a malicious application can be easily detected and safely undone. For example, the ability to play sound through nearby Bluetooth devices could be abused to annoy the user, but the user will easily be able to detect the problem and the system should offer convenient UI to identify the abusive app and silence it --- per-application volume control. There is no need for a priori permission requests in such cases.
Remember This Decision
I'll assume without further discussion that the system can automatically grant permission to do whatever the app was permitted to do before, unless the user chooses otherwise.
Permissions In Context
Once we've reduced permission requests to the bare minimum, we still have the question of whether to ask for permissions "up front" or while the application is running. I firmly believe it's best for applications to request permission in the context of the user action that requires that permission. For example, it's easy for me to understand that when I click on the "show my location" button in Google Maps, it's going to want my location.
This leaves us with a (smaller) version of the "bombarded by prompts" problem that we started with. Personally I think we should live with it. IMHO the alternative of "bundled permissions" doesn't solve the problem, it simply works around it by teaching users to grant all permissions. "Bombarded by prompts", viewed in a better light, is a process of making informed permission decisions one by one as the user becomes familiar with the app.
Greedy Applications
One wrinkle is that lazy app developers can turn the "permissions in context" model back into the "bundled permissions" model by activating APIs up-front and refusing to let the application proceed until all requests are granted. My hope is that if most apps don't behave that way, users will develop higher expectations and be distrustful of lazy apps.
Comments
Another problem that is solved by your scheme is the "all or nothing" problem. I don't mind giving out some benign piece of information (like my location) if it doesn't combine it with other information (like the email addresses of everyone I know). So if an app asks for both, I want to be able to deny one and allow the other. Android-style doesn't allow that (it could and should be changed, but that's probably hard to do now).
The Firefox permission bar at the top is kind of lame though, let's admit it =)
In your proposal then, Google Maps would open up to say a view of the world, and have a "Find me" button? Basically for all things that are naturally background, the web platform should encourage app developers to make them foreground?
Paul: CyanogenMod (Android derivative) actually does allow piecemeal permission grants, which is why I carefully said "stock Android". But if your APIs and apps don't expect this from the start, I'd be surprised if it really works.
I don't think we should ever grant an app permission to scan your hard drive. Right now the model has is fine, and it doesn't remember permissions at all. A better example for you would be permission to get input from the microphone; you don't want a site you sometimes use for teleconferencing to always be able to listen to you. So yes, I agree "remember this decision" is not always the right thing (although it often is).
Ambient stuff like ad targeting which you wouldn't normally trigger on a user action is tricky. I think I'd want the application to offer some kind of UI to enable targeted ads, which would trigger a prompt. If the application wants to restrict its functionality until I've enabled geolocation so it can target its ads, that's its decision, but at least this approach makes it obvious to me as a user what's going on.
So yes, some things that are "naturally backgrounnd" need to come to the foreground, but I think that's OK; if they need the user's permission, then they need the user's attention.
And when I let random strangers into my house, and one of them pisses on the carpet, it's ok because I can throw them out.
For example, if a webapp wants to use geolocation and to use camera, the webapp could ask the browser for those two permissions (similar to what android does now). However, the user can say "yes, sure", "No", or can select exactly which permissions they feel comfortable with.
If the user selects nothing - or some combination of permissions, the webapp should fall back to doing what it can without those permissions.
So then instead of launching the camera app, you'd turn the rear camera on and either get a choice of apps, or the camera app would just launch. When you turn the front camera on, you'd get a choice or the video call app would launch.
Another possibility is to solve the problem at app discovery time. If the user searches for apps that use the camera, and then installs one, we can take that as an implicit permission grant to use the camera.
Load a locally saved HTML page, tell the browser which file to load. It cant load any file outside of the current dir. It cant use it with canvas (to read pixels/load into WebGL). It cant store it in localStorage. It cant post it to any server.
Some of these are Firefox bugs, others are lacking areas of the spec. None of the actions I mention above give user-friendly reasons why they dont work or give the user the ability to grant that action. While it’s awesome to point at the failures in Android, it avoids focusing on the brokenness in engines and spec.
Though, if you insist on looking an Android apps, consider the manifest tag uses-feature, with its required="true"|"false". Surely thats a better model to encourage, requesting permissions and accepting that your user doesnt have to grant it.
I would prefer a javascript application to list wants and have the browser, balanced with my preferences, to inform my consent. Should a widget for statusnet need my password? No.
Should a graphics editor be able to print, post images to flickr, and save to local disk? Yes.
The web model isn't ideal, though. It's less convenient for the user, and that's going to discourage authors from using the features. I'd bet there are some sites could use geolocation to slightly enhance their services, but don't because it's not worth bothering the user. I don't know if this will be enough to give a significant advantage to non-web apps over web apps, but it's something to be mindful of. Given the choice, many users will prefer convenience to security or privacy, and the web has to be careful not to err *too* strongly against convenience. I don't have any better suggestions in general, though.
But we can develop smarter UI over time. The decision to install an app is enough to give it access to very high system resource limits, for instance, like disk space, without further prompts. Similarly, it might be fair to allow manually-installed apps to make cross-origin network requests without the user's credentials, say. Or whatever.
I recall reading that BitFrost (the OLPC security model) would allow standard apps to access the filesystem without user interaction only if the app had no network or IPC access whatsoever. That might not be a big use-case for *web* apps, but it's worth mentioning just to highlight the fact that you can have creative solutions here that don't involve pushing decisions off to the user, who can't always make an informed decision.
As for apps that refuse to run unless they're given appropriate permissions, there's an easy solution to that if it becomes a problem: don't tell the author if the user gave permission. For instance, geolocation could always return POSITION_UNAVAILABLE instead of PERMISSION_DENIED. That forces the author to either allow users to deny position or drive away users who can't help it (no GPS, IP geolocation failed).
I think a summary of my current views, which mostly mesh with your views would be:
-real time prompting for things that impact the user's personal level of privacy (geolocation, camera/video, identity information). This is the part that I don't like about the current android model.
-up front or no prompting for system level access that the user isn't likely to understand anyway (storage, protocol registration, accelerometer, light sensor). This was the part that I liked about the android model.
-we may need to limit some permissions to apps that originate from a reviewed and curated source (bluetooth, NFC, file system access), since these are both very dangerous in terms of security and privacy, and users can't really make informed decisions on them either up from or in real time.
I'm not sure if we agree on that third part though, but I can't see much of an alternative right now.
Aryeh: I think we basically agree. I think disk space falls into the "forgiveness, not permission" category; if I'm running out of storage because some app ate it all, I should be able to fix that easily with no harm done.
I do think it's fair to say that when a user keeps being presented with questions they can't answer, they'll make a rational choice to ignore them. How we describe the process that leads to the failure state doesn't matter much :-).
John: Web security depends on origins, and there is no good way to map file:/// URIs to origins, so apps running as "local files" don't work well, that's just how it is. Any model for "installed Web apps" needs to not depend on file URIs.
I've been thinking about how the Android model if completely broken and what could be done instead. A lot of application require way too much permissions, and even the google originated one are guilty of that. Google's Barcode scanner wants to be able to do an uncanny number of things, "because it may be scanning an url and want to open it", "because it may be scanning a contact and want to add it to your list", etc. If it were not coming from Google, I'd never had installed it. Lot of free application want unlimited network access, to be able to download and show advertising, actually it's *less* scaring when you understand what the unlimited network access was for, for an application that no good reason to access the network.
So I've been thinking for a while the solution is something, that's actually the basement for why works. Don't give any right to applications. Give the rights to modules, from which the application can request services, and make sure those modules are very strongly evaluated so that they don't do bad thing.
Here it's a file access module to which the application says "I want an handle of a file" and the file module takes care of the interaction of the user and making sure it the file that the user has willingly provided that the application will have access to and not any file.
Depending on the module, access is provided either automatically or with confirmation. There could be some "Adword", "Yahoo ads" modules, and the applications instead of requesting for network access, would request "Yahoo ads" and you'd know at a much higher and much more useful level what the request really is about.
"we should simply let any Web app register as any content-type handler". Which reminds me, why is it so hard to get content to open in Firefox? I like and trust my browser, I'd love to be able to tell it "Let me view mime-type application/x-vend/Mystery" as text/plain or text/xml in the browser", and only if I like what I see go through the malarkey of saving it and loading some app or plug-in. (I know, I should try the Open in Browser extension.)
Of course, the limitation of this approach is that the app can't enhance the experience.
Implicit is great when you can have it. People often equate it with creating a new form input type, but that's not necessarily the case (and often carries design issues of its own). Implicit permission can be triggered on valid auto-invocation events for instance, which is what .click() does (and the model followed by http://dev.w3.org/2009/dap/contacts/).
However not everything can be made implicit (or, at least, both implicit and usable) and for those cases bundling — but not upfront — can help make the experience better for the user, and perhaps more importantly avoid the "just click yes" syndrome that's likely to surface if you prompt thrice, even passively. There have been some interesting inputs for bundling, notably a demo playground (http://dev.w3.org/2009/dap/docs/feat-perms/feat-perms.html), a proposed draft spec (http://dev.w3.org/2009/dap/perms/FeaturePermissions.html), and a crack-fueled plan (http://w3c-test.org/dap/proposals/request-feature/). Other thoughts on this: http://berjon.com/blog/2011/02/harmful-trust.html.
I still don't get why we'd need a bundle API. If the user's input gesture requires more than one permission (a bad situation, and I haven't run into an example where that's necessary), the app can trigger multiple permission requests, and the browser can bundle them automatically in the UI.
When you see "which is what .click() does" I had actually written "which is what {input type=file}.click() does" (except with angle brackets). My point there was that you can trigger {input type=file}-like dialogs on valid self-invocation events even without a matching form control. No one's granting permissions on click — you might as well grant them on load. But it's a decent entry point for implicit permissions.
My concern with bundling is about things that *can't* be adequately obtained through implicit schemes and require passive prompting. Yes indeed you can automatically bundle upon request, but you'd have to speed-bump that prompt to avoid script requesting a new feature just the split second after seeing to mouse leave the viewport to okay the prompt — I'm not sure it would fly through usability testing. DougT also mentioned compile-time analysis of the privileges that will be required. It can be done but there are issues with that as well. At the end of the day I'm all for this being handled automatically, but I have yet to see a design that worked. In security UI, details tend to bite rather nastily :)
You’re incorrect in saying they don’t work well - some don’t work at all.
Why should origin treatment for http://example.com/ be any different from eg: file:///home/john/com/example/ ?
If I save "http://evil.com/index.html" to /home/roc/evil.html, and I save "http://good.com/index.html" to /home/roc/good.html, and I open those two files in my Web browser, it would be bad to treat them as same-origin, right? But if we don't, then what should the origin be? The full file path? But then, how would I save a page that contains a same-origin IFRAME in a way that's usable?
If you can come up with a bulletproof way to map file paths to origins, I'd love to hear it.