Jelajahi Sumber

Merge pull request #916 from weseek/fix/908-xss-prevents-autolink

Fix/908 xss prevents autolink
Yuki Takei 7 tahun lalu
induk
melakukan
386c5f0456

+ 3 - 0
CHANGES.md

@@ -2,10 +2,13 @@
 
 ## 3.4.5-RC
 
+* Improvement: Pass autolink through the XSS filter according to CommonMark Spec
+* Fix: Update ElasticSearch index when deleting/duplicating pages
 * Fix: Xss filter breaks PlantUML arrows
 * Support: Support growi-plugin-lsx@2.2.0
 * Support: Upgrade libs
     * growi-commons
+    * xss
 
 ## 3.4.4
 

+ 1 - 1
package.json

@@ -124,7 +124,7 @@
     "swig-templates": "^2.0.2",
     "uglifycss": "^0.0.29",
     "url-join": "^4.0.0",
-    "xss": "^1.0.3"
+    "xss": "^1.0.6"
   },
   "devDependencies": {
     "@alienfast/i18next-loader": "^1.0.16",

+ 42 - 0
src/lib/service/xss/commonmark-spec.js

@@ -0,0 +1,42 @@
+/**
+ * Valid schemes
+ * @see https://spec.commonmark.org/0.16/#autolinks
+ */
+const schemesForAutolink = [
+  'coap', 'doi', 'javascript', 'aaa', 'aaas', 'about', 'acap', 'cap', 'cid', 'crid', 'data', 'dav', 'dict', 'dns',
+  'file', 'ftp', 'geo', 'go', 'gopher', 'h323', 'http', 'https', 'iax', 'icap', 'im', 'imap', 'info', 'ipp', 'iris',
+  'iris.beep', 'iris.xpc', 'iris.xpcs', 'iris.lwz', 'ldap', 'mailto', 'mid', 'msrp', 'msrps', 'mtqp', 'mupdate',
+  'news', 'nfs', 'ni', 'nih', 'nntp', 'opaquelocktoken', 'pop', 'pres', 'rtsp', 'service', 'session', 'shttp',
+  'sieve', 'sip', 'sips', 'sms', 'snmp,soap.beep', 'soap.beeps', 'tag', 'tel', 'telnet', 'tftp', 'thismessage',
+  'tn3270', 'tip', 'tv', 'urn', 'vemmi', 'ws', 'wss', 'xcon', 'xcon-userid', 'xmlrpc.beep', 'xmlrpc.beeps', 'xmpp',
+  'z39.50r', 'z39.50s', 'adiumxtra', 'afp', 'afs', 'aim', 'apt,attachment', 'aw', 'beshare', 'bitcoin', 'bolo',
+  'callto', 'chrome,chrome-extension', 'com-eventbrite-attendee', 'content', 'cvs,dlna-playsingle', 'dlna-playcontainer',
+  'dtn', 'dvb', 'ed2k', 'facetime', 'feed', 'finger', 'fish', 'gg', 'git', 'gizmoproject', 'gtalk', 'hcp', 'icon',
+  'ipn', 'irc', 'irc6', 'ircs', 'itms', 'jar', 'jms', 'keyparc', 'lastfm', 'ldaps', 'magnet', 'maps', 'market,message',
+  'mms', 'ms-help', 'msnim', 'mumble', 'mvn', 'notes', 'oid', 'palm', 'paparazzi', 'platform', 'proxy', 'psyc',
+  'query', 'res', 'resource', 'rmi', 'rsync', 'rtmp', 'secondlife', 'sftp', 'sgn', 'skype', 'smb', 'soldat', 'spotify',
+  'ssh', 'steam', 'svn', 'teamspeak', 'things', 'udp', 'unreal', 'ut2004', 'ventrilo', 'view-source', 'webcal',
+  'wtai', 'wyciwyg', 'xfire', 'xri', 'ymsgr',
+];
+const schemesCondition = schemesForAutolink.join('|');
+
+/**
+ * RegExp for URI
+ * @type {RegExp}
+ * @see https://spec.commonmark.org/0.16/#autolinks
+ */
+const uriAutolinkRegexp = new RegExp(`^(${schemesCondition}):\\/\\/.+$`);
+
+/**
+ * RegExp for email
+ * @type {RegExp}
+ * @see https://spec.commonmark.org/0.16/#autolinks
+ */
+// eslint-disable-next-line max-len
+const emailAutolinkRegexp = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
+
+
+module.exports = {
+  uriAutolinkRegexp,
+  emailAutolinkRegexp,
+};

+ 9 - 1
src/lib/service/xss/index.js

@@ -1,7 +1,9 @@
+const xss = require('xss');
+const commonmarkSpec = require('./commonmark-spec');
+
 class Xss {
 
   constructor(xssOption) {
-    const xss = require('xss');
 
     xssOption = xssOption || {}; // eslint-disable-line no-param-reassign
 
@@ -17,6 +19,12 @@ class Xss {
       css: false,
       whiteList: whiteListContent,
       escapeHtml: (html) => { return html }, // resolve https://github.com/weseek/growi/issues/221
+      onTag: (tag, html, options) => {
+        // pass autolink
+        if (tag.match(commonmarkSpec.uriAutolinkRegexp) || tag.match(commonmarkSpec.emailAutolinkRegexp)) {
+          return html;
+        }
+      },
     };
 
     tagWhiteList.forEach((tag) => {

+ 0 - 0
src/lib/service/xss/recommendedXssWhiteList.js → src/lib/service/xss/recommended-whitelist.js


+ 3 - 3
src/lib/service/xss/xssOption.js

@@ -1,12 +1,12 @@
 class XssOption {
 
   constructor(config) {
-    const recommendedXssWhiteList = require('./recommendedXssWhiteList');
+    const recommendedWhitelist = require('./recommended-whitelist');
     const initializedConfig = (config != null) ? config : {};
 
     this.isEnabledXssPrevention = initializedConfig.isEnabledXssPrevention || true;
-    this.tagWhiteList = initializedConfig.tagWhiteList || recommendedXssWhiteList.tags;
-    this.attrWhiteList = initializedConfig.attrWhiteList || recommendedXssWhiteList.attrs;
+    this.tagWhiteList = initializedConfig.tagWhiteList || recommendedWhitelist.tags;
+    this.attrWhiteList = initializedConfig.attrWhiteList || recommendedWhitelist.attrs;
   }
 
 }

+ 3 - 3
src/server/models/config.js

@@ -7,7 +7,7 @@ module.exports = function(crowi) {
   const mongoose = require('mongoose');
   const debug = require('debug')('growi:models:config');
   const uglifycss = require('uglifycss');
-  const recommendedXssWhiteList = require('@commons/service/xss/recommendedXssWhiteList');
+  const recommendedWhitelist = require('@commons/service/xss/recommended-whitelist');
 
   const SECURITY_RESTRICT_GUEST_MODE_DENY = 'Deny';
   const SECURITY_RESTRICT_GUEST_MODE_READONLY = 'Readonly';
@@ -430,7 +430,7 @@ module.exports = function(crowi) {
           return [];
 
         case 2: // recommended
-          return recommendedXssWhiteList.tags;
+          return recommendedWhitelist.tags;
 
         case 3: // custom white list
           return config.markdown[key];
@@ -453,7 +453,7 @@ module.exports = function(crowi) {
           return [];
 
         case 2: // recommended
-          return recommendedXssWhiteList.attrs;
+          return recommendedWhitelist.attrs;
 
         case 3: // custom white list
           return config.markdown[key];

+ 2 - 2
src/server/routes/admin.js

@@ -14,7 +14,7 @@ module.exports = function(crowi, app) {
   const GlobalNotificationMailSetting = models.GlobalNotificationMailSetting;
   const GlobalNotificationSlackSetting = models.GlobalNotificationSlackSetting; // eslint-disable-line no-unused-vars
 
-  const recommendedXssWhiteList = require('@commons/service/xss/recommendedXssWhiteList');
+  const recommendedWhitelist = require('@commons/service/xss/recommended-whitelist');
   const PluginUtils = require('../plugins/plugin-utils');
   const ApiResponse = require('../util/apiResponse');
   const importer = require('../util/importer')(crowi);
@@ -117,7 +117,7 @@ module.exports = function(crowi, app) {
 
     return res.render('admin/markdown', {
       markdownSetting,
-      recommendedXssWhiteList,
+      recommendedWhitelist,
     });
   };
 

+ 2 - 2
src/server/views/admin/markdown.html

@@ -193,11 +193,11 @@
               <p class="font-weight-bold">{{ t('markdown_setting.Recommended setting') }}</p>
               <div class="m-t-15">
                 {{ t('markdown_setting.Tag names') }}
-                <textarea class="form-control xss-list" name="recommendedTags" rows="6" cols="40" readonly>{{ recommendedXssWhiteList.tags }}</textarea>
+                <textarea class="form-control xss-list" name="recommendedTags" rows="6" cols="40" readonly>{{ recommendedWhitelist.tags }}</textarea>
               </div>
               <div class="m-t-15">
                 {{ t('markdown_setting.Tag attributes') }}
-                <textarea class="form-control xss-list" name="recommendedAttrs" rows="6" cols="40" readonly>{{ recommendedXssWhiteList.attrs }}</textarea>
+                <textarea class="form-control xss-list" name="recommendedAttrs" rows="6" cols="40" readonly>{{ recommendedWhitelist.attrs }}</textarea>
               </div>
             </label>
           </div>

+ 4 - 3
yarn.lock

@@ -11601,9 +11601,10 @@ xpath@0.0.27:
   version "0.0.27"
   resolved "https://registry.yarnpkg.com/xpath/-/xpath-0.0.27.tgz#dd3421fbdcc5646ac32c48531b4d7e9d0c2cfa92"
 
-xss@^1.0.3:
-  version "1.0.3"
-  resolved "https://registry.yarnpkg.com/xss/-/xss-1.0.3.tgz#d04bd2558fd6c29c46113824d5e8b2a910054e23"
+xss@^1.0.6:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/xss/-/xss-1.0.6.tgz#eaf11e9fc476e3ae289944a1009efddd8a124b51"
+  integrity sha512-6Q9TPBeNyoTRxgZFk5Ggaepk/4vUOYdOsIUYvLehcsIZTFjaavbVnsuAkLA5lIFuug5hw8zxcB9tm01gsjph2A==
   dependencies:
     commander "^2.9.0"
     cssfilter "0.0.10"