User-submitted rich text content security rules
Certain security practices need to be adhered to when dealing with user-submitted TinyMCE content:
Web Application Firewall rules
WAFs often have core rules for protecting against XSS. Due to rich text editors usually including a bunch of HTML and CSS, WAFs will often block request bodies containing their output, which will present as a 403 error when submitting an AJAX call to e.g. save a user's inputted information.
HTML sanitization libraries
In order to protect your website from XSS and other attacks, you'll need to pass all rich text content received from users through some form of sanitisation filters. Many will strip out CSS styling on elements, which destroys the WYSIWYG implementation of the editor in question (and can strip out some content as well).
Solving the WAF problem: use base64 encoding
When sending AJAX requests including rich text content, encode the editor contents to base64 first - this will allow it through your firewall without causing a security risk (as any content being sent in base64 form that wasn't expected by your server isn't going to be interpreted as HTML - it won't be decoded).
Warning: the normal JavaScript methods for base64 encoding don't work on character sets with >1 byte per character (e.g Unicode!)
You can find information on how to encode base64 strings properly here: https://developer.mozilla.org/en-US/docs/Glossary/Base64#the_unicode_problem . Below is a slightly easier-to-use version of that code.
function base64ToString(base64) {
const binString = atob(base64);
let arr = Uint8Array.from(binString, (m) => m.codePointAt(0));
let decoded = new TextDecoder().decode(arr);
return decoded;
}
function stringToBase64(stringToEncode) {
let bytes = new TextEncoder().encode(stringToEncode);
const binString = String.fromCodePoint(...bytes);
let base64str = btoa(binString);
return base64str;
}
// Usage
stringToBase64("a Ā 𐀀 文 🦄"); // "YSDEgCDwkICAIOaWhyDwn6aE"
base64ToString("YSDEgCDwkICAIOaWhyDwn6aE"); // "a Ā 𐀀 文 🦄"
This allows you to send HTML requests past your WAF configuration without weakening it (by, for example, overriding its XSS inspection rules).