[MUSIC PLAYING]
SIMEON VINCENT: As
you probably guessed
from the very creative
title of this talk,
I am going to be talking
about Chrome extensions.
And there's a lot
I want to cover,
and our time together
is relatively limited.
So before we get
into everything,
I just want to make sure
we're on the same page.
We're going to take a quick
look at an itinerary of events.
So first, we're gong to talk
about how extensions are great,
and how they're amazing.
Then we're going
to talk about some
of the anatomy of the
existing ecosystem.
We're going to talk about
some of the challenges
the extension
ecosystem is facing.
We'll start to talk about
a fundamental shift in how
the Chrome team is thinking
about the Chrome Extensions
platform.
We'll go over some
details of how
to actually migrate an extension
and adopt this new system.
And then I'll try to
tie it all together
and say something
cool, we'll see.
So without further
ado, let's do it.
First off, extensions are great.
There are a lot
of different ways
that we could talk about
extensions, like how many have
been published, or how many
the average user has installed,
or user satisfaction
ratings, or whatever.
But personally, when I
think about extensions,
the thing I keep coming
back to is the fact
that Chrome extensions are
how users make Chrome theirs.
It's not just another
feature of the web browser.
This is the way that you
customize the browser
experience and make the web into
something that you personally
experience.
And users have
consistently told us
that they love using extensions,
that extensions are a core part
of how they browse the web.
And I think there's a
pretty simple reason why.
They make it your web browser.
You can use extensions to make
all kinds of crazy things.
Like you can, I don't know,
get some motivation every time
you open a new tab or automate
parts of your workflow.
You can change
your theme and make
Chrome feel more like home.
You can remove ads on
the sites you visit.
You can automatically donate
to the content creators
that you love.
Or you can take some
inspiration from XKCD
and replace a word
here and there
to spice up your day-to-day
browsing experience.
But the point is, extensions
put you front and center.
You customize your web
browser to your tastes.
And if you can't find
an extension that
does what you want, you could
probably build your own.
Those of you comfortable
with web development--
I'm going to assume that's a
decent number of you here--
are already most of the way
to building your own Chrome
extension.
See, the Chrome
Extensions platform
is itself an extension
of the web platform.
Chrome extensions use the
same standard technologies--
JavaScript, HTML,
CSS-- that you,
web developers use to make--
I don't know, I said you, web
developers, that's weird--
web developers use to make
websites and the experiences
that we all enjoy every day.
This webby design
is a core feature
of our browser extension model.
And to show you
what I mean, let's
take a quick look at an example
extension to see how it works.
Here, I have a
very real extension
that definitely exists.
And it does two main things.
It allows me to block websites
that I spend too much time on.
And it allows me
to log my work so I
can hold myself accountable.
So if we download this
extension and open it up,
we'll see something like this.
Here, this is the
CRX file that I've
downloaded from the web store.
And as you can see, this
command line utility I'm using
shows that the extension is
basically just a directory that
contains standard webby files.
AUDIENCE: [INAUDIBLE].
SIMEON VINCENT: Oh,
my, I don't know why
I was going to give you that.
So it's basically
just a directory
that contains a bunch of
files that you're typically
used to working on the web.
And I want to quickly call
out manifest.json here.
This file is important because
it's the primary entry point
to enter your extension.
So if we pop this open, we
can see that the manifest.json
contains everything
that the extension needs
in order for Chrome
to load it and run it.
And I specifically
want to point out here
that we're looking at a
Manifest version 2 extension.
The 2 means that we're working
with the second version
of the platform.
Later, we'll be talking more
about some of the features
specific to Chrome extensions
from the Manifest version 3
platform.
So here we have the
background property.
This is the-- oh,
no, what am I saying?
The background pop
property specifies
what code will be running
in the background.
Typically, your background is
used to set up event listeners
and coordinate between different
parts of your extension.
content_scripts
here are injected
onto specific web pages that you
want to load custom script on.
Here, I'm using
a special pattern
called all_urls, which, as you
might guess, matches all URLs.
And finally, the
permissions section
currently defines two things--
first, the URLs that I'm
going to be interacting with,
the hosts that I'm
going to interact with,
and the permissions that
the extension requires.
My extension is pretty
simple since it's only
basically blocking sites
and saving data locally.
It doesn't need
many permissions.
Now, there's a lot more
that Manifest can do.
But these are the
core pieces that we'll
be looking at later on.
So let's take a look
at some of the issues
that we have with the
current ecosystem.
While users love the platform,
and good actors put them
to wonderful use, we are
also facing some very real
challenges.
These are the issues
that we're facing.
We're going to go
over each in turn.
And while some of them
are closely related,
they're distinct
enough that we're
going to need to explain each.
So first, usability--
simply put,
when we first created
the extensions platform,
we made some assumptions
about how users would interact
with the installation flow,
and how well they understood
the install prompts, and
how well they understood
the trade-offs being requested.
And unfortunately,
over time, I think,
we've come to see
that these don't
hold as well for the average
user as we would have liked to.
On the flip side,
powerful APIs are often
a developer's only option.
For example, if you want to
block ads on a web today,
you have to give the
ad blocker broad access
to your network request.
This means you're
also implicitly
granting it the ability to see
literally everything you do.
And understandably, this gives
a good number of users a pause.
And speaking of powerful
permissions, all_urls
is kind of a special
case that needs
some of that extra attention.
See, it is extremely common
in today's ecosystem.
It's almost impossible to
install an extension that
doesn't say, this extension
can read and modify
all your site data.
And what that also means is that
end users aren't necessarily--
they're kind of desensitized.
They're not giving enough
credence to the danger
that this poses.
This should be a relatively
scary permission.
But it is kind of core to
how the current extension
ecosystem works.
It also makes it much harder
for us to closely scrutinize
the content of the
extension in order
to make sure that anomalous use
or potentially dangerous use
isn't occurring.
And while we're on the topic
of frightening capabilities,
in the current version of
the extension ecosystem,
it's possible for an extension
to load and execute code
from a remote server or
from an arbitrary string.
The term that we
tend to use for this
is remotely loaded code
or remotely hosted code.
And essentially, we
just mean any code
that isn't in the
extension's bundle.
And while this capability
is used to good effect,
it's also a major attack vector.
After all, if an
extension can change
what it does at runtime without
review, then essentially,
all bets are off.
And to put it lightly,
that's not the situation
we're exactly excited about.
Another major challenge of the
current extensions platform
is that extensions can pretty
easily tank performance,
either for specific
pages or for Chrome.
For specific pages, the
user can just close the page
and move on.
But when it starts
to drag down Chrome,
then everything suffers.
The web suffers, from
the user's point of view.
And due to the asynchronous
architecture of the extensions
platform, there's no obvious
signal to the end user
when this is happening.
So if a page were to
similarly slow down,
you would start to
see scroll junk,
or there would be clear
signals that there's issues.
But basically, the computer
just very slowly degrades.
And even if a user knew that
an extension was at fault,
there's not a great way
for them to take action,
to reclaim those resources.
And finally, users simply
don't have enough control
in today's ecosystem.
They don't have enough
control over the experience
of using an extension.
Historically, if an extension
said that it needed broad host
permissions, that
it needed all_urls,
they would just
include that pattern
in their permissions list.
And then the user is forced
to either choose to grant them
the set of capabilities that
the extension's requesting
or to bail out entirely.
And needless to say, this isn't
good for users or developers.
It also assumes that
the user actually
understands these permissions.
So if a user didn't understand
"read and change all your site
data," they might say yes,
even though they don't
understand the consequences.
And there's no remediation until
you uninstall the extension
entirely.
So that brings us to
this paradigm shift.
As we think about how to
improve the extensions platform
and where we want
it to go, we're
making some changes to
the base assumptions
about how extensions are
built. And unfortunately,
all of the issues
we just went through
present a fundamental conflict
with the current extensions
platform.
We can't make those changes
without some rather substantial
breaking changes to
the platform itself.
So we're going to make
some substantial changes
and break the Manifest
version, which
is why we're going from 2 to 3.
That way, we have a new
ecosystem to work in.
So if I had to give the
current ecosystem kind
of a tag line or a motto,
it would be something like,
"empower developers to create
amazing end user experiences."
But as we look to
the future of how
we want to evolve
the platform, we
want to shift it to
something more like,
"empower users to
customize Chrome
with amazing extensions."
The privacy and
security of the user
should be the primary focus for
both Chrome and for extension
developers.
And of course, we're still
striving to provide developers
with a powerful,
capable platform
that they can use to
enable and delight users.
But that respect for
the user should be
a core principle for everyone.
With this user-centered
philosophy in mind,
we're aiming to improve three
main areas of the Chrome
Extensions platform-- privacy,
security, and performance.
In order to improve the privacy
of the extension ecosystem,
we're trying to give
users more control
over when an extension will run
and what data it can access.
We're also trying to
encourage extension developers
to give users more
in-context permission
requests and temporary
permission grants.
In-context requests improve
the end users comprehension
of a permission being requested.
And temporary grants keep the
user in control of their data.
For more about
temporary grants, I'd
encourage you to check out
documentation on activeTab.
We're also looking to improve
the security guarantees
of the extensions platform.
That is, we want to be able to
say to the user with confidence
that it is significantly
harder or even impossible
for an extension to gain control
of this privileged execution
environment.
And by extension, we want to
increase-- huh, by extension--
we want to increase the end
user trust in what they install,
and that it won't cause
any long-term harm
or won't do anything without
their direct involvement.
Oh, right, I have
to press a button.
[LAUGHTER]
We're also aiming to make
the extension platform more
performant by default.
We want developers
to fall into a pit
of success, where
even if they make a mistake
or adopt an anti-pattern,
things will, for
the most part, just
work out for them and, by
extension, the end user.
So one of the goals
here is to reduce
the amount of resources
that are being consumed
over the extension's lifetime.
I have too many things.
OK, let's start to get
into some of the details
about how extension
developers will migrate
from the current
extensions platform
to the new version, Manifest V3.
There are four main
things that developers
are going to need to adapt
to in this transition.
First, we're migrating
from a background page
to a background service worker.
We're going to change how
the extension gets and uses
host permissions.
We're introducing a new
requirement for extensions
to bundle all the source code
that they're going to execute
into the extension itself.
And finally, we're changing
how network requests
are modified at runtime.
Each of these has its
own set of challenges
and will require a different
set of adaptations.
So we're going to step through
them and see how it goes.
First up, background
context changes--
the first and perhaps
broadest set of changes
is the transition from a
background page to a background
service worker.
There are two types of
background pages today--
persistent background
pages and event pages.
Persistent background
pages, as you may guess,
are long-lived page
environments that constantly
run in the background.
Event pages, on the other hand,
are temporary environments
that are started in
response to an event
and terminated when
they're no longer needed.
We want to move from
background pages
to service workers for
three general reasons.
First, better
overall performance--
we want to reduce the number of
concurrent processes running,
the amount of memory consumed,
and the total resource usage
overall of extensions.
Second, extensions are
built on top of the web.
Where possible, we much prefer
to use the web's primitives
rather than custom extension's
specific solutions.
And finally, maintenance cost--
upkeep has a very real cost.
If we have a bunch
of redundant features
that are both supported by the
web platform and the extension
platform, that means we
have to do twice the work.
Like Chrome has to do
twice the work in order
to make any change because
of knock-on effects.
One change here can
cause consequences
in other places
you didn't expect.
So as developers look to
migrate to service workers,
there are two categories
of issues that we're
going to need to face.
First is this transition
from a persistent page
to an ephemeral environment.
And the other is moving from
a headless page to a worker.
So first up, ephemerality--
extension listeners
need to be registered
in the root context
of an extension
rather than in
asynchronous registration
and some kind of callback.
For example, you can imagine
requesting some config
from Aroma server
and then, once you've
received the response,
registering the callback
handler.
And this is a little
bit off in the weeds,
but I think it's cool.
So I'm going to
share it with you.
In order for Chrome to
properly dispatch events,
it needs the events to be
registered as soon as possible,
preferably, in the first
turn of the event loop.
If they're not,
then it's possible
that you would perform your
asynchronous network request.
You'd come back.
Before the response
is received, Chrome
would try to dispatch the event.
It wouldn't be handled because
there's no handlers registered.
And then you receive
the response,
register your listener.
And now you're like, wait,
where did my event go?
Like I dropped it on the floor
because you weren't there.
All right, second, you
can't rely on global state.
Since service workers
are event-based,
the global context
with a service worker
is tossed every time the
service worker is torn down.
So you probably need to adapt
by moving from global state
to chrome.storage
APIs or IndexedDB.
I should also call out here
that extension service workers--
well, I guess, all
service workers--
are asynchronous by design.
So you can't rely on synchronous
APIs like local storage.
So if you're currently
using local storage
to store your state, you'll need
to work out a migration plan.
All right, the other major
challenge with background pages
is that they don't have
DOM-- or I'm sorry,
background service workers pages
have DOM because they're pages.
So no worker-- web
worker, or service worker,
or animation worklet--
none of them have access to DOM.
By design, workers are meant to
be a stripped down environment.
But that also means you
can't do things that you're
used to using DOM for.
You can't parse
XML or HTML, or you
can't traverse a document tree
because there's no document.
You can't dispatch events
because there are no elements
to dispatch events on.
You can't play audio or video.
You can't render
to a canvas element
because there's no element.
So each of these is going to
require its own specific ways
to handle.
For parsing documents,
traversing trees, dispatching
events, a library like JSDOM or
Undom can fill that use case.
For playing audio
or video, you'll
probably want to reuse
an existing DOM context
or create a new one.
So open a new tab or window.
And for rendering
to canvases, that's
what OffscreenCanvas is
for explicitly, by design.
And while this isn't
our preferred pattern,
in some cases,
you may absolutely
need a long-lived,
persistent page environment.
In those cases,
I'd recommend using
a new tab or a new window.
And that may sound
odd that we're
moving from a headless
page to a worker,
and the solution is
to open a new page.
And the answer is, yes.
The rationale here is that
this gives the user control.
If they are able to control
whether or not a page is open,
a tab is present, then they
can decide whether or not
they want your
page to be around,
or if they want to
reclaim those resources.
For additional guidance on
adopting service workers--
there are other issues to
be aware of here as well--
check out the Migration Guide.
I'll have a link at
the end of the talk.
All right, too many words.
Code-- assuming that you already
have your background script
in a state that can be
transitioned directly
to a service worker--
and for reference, a decent
number of event pages
already fit this bill--
you can simply change the
background scripts here
into a service worker.
That's it.
It's a one-line change
in your manifest.
But that makes a decent
number of assumptions.
All right, host permissions--
one of the fundamental
changes in how
the new version of the
extensions platform
is rethinking the
way extensions work
is this shift towards a more
user-centric interaction model.
In the past, if an extension
wanted to access data
on every website, as
I mentioned before,
they just add all_urls to
their permissions list.
And then if the user didn't
understand or just agreed
to it, the extension
would have that capability
until it was uninstalled.
Given the risks associated with
this persistent permission,
the extensions team
wanted to change
how capability grants like this
work in order to give users
more control over their data.
With the release of Chrome
70 in October of last year,
end users gained
a lot more control
with the introduction
of this feature.
Here, if you right-click an
extension in the toolbar,
you can go to the "This can
change and read site data"
option, where you can restrict
the extension's access
to either a specific site or
even to only run on click.
Looking to the future, we're
exploring additional changes
to the installation
flow, so that "When
you click the extension" option
in here is the new default.
Users can still
opt into granting
broader persistent permissions
if they wish to do so.
But that should be the user's
choice, not the developer's.
Rather extension should
provide a complete compelling
experience out-of-the-box
without having to ask the user
to give away the sun,
the moon, and the stars.
The intent here is more
direct user control
over when and where extensions
will access their data.
Today, many of
extensions are designed
around this pervasive
data access pattern.
And there are a whole host of
ways that good actors put this
to positive effect.
But it also comes at a cost that
a lot of developers and users
may not have considered.
And that cost is compromising
user security and privacy.
To that end, I'd strongly
encourage developers
to look into ways to
embrace this new paradigm,
this new mindset.
And try to design your
basic interactions
for your extension around
temporary host permissions
rather than persistent
host permissions.
Where possible, treat
in-page interaction and host
permissions as a
progressive enhancement.
If the user likes what
you're delivering,
then they can choose
to grant your extension
additional capabilities.
Before we move
off permissions, I
would want to make a quick
note about API changes.
Earlier I mentioned that
Manifest version 2 specify
hosts in the permissions field.
In Manifest version
3, we're changing
this to have a dedicated field
host.permissions, where you
define your host permissions.
While this is a small
change, the intent
is to better reflect
how the Chrome
platform is thinking about
and using host permissions.
These aren't capabilities that
will be required of the user.
These are things that may
enhance your extension.
All right, remotely
hosted code restrictions--
a few moments ago,
I talked about some
of the challenges related
to remotely loading code.
And in order to address
these issues, in the future,
extensions will only be
able to execute code that
is in the extension's bundle.
And by code, I specifically
mean JavaScript, CSS,
and WebAssembly.
Now, CSS may seem like a
bit of an outlier here.
But unfortunately,
through clever use of CSS,
it's possible to leak
data about the page
that the CSS is injected into.
So unfortunately, we have
to guard against that.
I should also call out
that remote data is fine.
You'll still be
able to load JSON.
You'll still be able to
request media assets.
You can still make remote
procedure calls or API calls.
You can still do
that webby stuff.
The intent, though, is, in
this privileged execution
environment, we need
to be able to see
the code that will be run.
We plan to accomplish
this through a combination
of platform and policy changes.
For example, if you attempt
to change the default content
security policy on an
extension, in order
to grant unsafe
eval, as in the case
here, or grant a remote
domain, you simply
will fail to load the
extension at install time.
I tend to be a big fan of
"error loudly and clearly,
as soon as possible."
And this is definitely that.
In order to adapt
to this change,
I'd strongly recommend
developers move
towards a config-driven
architecture.
Bundle all the code
that your extension
may execute at runtime.
And then use remotely
loaded configuration--
for example, JSON--
in order to choose
which files you actually
inject and which code parts you
execute.
I'd also encourage
extension developers
to consider adding feature
switches to their extensions
and possibly some
messaging support
in order to minimize
unexpected behaviors
and to communicate those
unexpected behaviors
and disabling of certain
features to end users.
One major area
changing in Manifest V3
is how we handle modifying
network requests.
Currently, extensions
use the blocking version
of the Web Request API in order
to, well, block web requests.
This API effectively places the
extension between the browser
and the network.
Here's a simplified version
of the web request flow.
First, the extension registers
event listeners with Chrome
in order to get callbacks
when a net request lifecycle
event is fired.
Next, when the
event is triggered,
Chrome passes a request
object to the extension.
And finally, the
extension chooses
whether to allow the
request, to modify it,
or to cancel it entirely.
While this API is very capable,
it has a couple of major issues
that we want to
address in this attempt
to move to a more
privacy-preserving and secure
extension platform.
First, it requires
host permissions
for the extension to work.
As we just talked about, we're
trying to go away from them
or discourage their
persistent use, which
means that in the current
world, an extension wouldn't
be able to observe or
modify the request.
In other words, at install time,
the extension wouldn't work
out-of-the-box.
That's a pretty bad
experience for the end user.
So it's something that
we want to address.
Second, this exposes too
much data to the extension
passively.
The request object that
I mentioned in step 2
here contains
detailed information,
such as the URL,
the cookies used,
the request body, et cetera.
And this pervasive
passive data access
is exactly the type
of thing that we're
trying to adjust in
Manifest version 3.
And third, and
finally, this API was
designed for a world with
persistent background pages.
To put it another way,
it's not a great fit
for moving to service workers.
Service workers
have a startup cost.
And all requests are
blocked until that startup
cost is paid.
Without getting too deep
into the internals of Chrome,
the web requests model
involves a decent amount
of extra work for Chrome.
For every lifecycle event that
is fired for every request,
every extension
that's interested
in it needs data to be
serialized and passed
across multiple
different process hops.
The extension use of
the service worker
is also a bit different
than on the open web,
where service workers
cash offline content
and enable better
offline experiences.
In our case, though, the service
worker would be a blocking--
network request would block on
the extension service worker
until the extension service
worker to start it up.
And that has a very
real cost to end users.
So in order to continue to
serve the Web Request use
case and the wonderful
things that it does,
we're trying to take a
think on redesigning some
of the basics of this model.
To show you what I
mean, let's take a look
at how a new API that we're
introducing is going to work.
Oh, I lied.
I have to say that
in order to continue
to serve the basic use cases--
oh, no, I said all that.
Not that it matters.
We're introducing a new
API called Declarative Net
Request that takes a
completely different approach.
So rather than the
extension sitting
between the browser
and the network,
the extension at
install time says,
hey, Chrome, here's
a list of rules
that I want you to enforce.
And then Chrome is responsible
for enforcing them.
This declarative
model drastically
limits how much data is exposed
to the extension, while still
enabling extensions to
modify requests and block
ads and stuff.
So let's see some code to
actually compare the two.
First, in Manifest version 2,
I have a set of permissions
that I request.
I have to request
both webRequest and
webRequestBlocking because
that's a separate thing.
I also have to request all the
hosts that I want to intercept.
And then I match
requests that are
sent to the main_frame on
Twitter, and I cancel them.
So all of this is
happening running
in a JavaScript environment.
Instead in Manifest version
3, my permissions list now
is only declarativeNetRequest.
No host permissions required.
I have a new property called
declarative_net_request,
where I define a
set of static rules.
And each of these
rules will match
the main_frame and the URL
and then block that request.
I should also call out that in
response of developer feedback,
we've also added a--
what's it called-- Runtime API
in order to add dynamic rules.
But this still allows
Chrome to remain
in control of what
requests are allowed
and limit the amount of data
exposed to the extension.
If you're interested
in learning more,
please check out
our documentation.
Again, link at the
end of the talk.
But we are very
interested in trying
to work with the
development community
in order to find a
good solution for this.
All right, wrap it up.
We talked about a lot of stuff,
moving from background pages
to service workers,
host permissions,
remotely hosted
code, restrictions,
net request modification.
And all of that was too fast
to even hear what I just said.
But before our time
together is over,
I want to touch on another
important thing, what
we're keeping the same.
Extensions are an amazing
feature of Chrome.
Time and time again,
we've heard that extension
cited as a key feature of
how users browse the web.
Extensions give users a way
to customize Chrome and truly
make it their own.
As we refine the
platform to give users
more control over their
browsing experience,
we're also striving to maintain
the eclectic, feature-rich,
vibrant ecosystem of
extensions that we have today.
We want to get to
a world where we
can satisfy all of these
use cases that empower users
and make Chrome their web
browser, while also feeling
safe, and in charge, and secure.
That's the reason that we're
pursuing Manifest version 3.
And we're committed
to continuing
to work with the
development community
throughout this transition.
Before I go, though, I'd
like to encourage you all
to start experimenting with
the new version of the Chrome
Extensions platform.
We have a developer preview
in Chrome Canary today.
Well, actually, we
released it on Halloween.
But it's out there.
You can start experimenting
and trying these out.
Try migrating extensions
and also give us
feedback on what you
can and can't do.
And please let us
know if you run
into any issues on the Chromium
Extensions Google group.
Again, thank you very much.
I appreciate it.
Have a good one.
[APPLAUSE]
[MUSIC PLAYING]
