diff --git a/src/platforms/web/server/modules/attrs.js b/src/platforms/web/server/modules/attrs.js index 9e7cc06160..c3f73013e3 100644 --- a/src/platforms/web/server/modules/attrs.js +++ b/src/platforms/web/server/modules/attrs.js @@ -14,6 +14,8 @@ import { isFalsyAttrValue } from 'web/util/attrs' +import { isSSRUnsafeAttr } from 'web/server/util' + export default function renderAttrs (node: VNodeWithData): string { let attrs = node.data.attrs let res = '' @@ -34,6 +36,9 @@ export default function renderAttrs (node: VNodeWithData): string { } for (const key in attrs) { + if (isSSRUnsafeAttr(key)) { + continue + } if (key === 'style') { // leave it to the style module continue diff --git a/src/platforms/web/server/util.js b/src/platforms/web/server/util.js index 774686dae6..274897050a 100644 --- a/src/platforms/web/server/util.js +++ b/src/platforms/web/server/util.js @@ -18,6 +18,11 @@ const isAttr = makeMap( 'target,title,type,usemap,value,width,wrap' ) +const unsafeAttrCharRE = /[>/="'\u0009\u000a\u000c\u0020]/ +export const isSSRUnsafeAttr = (name: string): boolean => { + return unsafeAttrCharRE.test(name) +} + /* istanbul ignore next */ const isRenderableAttr = (name: string): boolean => { return ( diff --git a/src/server/optimizing-compiler/runtime-helpers.js b/src/server/optimizing-compiler/runtime-helpers.js index 9abfe1985d..6f65de04e5 100644 --- a/src/server/optimizing-compiler/runtime-helpers.js +++ b/src/server/optimizing-compiler/runtime-helpers.js @@ -1,6 +1,6 @@ /* @flow */ -import { escape } from 'web/server/util' +import { escape, isSSRUnsafeAttr } from 'web/server/util' import { isObject, extend } from 'shared/util' import { renderAttr } from 'web/server/modules/attrs' import { renderClass } from 'web/util/class' @@ -109,6 +109,9 @@ function renderStringList ( function renderAttrs (obj: Object): string { let res = '' for (const key in obj) { + if (isSSRUnsafeAttr(key)) { + continue + } res += renderAttr(key, obj[key]) } return res diff --git a/test/ssr/ssr-string.spec.js b/test/ssr/ssr-string.spec.js index 5300bbfefa..865ebd6a8b 100644 --- a/test/ssr/ssr-string.spec.js +++ b/test/ssr/ssr-string.spec.js @@ -929,6 +929,40 @@ describe('SSR: renderToString', () => { }) }) + it('should prevent xss in attribute names', done => { + renderVmWithOptions({ + data: { + xss: { + 'foo="bar">': '' + } + }, + template: ` +
+ ` + }, res => { + expect(res).not.toContain(``) + done() + }) + }) + + it('should prevent xss in attribute names (optimized)', done => { + renderVmWithOptions({ + data: { + xss: { + 'foo="bar">': '' + } + }, + template: ` +
+ foo +
+ ` + }, res => { + expect(res).not.toContain(``) + done() + }) + }) + it('should prevent script xss with v-bind object syntax + array value', done => { renderVmWithOptions({ data: {