SMT-ERP 项目初始提交
This commit is contained in:
70
smtERP-web/tests/security.cjs
Normal file
70
smtERP-web/tests/security.cjs
Normal file
@@ -0,0 +1,70 @@
|
||||
const assert = require('assert')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const vm = require('vm')
|
||||
const babel = require('@babel/core')
|
||||
const compiler = require('vue-template-compiler')
|
||||
const { JSDOM } = require('jsdom')
|
||||
const browser = new JSDOM('', { url: 'https://erp.example.test' }).window
|
||||
const purifier = require('dompurify')(browser)
|
||||
|
||||
function loadSource (relative, dependencies = {}) {
|
||||
const filename = path.join(__dirname, '..', relative)
|
||||
const source = fs.readFileSync(filename, 'utf8')
|
||||
const script = relative.endsWith('.vue') ? compiler.parseComponent(source).script.content : source
|
||||
const transformed = babel.transformSync(script, {
|
||||
babelrc: false,
|
||||
configFile: false,
|
||||
plugins: ['@babel/plugin-transform-modules-commonjs']
|
||||
}).code
|
||||
const exports = {}
|
||||
vm.runInNewContext(transformed, {
|
||||
exports,
|
||||
require: name => {
|
||||
assert.ok(Object.prototype.hasOwnProperty.call(dependencies, name), `Unexpected import ${name}`)
|
||||
return dependencies[name]
|
||||
},
|
||||
window: browser,
|
||||
console: { log () {}, warn () {} }
|
||||
}, { filename })
|
||||
return exports
|
||||
}
|
||||
|
||||
const menu = loadSource('src/utils/menuUrl.js')
|
||||
browser._CONFIG = { domianURL: '/apis' }
|
||||
assert.strictEqual(menu.resolveMenuUrl('{{ window._CONFIG.domianURL }}/report', browser), '/apis/report')
|
||||
assert.strictEqual(menu.resolveMenuUrl("{{ window._CONFIG['domianURL'] }}/report", browser), '/apis/report')
|
||||
assert.strictEqual(menu.resolveMenuUrl('{{ window.location.origin }}/report', browser), 'https://erp.example.test/report')
|
||||
assert.strictEqual(menu.resolveMenuUrl('/dashboard/analysis', browser), '/dashboard/analysis')
|
||||
const attack = '{{ window.compromised = true }}'
|
||||
assert.strictEqual(menu.resolveMenuUrl(attack, browser), attack)
|
||||
assert.strictEqual(browser.compromised, undefined)
|
||||
assert.strictEqual(menu.resolveMenuUrl('{{ constructor.constructor("alert(1)")() }}', browser),
|
||||
'{{ constructor.constructor("alert(1)")() }}')
|
||||
console.log('PASS: supported menu placeholders and malicious expressions')
|
||||
|
||||
const announcement = loadSource('src/components/tools/ShowAnnouncement.vue', { dompurify: purifier }).default
|
||||
const safeContent = content => announcement.computed.safeContent.call({ record: { msgContent: content } })
|
||||
assert.strictEqual(safeContent('<p>中文公告 <strong>加粗</strong></p>'), '<p>中文公告 <strong>加粗</strong></p>')
|
||||
assert.strictEqual(safeContent(null), '')
|
||||
const sanitized = safeContent('<p>公告</p><script>alert(1)</script><img src=x onerror=alert(1)>' +
|
||||
'<a href="javascript:alert(1)">link</a><svg onload=alert(1)></svg><iframe srcdoc="bad"></iframe>')
|
||||
assert.ok(sanitized.includes('<p>公告</p>'))
|
||||
assert.ok(!/script|onerror|onload|javascript:|svg|iframe/i.test(sanitized))
|
||||
const vueSource = fs.readFileSync(path.join(__dirname, '../src/components/tools/ShowAnnouncement.vue'), 'utf8')
|
||||
assert.ok(compiler.compile(compiler.parseComponent(vueSource).template.content).render.includes('safeContent'))
|
||||
console.log('PASS: rich-text formatting retained and XSS payloads removed')
|
||||
|
||||
const notice = loadSource('src/components/tools/HeaderNotice.vue', {
|
||||
'@/api/manage': {}, './ShowAnnouncement': {}, '@/store/': {}, './DynamicNotice': {}, '@/views/system/MsgList': {}
|
||||
}).default
|
||||
let updates = 0
|
||||
const receive = data => notice.methods.websocketOnmessage.call({ loadData () { updates++ } }, { data })
|
||||
receive('{"cmd":"topic"}')
|
||||
receive('{"cmd":"user"}')
|
||||
assert.strictEqual(updates, 2)
|
||||
for (const input of ['null', '[]', '42', 'invalid', '{"cmd":"heartbeat"}', '(window.compromised=true)']) receive(input)
|
||||
assert.strictEqual(updates, 2)
|
||||
assert.strictEqual(browser.compromised, undefined)
|
||||
browser.close()
|
||||
console.log('PASS: notification commands preserved and executable/non-object payloads ignored')
|
||||
Reference in New Issue
Block a user