[mirotalksfu] - Improve security, add tests

هذا الالتزام موجود في:
Miroslav Pejic
2024-08-16 01:20:09 +02:00
الأصل 8d7901e7d0
التزام 7287363a86
6 ملفات معدلة مع 311 إضافات و58 حذوفات

عرض الملف

@@ -43,7 +43,7 @@ dependencies: {
* @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon
* @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
* @version 1.5.59
* @version 1.5.60
*
*/

عرض الملف

@@ -1,66 +1,96 @@
'use strict';
const xss = require('xss');
const { JSDOM } = require('jsdom');
const DOMPurify = require('dompurify');
const he = require('he');
// Initialize DOMPurify with jsdom
const window = new JSDOM('').window;
const purify = DOMPurify(window);
const Logger = require('./Logger');
const log = new Logger('Xss');
// Configure DOMPurify
purify.setConfig({
ALLOWED_TAGS: ['a', 'img', 'div', 'span', 'svg', 'g', 'p'], // Allow specific tags
ALLOWED_ATTR: ['href', 'src', 'title', 'id', 'class'], // Allow specific attributes
ALLOWED_URI_REGEXP: /^(?!data:|javascript:|vbscript:|file:|view-source:).*/, // Disallow dangerous URIs
});
// Clean problematic attributes
function cleanAttributes(node) {
if (node.nodeType === window.Node.ELEMENT_NODE) {
// Remove dangerous attributes
const dangerousAttributes = ['onerror', 'onclick', 'onload', 'onmouseover', 'onfocus', 'onchange', 'oninput'];
dangerousAttributes.forEach((attr) => {
if (node.hasAttribute(attr)) {
node.removeAttribute(attr);
}
});
// Handle special cases for 'data:' URIs
const src = node.getAttribute('src');
if (src && src.startsWith('data:')) {
node.removeAttribute('src');
}
// Remove unsafe 'style' attributes
if (node.hasAttribute('style')) {
const style = node.getAttribute('style');
if (style.includes('javascript:') || style.includes('data:')) {
node.removeAttribute('style');
}
}
// Remove 'title' attribute if it contains dangerous content
if (node.hasAttribute('title')) {
const title = node.getAttribute('title');
if (title.includes('javascript:') || title.includes('data:') || title.includes('onerror')) {
node.removeAttribute('title');
}
}
}
}
// Hook to clean specific attributes that can cause XSS
purify.addHook('beforeSanitizeAttributes', cleanAttributes);
// Main function to check and sanitize data
const checkXSS = (dataObject) => {
try {
if (Array.isArray(dataObject)) {
if (Object.keys(dataObject).length > 0 && typeof dataObject[0] === 'object') {
dataObject.forEach((obj) => {
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
let objectJson = objectToJSONString(obj[key]);
if (objectJson) {
let jsonString = xss(objectJson);
let jsonObject = JSONStringToObject(jsonString);
if (jsonObject) {
obj[key] = jsonObject;
}
}
}
}
});
log.debug('XSS Array of Object sanitization done');
return dataObject;
}
} else if (typeof dataObject === 'object') {
let objectJson = objectToJSONString(dataObject);
if (objectJson) {
let jsonString = xss(objectJson);
let jsonObject = JSONStringToObject(jsonString);
if (jsonObject) {
log.debug('XSS Object sanitization done');
return jsonObject;
}
}
} else if (typeof dataObject === 'string' || dataObject instanceof String) {
log.debug('XSS String sanitization done');
return xss(dataObject);
}
log.warn('XSS not sanitized', dataObject);
return dataObject;
return sanitizeData(dataObject);
} catch (error) {
log.error('XSS error', { data: dataObject, error: error });
return dataObject;
log.error('Sanitization error:', error);
return dataObject; // Return original data in case of error
}
};
function objectToJSONString(dataObject) {
try {
return JSON.stringify(dataObject);
} catch (error) {
return false;
// Recursively sanitize data based on its type
function sanitizeData(data) {
if (typeof data === 'string') {
// Decode HTML entities and URL encoded content
const decodedData = he.decode(decodeURIComponent(data));
return purify.sanitize(decodedData);
}
if (Array.isArray(data)) {
return data.map(sanitizeData);
}
if (data && typeof data === 'object') {
return sanitizeObject(data);
}
return data; // For numbers, booleans, null, undefined
}
function JSONStringToObject(jsonString) {
try {
return JSON.parse(jsonString);
} catch (error) {
return false;
}
// Sanitize object properties
function sanitizeObject(obj) {
return Object.keys(obj).reduce((acc, key) => {
acc[key] = sanitizeData(obj[key]);
return acc;
}, {});
}
module.exports = checkXSS;