feat(core): 限制dangerouslySetInnerHTML API生效的条件,减少XSS攻击面

This commit is contained in:
huangxuan 2024-04-02 10:47:31 +08:00
parent ec34490202
commit ebfe1eceb9
No known key found for this signature in database
GPG Key ID: E79F50C67022565D
2 changed files with 43 additions and 0 deletions

View File

@ -95,4 +95,16 @@ describe('Dom Attribute', () => {
Inula.render(<div {...emptyStringProps} />, container);
}).not.toThrow();
});
it('dangerouslySetInnerHTML和children同时设置只渲染children', () => {
Inula.act(() => {
Inula.render(
<div className="root" dangerouslySetInnerHTML={{ __html: '1234' }}>
123
</div>,
container
);
});
expect(container.innerHTML).toBe('<div class="root">123</div>');
});
});

View File

@ -17,6 +17,25 @@ import { getPropDetails, PROPERTY_TYPE, PropDetails } from './PropertiesData';
const INVALID_EVENT_NAME_REGEX = /^on[^A-Z]/;
const voidTagElements = [
'area',
'base',
'br',
'col',
'embed',
'hr',
'img',
'input',
'keygen',
'link',
'meta',
'param',
'source',
'track',
'wbr',
'menuitem',
];
// 是内置元素
export function isNativeElement(tagName: string, props: Record<string, any>) {
return !tagName.includes('-') && props.is === undefined;
@ -108,6 +127,18 @@ export function validateProps(type, props) {
throw new Error('style should be a object.');
}
// 对于没有children的元素设置dangerouslySetInnerHTML不生效
if (voidTagElements.includes(type)) {
if (props.dangerouslySetInnerHTML != null) {
delete props.dangerouslySetInnerHTML;
}
}
// dangerouslySetInnerHTML和children同时设置只渲染children
if (props.dangerouslySetInnerHTML != null && props.children != null) {
delete props.dangerouslySetInnerHTML;
}
if (isDev) {
// 校验属性
const invalidProps = Object.keys(props).filter(key => !isValidProp(type, key, props[key]));