Merge pull request #10537 from qazbnm456/improve-content_scripts.css

[Security] Use textContent instead innerHTML to remediate DOM based XSS
This commit is contained in:
John Kleinschmidt 2017-10-26 11:51:43 -04:00 committed by GitHub
commit beb06c0787

View file

@ -5,7 +5,7 @@ const {runInThisContext} = require('vm')
// https://developer.chrome.com/extensions/match_patterns // https://developer.chrome.com/extensions/match_patterns
const matchesPattern = function (pattern) { const matchesPattern = function (pattern) {
if (pattern === '<all_urls>') return true if (pattern === '<all_urls>') return true
const regexp = new RegExp('^' + pattern.replace(/\*/g, '.*') + '$') const regexp = new RegExp(`^${pattern.replace(/\*/g, '.*')}$`)
const url = `${location.protocol}//${location.host}${location.pathname}` const url = `${location.protocol}//${location.host}${location.pathname}`
return url.match(regexp) return url.match(regexp)
} }
@ -14,7 +14,7 @@ const matchesPattern = function (pattern) {
const runContentScript = function (extensionId, url, code) { const runContentScript = function (extensionId, url, code) {
const context = {} const context = {}
require('./chrome-api').injectTo(extensionId, false, context) require('./chrome-api').injectTo(extensionId, false, context)
const wrapper = `(function (chrome) {\n ${code}\n })` const wrapper = `((chrome) => {\n ${code}\n })`
const compiledWrapper = runInThisContext(wrapper, { const compiledWrapper = runInThisContext(wrapper, {
filename: url, filename: url,
lineOffset: 1, lineOffset: 1,
@ -23,6 +23,23 @@ const runContentScript = function (extensionId, url, code) {
return compiledWrapper.call(this, context.chrome) return compiledWrapper.call(this, context.chrome)
} }
const runStylesheet = function (url, code) {
const wrapper = `((code) => {
function init() {
const styleElement = document.createElement('style');
styleElement.textContent = code;
document.head.append(styleElement);
}
document.addEventListener('DOMContentLoaded', init);
})`
const compiledWrapper = runInThisContext(wrapper, {
filename: url,
lineOffset: 1,
displayErrors: true
})
return compiledWrapper.call(this, code)
}
// Run injected scripts. // Run injected scripts.
// https://developer.chrome.com/extensions/content_scripts // https://developer.chrome.com/extensions/content_scripts
const injectContentScript = function (extensionId, script) { const injectContentScript = function (extensionId, script) {
@ -35,19 +52,22 @@ const injectContentScript = function (extensionId, script) {
process.once('document-start', fire) process.once('document-start', fire)
} else if (script.runAt === 'document_end') { } else if (script.runAt === 'document_end') {
process.once('document-end', fire) process.once('document-end', fire)
} else if (script.runAt === 'document_idle') { } else {
document.addEventListener('DOMContentLoaded', fire) document.addEventListener('DOMContentLoaded', fire)
} }
} }
} }
if (script.css) { if (script.css) {
for (const {code} of script.css) { for (const {url, code} of script.css) {
process.once('document-end', () => { const fire = runStylesheet.bind(window, url, code)
var node = document.createElement('style') if (script.runAt === 'document_start') {
node.innerHTML = code process.once('document-start', fire)
window.document.body.appendChild(node) } else if (script.runAt === 'document_end') {
}) process.once('document-end', fire)
} else {
document.addEventListener('DOMContentLoaded', fire)
}
} }
} }
} }