Trustworthy Chrome Extensions, by default
blog.chromium.org
blog.chromium.org
For small extensions that add basic browser functionality (e.g. reorder tabs, enable autocomplete), I wish Google would enable users to verify open-source extensions. I trust the version of the code that I have reviewed on github. I do not trust that the kid who wrote this extension won’t go rogue and upload a malicious version in a future autoupdated release. So the only way I can verify the code that I run is to install it from the Chrome Web Store, copy the code and verify it, uninstall the Chrome Web Store version, and then load the unpacked extension (or even publish my own copy of it to the Chrome Web Store). This is pretty cumbersome.
Unless there's another option, I agree with the OP of this thread. Not allowing a 'locked dependency' type of mechanism for extensions continues to be very dangerous.
Alternate idea: Google can take responsibility for software they are distributing in a more serious manner.
You cannot read all the code of all the extensions you use, and if you are 'regular user', you shouldn't, but you trust some power users, researchers, developers who read the code of particular version of particular extension.
All that is needed is some infrastructure for that. You could even tune the percentage of people you trust who audited the new version of extension to mark it automatically updated for you.
That's not actually have to be anonymous audit process, most of the people in security industry have names, and you know, they actually use extensions too, so they usually read the code anyway. All we need is the checkbox where they could 'ack' the extension.
Example: Stylish -- https://arstechnica.com/information-technology/2018/07/styli...
Making the permissions as fine-grained as possible - as google is doing here - is a good way to prevent an extension from becoming malicious in the future.
Most users just click yes to all of these things. Those who would skip installing an extension because of this are an extreme minority.
This isn't perfect, but it comes with some advantages. It's more work for an extension author to check for the permissions than to just write their application logic normally. This means that the lazy authors start coding their apps correctly (just try to do the thing and let the OS handle asking for permission), and only the malicious authors are left nagging for permissions early.
If you have more legitimate than malicious app on your platform, you can at least sort of train some users to think what the malicious apps are doing is weird. If most of your apps don't ask for permissions up front, then the ones who do start to look weirder.
If I go to a website, and a permission pops up asking to access my webcam, and I didn't do something to make that permission pop up... that is really weird and I'm going to click 'no'. And when I click no, if the website wants to be cranky about it, they have to write extra code to hide whatever content is already loaded and pop up a dialog complaining. If I click OK and then immediately click a button and revoke that permission, they need to have even more code continually running in the background to detect it.
Again, it's not hard for a malicious extension/app to do that, it's just that only the malicious extensions/apps are going to do that. So it becomes easier to educate users with simple rules like, "if a site asks for a permission that's unrelated to what you're doing, always say no." It also becomes easier for users who are already careful about permissions to be paranoid and grant them carefully, because they don't have to decide up-front whether the app is worth installing -- they can decide later on whether or not they trust it to have access to something.
Part of having fine-grained permissions is in getting rid of what I call the Terms of Service version, where you just stick anything you might ever want inside of a manifest and then users either accept everything or the app doesn't install.
Are you sure it's this simple? Adblockers and password managers for example require wide ranging permissions to work and there's plenty of popular extensions in the same situation.
Fine-grained permissions will allow for this sort of thing.
So yes, the functionality of most popular extensions will be covered by the new APIs, because Google will designing the new APIs with those popular extensions in mind.
They need to fix the UX here and it doesn't seem like they intend to.
All that being said, there's still so much that Chrome needs to fix when it comes to extensions. Extension updates are done in a very opaque way. Extensions that alter network requests have precedence based on their install order --- and there's no clean way for two extensions to really coordinate between each other. This means that HTTPS Everywhere and Decentraleyes and uBlock conflict with one another, and the solution might be to uninstall and reinstall them in a different order. That is clearly insanity. What happens when you login to Chrome on a new machine and your extensions are pulled in, is the install order guaranteed to match your previous machine?
There's also no centralized storage for extensions, which means that settings are generally going to be completely different between machines unless the extension implements its own syncing/backup code.
There's also no way to disable an extension on one machine without disabling it on another machine. That means that if you want an app on your Chromebook, it's gotta be on your desktop as well.
It's frustrating to use extensions on Chrome.
Centralized storage is an optional but fully functional API in Chrome extensions. Many extensions simply opt not to use it for whatever reasons. (I'm not sure if the storage synchronizing also gets disabled by disabling the syncing of extensions. This should be made more clear, along with fine-grained extension synchronization.)
But yes, there needs to be some kind of solution to the install order issue of the network request API. I don't know why this hasn't been addressed yet.
Well Firefox has switched to webextensions for security reasons and they received a lot of flak because of it. So I'd say the opposite, since Mozilla pushed this hard and still working on better support.
> there's no clean way for two extensions to really coordinate between each other
I don't think something like this should be allowed, could be abused. Instead browsers should embrace the fact that they've become operating systems inside operating systems and implement some of the most used extensions natively.
I completely agree about extensions setting sync tho, it's major pita across all browsers not just chrome.
One tip I suggest though: Create one locked down profile in Chrome that you use for email, banking etc. and a separate profile that you can be less careful about installing extension in. Extensions in the second profile won't have access to your browsing activity in the first profile. I have a profile I use for web development for example which I install lots of extensions to that require access to everything.
If Google follows the model with Chrome that they did Android, UXSS permissions will eventually be phased out over time and replaced with better, more secure, opt-in, purpose-built APIs in Chrome. (Assuming they can do that without sacrificing _too_ much functionality.)
That and the ease that you can revoke permissions. No going into a separate settings window, just click next to the URL bar and everything shows up.
EULAs, Terms of Service, Mobile Apps, Cookie Consents have boy-who-cried-wolf'ed everyone except the most paranoid and tech-savvy to the point that they are mostly ignored.
Yes, many non-technical users do not pay attention to permissions. But permissions are extremely helpful to people who do use them -- and the number of people who do use them is larger than the number of people who audit source code or set up VMs.
Educating normal users to pay attention to permissions is a problem. It is a separate problem than, "do they even have tools in the first place if they want to use them." The problem I want solved is how I verify that an extension is safe. Granular extension permissions solves that problem for people like me.
After that problem is solved, then I can worry about educating my friends and family.
No idea if that's included in Google's plans for Manifest v3, but I agree with you that it _should_ be done that way if at all possible.
I have a Chrome extension that uses Webpack to convert TypeScript to JavaScript which then uses UglifyJS to minify it. If I submit only the minified code, is this compliant?
> Ordinary minification, on the other hand, typically speeds up code execution as it reduces code size, and is much more straightforward to review. Thus, minification will still be allowed
Firefox/Mozilla require you to submit the original source code for review for example (minification is not allowed): https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/Sou...
Obfuscation is more like the maximum amount of code changes possible while keeping semantics.
Writing an unminifier is pretty feasible and the only real trouble with reading the resulting code is the meaningless variable names. Writing a deobfuscator is intentionally hard.
> Writing an unminifier is pretty feasible and the only real trouble with reading the resulting code is the meaningless variable names.
Reviewing code with meaningless variable names is still several orders of magnitude harder than reviewing the original code though. I agree code though an obfuscater is another step up however.
Automated checking tools don't really care about human-friendly user functions' names. They will however check for calls to dangerous APIs (eg: XMLHttpRequest(url), eval(stuff) ) and some dangerous patterns (eg: background actions unprompted by the user ).
> even if it requires a lot of changes
A minifier will not make changes that are not required. In fact a lot of the more obscure changes can still be easily detected by code and reversed. Eg most minifiers will turn
if(hello) {
alert("hi");
}
into hello&&alert("hi");
That seems cryptic to the untrained reader. But you can probably imagine writing an unminifier that can detect that the result of that expression is not assigned to anything and that the && is only used for lazy evaluation. This means that you could restore the original "if". Now note that the only reason you can do this is because minifiers follow this same pattern all the time. Every if with a small body is minified in this same way. Unminifiers know the patterns that minifiers use and reverse them where possible. It's pretty fun to do actually.An obfuscator, on the other side, will try to vary the patterns by which code is changed as much as possible, and as randomly as possible. Depending on a random seed, the same if might be turned into
var b=52,w="toString",h=History;
(((hello==(b-51))||(!b))&&(()=>alert(h[w].call(h).substr(9,2)))())
This is a lot harder to turn back into that if, and essentially impossible for reviewers to follow. A good static analysis tool could probably do some flow analysis and derive that hello is checked for truthiness, the !b check is superfluous and the function expression is immediately invoked, and still restore that if. But real decent obfuscators can do similar static analysis and have access to much more data, by definition (especially if the input code is typed). Eg it would use existing variables in scope that it knows are truthy/falsy/etc and needlessly add them to checks (maybe even bring them into scope from elsewhere). The more code you have, the better you can obfuscate it. Writing a good obfuscator is hard (writing a shitty one is peanuts and a lot of fun), but writing a useful deobfuscator that can handle non-shitty obfuscators is nearly impossible.You're agreeing. Minification makes things as small as possible. No one said otherwise. The "minimum amount of code changes" could very well be "a lot of changes".
The blog post explicitly calls out all of the following techniques as acceptable, for example:
> * Removal of whitespace, newlines, code comments, and block delimiters
> * Shortening of variable and function names
> * Collapsing the number of JavaScript files
It was a pain to get through but doing good things for your users takes effort.
That is really nice.
One of the reasons Firefox is a non-starter for me is because sometimes there's no good way to tell what hosts an extension requires access to:
I hope they can find a path forward that doesn't kill off extensions like 1Password X.
For example, it would be easy for Google/Mozilla/etc to compile a list of HTML tags and attributes that can never be used to inject javascript. Lots of "HTML sanitization" libraries do this, for instance. Then, we could get permissions like "remove content", "inject non-interactive content" and "inject interactive content". An ad blocker, for instance, should work with no network access whatsoever and should never need to inject code. So I can totally lock it down to not being able to do anything except replace ads by empty <div> tags.
I think there's an opportunity for browser builders here with more granular permissions in other areas too (eg "network access but only to domains x and y", which ofc only makes sense if you can't also inject arbitrary interactive content but ok). No user is of course ever going to read those, or understand which combination of permissions make sense, but a Google reviewer can. Then the reviewer doesn't need to review anymore whether the code does something bad, but only whether the requested permissions would _allow_ the code to do something bad an whether the permissions make sense for what the extension is supposed to be doing.
Eg LastPass ought to work just fine with only "access to *.lastpass.com" plus "inject only non-interactive content".
This could be particularly powerful if browser designers would create a way for extensions to show possibly-interactive content on the top/left/side/bottom of the page (in a popover bar for instance) that is clearly not part of the page DOM. Then, LastPass can remove their "click to auto-fill" icons inside user/pass forms and replace them by a "That looks like a login form. Do you want to auto-login?" popover bar with an ok button. The UX is still great, security is greatly improved.
I don't pretend to be smarter than the teams that build browsers, so I may be missing something. Nevertheless right now I think that this, combined with the feature announced in this post where extensions can be locked down to specific websites, will remove the need for nearly any "can change anything on any website and do anything with it" extensions (which are pretty much the norm right now). Gmail extension? Website-specific. Pinterest "pin it" button? Non-interactive (make the injected button just be a selector and show the final "pin selected images" action in a popover bar). HN-Submit? Non-interactive. And so on.
1. https://developer.chrome.com/extensions/declarativeContent 2. https://developer.chrome.com/apps/permissions
So technically you can write whole extension in WebAssebly with thin wrapper written in js.
Although "Starting today, Chrome Web Store will no longer allow extensions with obfuscated code." which might be an issue.
Right now, as you say, only power users will use this feature. But once suitable alternative permissions are available for the more common use cases, Google will start to transition to "When you click the extension" as the default setting, which will put pressure on affected extension developers to migrate to the new permissions systems to avoid unnecessary friction for their users.
How does this effect Greasemonkey-style extensions where the user imports JS to run on pages?
This way one could simply disallow extensions to do anything that isn't happeninging locally.
The extension needs permission to modify documents on the hacker news domain. But if it can insert an <a> tag, what's to stop it from inserting an invisible <img href> tag, which could be used to exfiltrate data? Or even just inserting an <a> tag with an onClick handler, or a javascript: url?
Say you have an extension that ONLY wants access to mail.google.com. It might feel safer because it can't load in any third party scripts. But it can just as easily SEND data from your account as an email which it promptly deletes.
Same goes for LinkedIn, Facebook, HN, any interactive website can be used to exfiltrate data.
They should implement default-deny. It'll take two seconds for users to grant the permission, and the vast majority of extensions don't need it.
I still do most of my web development with server side rendering stacks.
Lots of functionality (and thus current extensions) requires requesting blanket access to all websites so they have a big task ahead of them trying to get all those extensions to comply.
In general the way things work for Chrome Extensions right now is bad for users and downright hostile to developers. Because I actually followed best practices on extension permissions I got a lot of confused, paranoid users, and had to explain Google's awful permissions model and UI in detail: https://www.reddit.com/r/Granblue_en/comments/86bdmo/psa_vir... If I had simply requested a large set of blanket permissions when I first created the extension, I would've saved myself a huge amount of effort.
Users having the choice to scope wildcards down to specific pages is a start but until it's a default it isn't really a meaningful improvement for anyone because few people are qualified to actually set those restrictions properly. The design of the extension API itself tends to require wildcards to provide functionality due to limitations in the other APIs. For example, if you want to do anything fancy with web requests and do it performantly, you may need to inject JS directly into webpages - the background-page-based webRequest API is slow and missing key features.
There's also a risk here that by trying to kludge better access controls into the existing full-of-holes extension model, Google is going to break tons of extensions that ordinary users rely on and they're going to be too frustrated by this to be happy about any security upside.
Some genuinely good changes though:
* Requiring 2FA to deploy extension updates. This is a big vulnerability in the existing system, especially if an extension has many users. It's been exploited in the past.
* Service worker support (probably) - the current model with page/content/background scripts and popup pages is a nightmare both to author and debug, hopefully service workers will provide a better way to architect all of this.
* Narrowly scoped declarative APIs - hopefully this means extension developers can finally get access to smaller features without having to request access to the entire universe. Some of the feature scoping is really absurd and occasionally unrelated APIs are tucked under a larger permission in a way that really confuses users. As I explained to users in my old reddit comment above, Google currently uses "Access your browsing history" to describe an ENORMOUS set of unrelated features.
* Blocking obfuscated JS - this literally will do nothing to protect users, but it's worth denying it anyway. There's no good reason to obfuscate extension JS since it's so hard to debug extensions you didn't write anyway. It's possible this will make it easier for them to apply machine learning to identify malicious extension code, at least, but I bet the machine learning will just randomly reject updates to legitimate extensions without any explanation and you'll be screwed.
The big wildcard here is Google's history of failing to maintain or properly document extension APIs. They're going to be rearranging lots of existing stuff and adding new stuff, so the underlying mess will probably become 10x worse. Core APIs like notifications have been entirely or partially broken for years with no effort made to fix them or update docs. Inertia is one of the main things carrying the chrome extension ecosystem forward and it's possible many extension developers will churn out after they find the migration effort involved here too much, similar to how Firefox lost many extensions during their two transitions (old->multiprocess compatible->webextensions)
On Firefox the reviewer took my source code, inc package.json, and ran it through the exact same version of my dependencies and then did a checksum of the output against what I submitted. The reviewer also read my source code and reviewed all dependencies.
It was a pain to get through but doing good things for your users takes effort.