security.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. // Copyright (c) Jupyter Development Team.
  2. // Distributed under the terms of the Modified BSD License.
  3. define([
  4. 'jquery',
  5. 'components/google-caja/html-css-sanitizer-minified',
  6. ], function($, sanitize) {
  7. "use strict";
  8. var noop = function (x) { return x; };
  9. var caja;
  10. if (window && window.html) {
  11. caja = window.html;
  12. caja.html4 = window.html4;
  13. caja.sanitizeStylesheet = window.sanitizeStylesheet;
  14. }
  15. var sanitizeAttribs = function (tagName, attribs, opt_naiveUriRewriter, opt_nmTokenPolicy, opt_logger) {
  16. /**
  17. * add trusting data-attributes to the default sanitizeAttribs from caja
  18. * this function is mostly copied from the caja source
  19. */
  20. var ATTRIBS = caja.html4.ATTRIBS;
  21. for (var i = 0; i < attribs.length; i += 2) {
  22. var attribName = attribs[i];
  23. if (attribName.substr(0,5) == 'data-') {
  24. var attribKey = '*::' + attribName;
  25. if (!ATTRIBS.hasOwnProperty(attribKey)) {
  26. ATTRIBS[attribKey] = 0;
  27. }
  28. }
  29. }
  30. // Caja doesn't allow data uri for img::src, see
  31. // https://github.com/google/caja/issues/1558
  32. // This is not a security issue for browser post ie6 though, so we
  33. // disable the check
  34. // https://www.owasp.org/index.php/Script_in_IMG_tags
  35. ATTRIBS['img::src'] = 0;
  36. return caja.sanitizeAttribs(tagName, attribs, opt_naiveUriRewriter, opt_nmTokenPolicy, opt_logger);
  37. };
  38. var sanitize_css = function (css, tagPolicy) {
  39. /**
  40. * sanitize CSS
  41. * like sanitize_html, but for CSS
  42. * called by sanitize_stylesheets
  43. */
  44. return caja.sanitizeStylesheet(
  45. window.location.pathname,
  46. css,
  47. {
  48. containerClass: null,
  49. idSuffix: '',
  50. tagPolicy: tagPolicy,
  51. virtualizeAttrName: noop
  52. },
  53. noop
  54. );
  55. };
  56. var sanitize_stylesheets = function (html, tagPolicy) {
  57. /**
  58. * sanitize just the css in style tags in a block of html
  59. * called by sanitize_html, if allow_css is true
  60. */
  61. var h = $("<div/>").append(html);
  62. var style_tags = h.find("style");
  63. if (!style_tags.length) {
  64. // no style tags to sanitize
  65. return html;
  66. }
  67. style_tags.each(function(i, style) {
  68. style.innerHTML = sanitize_css(style.innerHTML, tagPolicy);
  69. });
  70. return h.html();
  71. };
  72. var sanitize_html = function (html, allow_css) {
  73. /**
  74. * sanitize HTML
  75. * if allow_css is true (default: false), CSS is sanitized as well.
  76. * otherwise, CSS elements and attributes are simply removed.
  77. */
  78. var html4 = caja.html4;
  79. if (allow_css) {
  80. // allow sanitization of style tags,
  81. // not just scrubbing
  82. html4.ELEMENTS.style &= ~html4.eflags.UNSAFE;
  83. html4.ATTRIBS.style = html4.atype.STYLE;
  84. } else {
  85. // scrub all CSS
  86. html4.ELEMENTS.style |= html4.eflags.UNSAFE;
  87. html4.ATTRIBS.style = html4.atype.SCRIPT;
  88. }
  89. var record_messages = function (msg, opts) {
  90. console.log("HTML Sanitizer", msg, opts);
  91. };
  92. var policy = function (tagName, attribs) {
  93. if (!(html4.ELEMENTS[tagName] & html4.eflags.UNSAFE)) {
  94. return {
  95. 'attribs': sanitizeAttribs(tagName, attribs,
  96. noop, noop, record_messages)
  97. };
  98. } else {
  99. record_messages(tagName + " removed", {
  100. change: "removed",
  101. tagName: tagName
  102. });
  103. }
  104. };
  105. var sanitized = caja.sanitizeWithPolicy(html, policy);
  106. if (allow_css) {
  107. // sanitize style tags as stylesheets
  108. sanitized = sanitize_stylesheets(sanitized, policy);
  109. }
  110. return sanitized;
  111. };
  112. var sanitize_html_and_parse = function (html, allow_css) {
  113. /**
  114. * Sanitize HTML and parse it safely using jQuery.
  115. *
  116. * This disable's jQuery's html 'prefilter', which can make invalid
  117. * HTML valid after the sanitizer has checked it.
  118. *
  119. * Returns an array of DOM nodes.
  120. */
  121. var sanitized_html = sanitize_html(html, allow_css);
  122. var prev_htmlPrefilter = $.htmlPrefilter;
  123. $.htmlPrefilter = function(html) {return html;}; // Don't modify HTML
  124. try {
  125. return $.parseHTML(sanitized_html);
  126. } finally {
  127. $.htmlPrefilter = prev_htmlPrefilter; // Set it back again
  128. }
  129. };
  130. var security = {
  131. caja: caja,
  132. sanitize_html_and_parse: sanitize_html_and_parse,
  133. sanitize_html: sanitize_html
  134. };
  135. return security;
  136. });