Skip to content

Commit

Permalink
0.4.0-alpha.22 with Fix #363 Block blob URLs and Issue #362 Option to…
Browse files Browse the repository at this point in the history
… mitigate Chrome Canary 86 issue
  • Loading branch information
t2ym committed Jul 29, 2020
1 parent 8081b8b commit 0ef5231
Show file tree
Hide file tree
Showing 30 changed files with 318 additions and 120 deletions.
7 changes: 5 additions & 2 deletions demo-frontend/components/thin-hook/demo/bootstrap.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,11 @@ else {
hook.parameters.emptyDocumentUrl = new URL('./empty-document.html', baseURI);
hook.parameters.bootstrap = `<script>frameElement.dispatchEvent(new Event('srcdoc-load'))</script>`;
hook.parameters.onloadWrapper = `event.target.addEventListener('srcdoc-load', () => { $onload$ })`;
hook.parameters.emptySvg =
`<?xml version="1.0"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1px" height="1px"><script><![CDATA[ location = new URL("$location$?referrer=hook.parameters.emptySvg", location.ancestorOrigins ? location.ancestorOrigins[0] : "$origin$").href; ]]></script></svg>`;
// Set as true for mitigating the impacts of #362 [Vulnerability][Chrome Canary 86] SVG images and HTML documents loaded in <object>, <embed> elements bypass Service Worker
hook.parameters.hangUpOnEmbedAndObjectElement = false; // Note: If the value is true, all <embed> and <object> elements are prohibited and the app will hang up on them
hook.parameters.emptySvg = hook.parameters.hangUpOnEmbedAndObjectElement
? `<?xml version="1.0"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1px" height="1px"><script><![CDATA[ location = "about:blank"; ]]></script></svg>`
: `<?xml version="1.0"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1px" height="1px"><script><![CDATA[ location = new URL("$location$?referrer=hook.parameters.emptySvg", location.ancestorOrigins ? location.ancestorOrigins[0] : "$origin$").href; ]]></script></svg>`;
hook.parameters.bootstrapSvgScripts = `
<script xlink:href="${new URL('../../thin-hook/hook.min.js?no-hook=true&hook-name=__hook__&context-generator-name=method&discard-hook-errors=false&fallback-page=index-fb.html&hook-property=true&hook-global=true&hook-prefix=_uNpREdiC4aB1e_&compact=true&no-hook-authorization=', baseURI).href.replace(/\&/g, '&amp;').substring(location.origin.length) + noHookAuthorization}"></script>
<script xlink:href="${new URL('no-hook-authorization.js?no-hook=true', baseURI).href.substring(location.origin.length)}"></script>
Expand Down
Binary file modified demo-frontend/components/thin-hook/demo/bootstrap.js.gz
Binary file not shown.
50 changes: 25 additions & 25 deletions demo-frontend/components/thin-hook/demo/cache-bundle.json

Large diffs are not rendered by default.

Binary file modified demo-frontend/components/thin-hook/demo/cache-bundle.json.gz
Binary file not shown.
195 changes: 195 additions & 0 deletions demo-frontend/components/thin-hook/demo/hook-callback.js
Original file line number Diff line number Diff line change
Expand Up @@ -8889,6 +8889,201 @@ else {
navigator.userAgent.replace(/^.*Chrome\/([^ ]*) .*$/, '| $1 ') + '| 0.4.0-alpha.* | ' + results.map((result) => (new Intl.NumberFormat()).format(parseInt(1000 * r / result[1]))).join(' | ') + ' |');
}

// Track mutations of elements
if (self.constructor.name === 'Window') {
const console = _global.console;
const document = _global.document;
const Node = _global.Node;
const HTMLAnchorElement = _global.HTMLAnchorElement;
const HTMLAreaElement = _global.HTMLAreaElement;
const HTMLEmbedElement = _global.HTMLEmbedElement;
const HTMLObjectElement = _global.HTMLObjectElement;
const ELEMENT_NODE = Node.ELEMENT_NODE;
const TEXT_NODE = Node.TEXT_NODE;
const CDATA_SECTION_NODE = Node.CDATA_SECTION_NODE;
const PROCESSING_INSTRUCTION_NODE = Node.PROCESSING_INSTRUCTION_NODE;
const COMMENT_NODE = Node.COMMENT_NODE;
const DOCUMENT_NODE = Node.DOCUMENT_NODE;
const DOCUMENT_TYPE_NODE = Node.DOCUMENT_TYPE_NODE;
const DOCUMENT_FRAGMENT_NODE = Node.DOCUMENT_FRAGMENT_NODE;

const config = {
childList: true,
subtree: true,
attributes: true,
//attributeFilter: ['src', 'data', 'srcdoc', 'href', 'action'],
attributeOldValue: true,
characterData: true,
characterDataOldValue: true,
};

const auditURL = function (node, name, urlStr) {
let url = new URL(urlStr, location.href);
let allowed = false;
if (hook.parameters.hangUpOnEmbedAndObjectElement) {
if (node instanceof HTMLEmbedElement || node instanceof HTMLObjectElement) {
if (urlStr !== 'about:blank') {
node[name] = 'about:blank';
if (urlStr) {
_global.top.location = 'about:blank'; // The application hangs up since all <embed> and <object> nodes are unexpected and malicious
}
}
return;
}
}
switch (url.protocol) {
case 'javascript:':
if (name === 'href') {
if (!urlStr.match(/^javascript:const __[0-9a-zA-Z]*__=\$hook\$[.]\$/)) {
//console.warn(`auditURL: hooking ${node.tagName.toLowerCase()}.${name} with value "${urlStr}" for `, node);
node.setAttribute(name, urlStr);
}
}
else {
node.removeAttribute(name);
//console.warn(`auditURL: blocking ${node.tagName.toLowerCase()}.${name} with value "${urlStr}" for `, node);
}
break;
case 'http:':
case 'https:':
break;
case 'blob:':
if (node instanceof HTMLAnchorElement || node instanceof HTMLAreaElement) {
if (node.hasAttribute('download')) {
allowed = true; // <a download href="blob:*">
}
}
if (!allowed) {
node.removeAttribute(name);
//console.warn(`auditURL: blocking ${node.tagName.toLowerCase()}.${name} with value "${urlStr}" for `, node);
}
break;
case 'data:':
case 'about:':
default:
break;
}
};

const auditNode = function (node) {
switch (node.nodeType) {
case ELEMENT_NODE:
{
let tagName = node.tagName.toLowerCase();
let targets = Object.create(null);
switch (tagName) {
case 'script':
targets.src = node.src;
break;
case 'iframe':
targets.src = node.src;
targets.srcdoc = node.srcdoc;
break;
case 'object':
targets.data = node.data;
break;
case 'embed':
targets.src = node.src;
break;
case 'form':
targets.action = node.action;
break;
case 'a':
case 'area':
targets.href = node.href;
targets.download = node.download;
break;
default:
break;
}
for (let name in targets) {
switch (name) {
case 'srcdoc':
if (targets[name]) {
node.removeAttribute('srcdoc');
//console.warn(`auditURL: blocking ${node.tagName.toLowerCase()}.${name} with value "${targets[name]}" for `, node);
}
break;
case 'download':
if (!node.hasAttribute('download')) {
if (node.href && node.href.startsWith('blob:')) {
node.removeAttribute('href'); // invalidate href link for downloading
}
}
break;
default:
auditURL(node, name, targets[name]);
break;
}
}
}
break;
case TEXT_NODE:
case CDATA_SECTION_NODE:
case PROCESSING_INSTRUCTION_NODE:
case COMMENT_NODE:
case DOCUMENT_NODE:
case DOCUMENT_TYPE_NODE:
case DOCUMENT_FRAGMENT_NODE:
default:
break;
}
};

const addTargetNodes = function (targetNodes, node) {
targetNodes.add(node);
if (node.children) {
for (let child of node.children) {
addTargetNodes(targetNodes, child);
}
}
if (node.shadowRoot) {
observer.observe(node.shadowRoot, config);
for (let child of node.shadowRoot.children) {
addTargetNodes(targetNodes, child);
}
}
};

const observerCallback = function (mutations, observer) {
let targetNodes = new Set();
for(let mutation of mutations) {
switch (mutation.type) {
case 'childList':
if (mutation.addedNodes.length > 0) {
for (let node of mutation.addedNodes) {
addTargetNodes(targetNodes, node);
}
}
break;
case 'attributes':
case 'characterData':
targetNodes.add(mutation.target);
break;
default:
break;
}
}
for (let node of targetNodes) {
auditNode(node);
}
//if (targetNodes.length > 0) { console.log('observerCallback: nodes should be audited', ...targetNodes); }
};

const observer = new MutationObserver(observerCallback);

// For ShadowRoot
hook.parameters.mutationObserver = observer;
hook.parameters.mutationObserverConfig = config;

try {
observer.observe(document, config);
}
catch (e) {
console.error(e, document);
}
}

// Moved from hook-native-api.js
const enableDebugging = false;
const onUnexpectedAccessToGlobalObject = function onUnexpectedAccessToGlobalObject(op, name, value, oldValue) {
Expand Down
Binary file modified demo-frontend/components/thin-hook/demo/hook-callback.js.gz
Binary file not shown.
12 changes: 6 additions & 6 deletions demo-frontend/components/thin-hook/demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@
<html lang="en">
<head>
<meta charset="utf-8">
<script integrity="sha256-mns8c13+4QxV+A8S8eLp4eqe6EdWl3PhsaizG0OsKYI= sha256-97Eh+yQo0gHJuQ6uTiapAq7jN4Pr4+dNvr8O+tz4ngk=" src="../../thin-hook/hook.min.js?version=668&no-hook-authorization=51b5c42e7268500ddb189f40dcb8850535b85b571a8f1d89155805c7ad74609c,a578e741369d927f693fedc88c75b1a90f1a79465e2bb9774a3f68ffc6e011e6,log-no-hook-authorization&sw-root=/&no-hook=true&hook-name=__hook__&context-generator-name=method&discard-hook-errors=false&fallback-page=index-fb.html&hook-property=true&hook-global=true&hook-prefix=_uNpREdiC4aB1e_&compact=true&service-worker-ready=false"></script></head></html>
<script context-generator src="no-hook-authorization.js?no-hook=true" integrity="sha256-UbXELnJoUA3bGJ9A3LiFBTW4W1cajx2JFVgFx610YJw="></script>
<script context-generator src="integrity.js?no-hook=true" integrity="sha256-rCp6LldKuCJPgsdlv/VjanjhUe4Z5lUAU5h/jTwaTss="></script>
<script integrity="sha256-7gK/wntAhUhT3b0NaUltGtcHjn7OA+67aFEWb0gu3hg= sha256-DupMLFiwUCzQYBZtCtM0lummeQq8R4e/3K3koycPhso=" src="../../thin-hook/hook.min.js?version=668&no-hook-authorization=db5fa57d5a9fcdf6809c80c9ec4f6e3183fe05fb28a854f46818be7472a34cfd,a578e741369d927f693fedc88c75b1a90f1a79465e2bb9774a3f68ffc6e011e6,log-no-hook-authorization&sw-root=/&no-hook=true&hook-name=__hook__&context-generator-name=method&discard-hook-errors=false&fallback-page=index-fb.html&hook-property=true&hook-global=true&hook-prefix=_uNpREdiC4aB1e_&compact=true&service-worker-ready=false"></script></head></html>
<script context-generator src="no-hook-authorization.js?no-hook=true" integrity="sha256-21+lfVqfzfaAnIDJ7E9uMYP+BfsoqFT0aBi+dHKjTP0="></script>
<script context-generator src="integrity.js?no-hook=true" integrity="sha256-XAvrwgjJrOPDD1A1ouvUdk0KFkdggJCDa717R9lnjO4="></script>
<script context-generator src="disable-devtools.js?no-hook=true" integrity="sha256-qBIJIoIJlBCXrEHFvaO8HNZDdeabfIETr/aML+Zyn/I="></script>
<script context-generator src="context-generator.js?no-hook=true" integrity="sha256-Q3SuHyjOwrlpq0iIlaQmYkTWXijh+Cco/SzTkTD+DZ4="></script>
<script context-generator src="bootstrap.js?no-hook=true" integrity="sha256-TqPlk5mugojW8S5owdMaeSZi4Sw/xmbQjb39/JFLAJE="></script>
<script context-generator src="bootstrap.js?no-hook=true" integrity="sha256-K9v31fNcyLJl/7uHjINtZIbWQW/z32QiReMO9I7KffM="></script>
<script context-generator no-hook integrity="sha256-pXjnQTadkn9pP+3IjHWxqQ8aeUZeK7l3Sj9o/8bgEeY=">
{
hook.parameters.cors = [
Expand Down Expand Up @@ -49,8 +49,8 @@
};
}
</script>
<script context-generator src="cache-bundle.js?no-hook=true&authorization=f465743de4ab19b81f801ec9976d8b2108e1a64e0651a6e78e4f2616db942e5b" integrity="sha256-xZ1Ebqkx3yhzbVhtwmh3Mdrbczw8/WRMffOvs2pq45o="></script>
<script src="hook-callback.js?no-hook=true" integrity="sha256-8sKZfQkeEWnxBCpSZ0RyHLNZixEjKY/dCXOQCPqesto="></script>
<script context-generator src="cache-bundle.js?no-hook=true&authorization=1da69800cd49b566e222607d62324751bdcac8162d9a85031a0cce6ce0c3cab5" integrity="sha256-xZ1Ebqkx3yhzbVhtwmh3Mdrbczw8/WRMffOvs2pq45o="></script>
<script src="hook-callback.js?no-hook=true" integrity="sha256-tz9m8NV/pCoUQxknebU4e2kmRewnqKaUPAwGWq/FhZ0="></script>
<script context-generator src="script-hashes.js?no-hook=true&service-worker-ready=false" integrity="sha256-ugdlTRwkonG6D6fuXFXNYMAhM7DlPLa7bmNNpHOx5UA= sha256-DteoIEQQ1mutKCjqyrYXSzKRp26scMUVeZS+7SjyUhQ="></script><!--<C!-- end of mandatory no-hook scripts --C>
<script src="../../webcomponentsjs/webcomponents-lite.js"></script>
<C!-- <script no-hook>
Expand Down
4 changes: 2 additions & 2 deletions demo-frontend/components/thin-hook/demo/integrity.js
Original file line number Diff line number Diff line change
Expand Up @@ -331,8 +331,8 @@

RSA.publicKeyBits = 2048; // number of bits in RSA public key, which must be at least 2048
RSA.publicKeySize = RSA.publicKeyBits / 8; // number of bytes for RSA-OAEP encrypted data size
RSA.publicKeyBase64 = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiVA81HI8NEi8ii0PJpfOUFBWPA33YApwc0hA38Oz/CaJEoQ8Fe85sU72wPXxAlI2yLp/ZKRWywOcKfkXQ9FTrwHGk4LBhHGdt7X58JoVXdLvAU4LtSXrkka6IMmHRClgy2+6Dfxm1eZOkoYJGJYrZWzJBHCbQl69jmxoLzFyfcWwU8VwW1MDduS3/JitqRehgNH9lOz+eWtrgWCMUVHSgDAELyE/PGxJyMbIpI0M/J2SaQgTsma1ZC8/kgOZQIebVfKrOSgnILqUYkjYXpmyeEKfuA3C+QDeloC3h2VvS0mlnSt+w0VBL6MyqScJGjmaeyy4oDz3VYv4sLEnRXOlJwIDAQAB';
ECDSA.publicKeyBase64 = 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1kVabntFjtNOoE9En+qR4pT/Z1WHCvPn6yu+mpCRe30Ms8Q02YOtWBrQqLyEnIzKkXeKjzwj+fMCuAR6ulSBvg==';
RSA.publicKeyBase64 = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmRksci2aSAAPTCPs42LITZx5gEnzDyOibOmS7k3WfIEex6vLJ6y1Vojt8NToFc9D4PpoWcNN89ToQUPH2K8DSHV3KRlY3yG8JeAag8MQ3Bmg9dMkb8ed9sGpcDXmNXiAVFcz5OdUgZ5cqUEwZKWxJPX4mzMLVmH1jO861HRes/GFpSfwUR4OeL8Kfh5BhpuE8/ql08msnCcam4yCB6CtM4/Z1ON/Hr+CHTuGGhcApQGaHyMyAde/A52ezIfVmuUJdDX0xXWshqvaajG+NMdwrVlH+htlmX3WWs/CfMfz+T34j4+eM9wf4LcHa7W4rjVBiHZCgs1dNDkg5vxy/Fdk5QIDAQAB';
ECDSA.publicKeyBase64 = 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAElvO1W41dNWq18Fun+GWtyNmoVt6/kmVS3UWAA8GbCYriygjyH+XcGBCtTrAwIqYuFRS174qWXl+FCsfhfiWPYw==';
ECDSA.signatureLength = SHA256.hashBytes * 2;
ECDHE.publicKeyLength = 1 + SHA256.hashBytes * 2;

Expand Down
Binary file modified demo-frontend/components/thin-hook/demo/integrity.js.gz
Binary file not shown.
Loading

0 comments on commit 0ef5231

Please sign in to comment.