-
Notifications
You must be signed in to change notification settings - Fork 6
Home
Policy enforced on a resource SHOULD NOT interfere with the operation of user-agent features like addons, extensions, or bookmarklets. These kinds of features generally advance the user’s priority over page authors, as espoused in [HTML-DESIGN].
— Content Security Policy Level 3
But implementations are incorrect:
- Firefox: bookmarklets are executed as non-privileged script, blocked by CSP (
unsafe-inline
script). Anddocument.execCommand("cut")
(or"copy"
or"past"
) is not allowed, will log the following error:document.execCommand('cut'/'copy') was denied because it was not called from inside a short running user-generated event handler.
. - Chrome: execute bookmarklet as non-privileged script, but ignoring CSP directives. However subsequent resource (injected scripts by the bookmarklet. Ex:
document.createElement("script")
) are still subject to CSP, CORS check and mixed content restriction (HTTPS vs HTTP)
See also:
- 233903 - CSP: Bookmarklets should bypass pages' policies. - chromium - Monorail
- 866522 – Bookmarklets affected by CSP
- 1267027 – Page CSP should not apply to content inserted by content scripts.
- 615708 – CSP blocks content injected by add-ons (including data: URLs)
- Bug 149000 – Some extensions triggers CSP violation reports
- Content Security Policy - Browser add-ons and extensions exemption — Wikipedia
- Bookmarklets are Dead… – Making Instapaper – Medium
- Mixed Content Blocking and Content-Security-Policy Block Bookmarklets
- Greasemonkey accessed by Bookmarklets - Google Groups
- security - How to disable CSP in Firefox for just bookmarklets? - Super User
- Content Security Policy
Doesn't work because reports don't provide the URI (blocked-uri
) like javascript:...
but self
(at least Firefox):
{ "csp-report": { "document-uri": "http://example.com/signup.html", "referrer": "", "blocked-uri": "http://example.com/css/style.css", "violated-directive": "style-src cdn.example.com", "original-policy": "default-src 'none'; style-src cdn.example.com; report-uri /_/csp-reports" } }
As you can see, the report includes the full path to the violating resource in
blocked-uri
. This is not always the case. For example, when thesignup.html
would attempt to load CSS fromhttp://anothercdn.example.com/stylesheet.css
, the browser would not include the full path but only the origin (http://anothercdn.example.com
). The CSP specification gives an explanation of this odd behaviour. In summary, this is done to prevent leaking sensitive information about cross-origin resources. Note, that even the specification got this part wrong in its example on violation reports (blocked-uri
should behttp://evil.example.com
).
— Content Security Policy (CSP) - HTTP | MDN
Register a CSP violation report and handle violation generated by bookmarklets.
Intercept the report-uri /my-custom-resport-url
request or use the securitypolicyviolation
DOM event (only implemented in Chrome) or CSP3 report-to
- CSP: report-uri - HTTP | MDN
- 1302962 – CSP: Implement SecurityPolicyViolationEvent
-
1341594 – WebRequest listeners are not triggered for CSP report requests - To get request body with WebExtensions
webRequest
require at least Firefox 53
It doesn't work because CSP don't allow to specify a source-hash
for javascript URIs (CSP2):
Add source hashes of all bookmarklets to the CSP script-src
directive
if at least one nonce-source or hash-source is present in the list of allowed script sources:
- [...]
- Whenever the user agent would execute script contained in a javascript URL, instead the user agent MUST NOT execute the script, and MUST report a violation.
— Content Security Policy Level 2
The inline script restrictions imposed by CSP include script valued attributes (commonly used for DOM Level 0 event handlers, e.g. onclick); hash-source and nonce-source cannot help you with these. Currently CSP does not provide mechanisms to apply directives to such script valued attributes but let’s see what the future brings!
— CSP for the web we have | Mozilla Security Blog
See the add-csp-source-hash-idea
branch
It's not ideal, because the user net to update all her/his bookmarklets to use this custom protocol and she/he want to execute the bookmarklet for the current document, not to navigate to an other document/application, then go back. And it's hard to implement.
Create a custom protocol. Ex: bookmarklet:
:
- register it with
navigator.registerProtocolHandler()
to point Point to an empty document (likeabout:blank?%s
orhttps://bookmarklet/%s
) that the WebExtension could handle for execute the bookmarklet source - or create a native application handle the protocol (more complexe)
Note: (as current implementation) the protocol name need to be prefixed by web+
if it's not from the provided list
- Chrome custom protocol handling, simon and garfunkle style
- Custom protocol handler in chrome - Stack Overflow
- 1310427 - protocol handlers (for mailto etc)
- 1271553 – Add ability to implement programmable custom protocol handler
- autoland: toolkit/components/extensions/schemas/extension_protocol_handlers.json@c2574d7124fa
The only one working solution, but require a specific UI (context menu). Still face issues with mixed content restrictions (HTTPS vs HTTP) and CSP applied on injected subresource
Recreate the bookmarks hierarchy, but with only bookmarklets in a context menu.
It's doesn't work. WebExtension API webNavigation.onBeforeNavigate
(in Firefox and Chrome) don't receive any event when navigate to javascript:
URIs. In fact only ftp://
, http(s)://
and custom protocols (registered or not) are handled, but not javascript:
, data:
nor moz-extension://
Listen to javascript:
URIs navigation.
It doesn't work, because we can only rewrite CSP via headers, before the document be parsed, not after:
Modifications to the content attribute of a meta element after the element has been parsed will be ignored.
— Content Security Policy Level 2
It's not recommended, because this open the possibility to a malicious script to be executed (disable the author's CSP rules)
Allow temporary 'unsafe-inline'
scripts sources.
Use WebExtension page action.
Note: WebDeveloper tools network tab display the original header (as defined before addons rewrite it).
Note: Does browsers have an internal limit (client side) for header length?
Firefox call stack from bookmark click to javascript: URI execution:
menupopup#BMB_bookmarksPopup.onclick - browser/base/content/browser.xul
↳ BookmarksEventHandler.onClick - browser/base/content/browser-places.js
↳ BookmarksEventHandler.onCommand - browser/base/content/browser-places.js
↳ PlacesUIUtils.openNodeWithEvent - browser/components/places/PlacesUIUtils.jsm
↳ PlacesUIUtils._openNodeIn - browser/components/places/PlacesUIUtils.jsm
↳ openUILinkIn - browser/base/content/utilityOverlay.js
↳ openLinkIn - browser/base/content/utilityOverlay.js
↳ loadURIWithFlags - toolkit/content/widgets/browser.xml
↳ loadURIWithOptions - toolkit/content/widgets/browser.xml
↳ RemoteWebNavigation#loadURIWithOptions - toolkit/components/remotebrowserutils/RemoteWebNavigation.js
↳ _sendMessage → browser.messageManager.sendAsyncMessage "WebNavigation:LoadURI" - toolkit/components/remotebrowserutils/RemoteWebNavigation.js
↳ receiveMessage "WebNavigation:LoadURI" - toolkit/content/browser-child.js
↳ loadURI - toolkit/content/browser-child.js
↳ nsDocShell::LoadURIWithOptions - docshell/base/nsDocShell.cpp
↳ nsDocShell::LoadURI - docshell/base/nsDocShell.cpp
↳ nsDocShell::InternalLoad - docshell/base/nsDocShell.cpp
↳ nsDocShell::DoURILoad - docshell/base/nsDocShell.cpp where channel = nsJSChannel dom/jsurl/nsJSProtocolHandler.cpp; uriLoader = do_GetService("@mozilla.org/uriloader;1"
↳ nsDocShell::DoChannelLoad - docshell/base/nsDocShell.cpp
↳ nsURILoader::OpenURI - uriloader/base/nsURILoader.cpp
↳ nsURILoader::OpenChannel - uriloader/base/nsURILoader.cpp
↳ nsJSChannel::GetURI - dom/jsurl/nsJSProtocolHandler.cpp
↳ ??
↳ nsJSChannel::AsyncOpen - dom/jsurl/nsJSProtocolHandler.cpp
↳ nsJSChannel::EvaluateScript - dom/jsurl/nsJSProtocolHandler.cpp