Просмотр исходного кода

Merge pull request #217 from weseek/imprv/215-prevent-xss

Imprv/215 prevent xss
Yuki Takei 8 лет назад
Родитель
Сommit
c8bf8f061e
8 измененных файлов с 72 добавлено и 5 удалено
  1. 1 2
      CHANGES.md
  2. 2 2
      README.md
  3. 13 0
      lib/models/revision.js
  4. 27 0
      lib/util/xss.js
  5. 2 1
      package.json
  6. 2 0
      resource/js/util/CrowiRenderer.js
  7. 14 0
      resource/js/util/PreProcessor/XssFilter.js
  8. 11 0
      yarn.lock

+ 1 - 2
CHANGES.md

@@ -4,6 +4,7 @@ CHANGES
 ## 2.3.0-RC3
 
 * Feature: LDAP Authentication
+* Imprv: Prevent XSS
 * Fix: node versions couldn't be shown
 * Support: Upgrade libs
     * express-pino-logger
@@ -15,8 +16,6 @@ CHANGES
 * Fix: HeaderSearchBox didn't append 'q=' param when searching
     * Degraded by 2.2.3 updates
 
-* Feature: LDAP Authentication
-
 ## 2.2.3
 
 * Fix: The server responds anything when using passport

+ 2 - 2
README.md

@@ -30,8 +30,8 @@ Why crowi-plus?
   * Adopt the fastest logger [pino](https://github.com/pinojs/pino)
   * Using CDN
 * **Secure**
-  * Upgrade jQuery to 3.x
-  * Upgrade other insecure libs
+  * Prevent XSS (Cross Site Scripting)
+  * Upgrade jQuery to 3.x and other insecure libs
   * The official Crowi status is [![dependencies Status](https://david-dm.org/crowi/crowi/status.svg)](https://david-dm.org/crowi/crowi) [![devDependencies Status](https://david-dm.org/crowi/crowi/dev-status.svg)](https://david-dm.org/crowi/crowi?type=dev)
 * **Convenient**
   * Support LDAP Authentication

+ 13 - 0
lib/models/revision.js

@@ -1,6 +1,7 @@
 module.exports = function(crowi) {
   var debug = require('debug')('crowi:models:revision')
     , mongoose = require('mongoose')
+    , Xss = require('../util/xss')
     , ObjectId = mongoose.Schema.Types.ObjectId
     , revisionSchema;
 
@@ -12,6 +13,18 @@ module.exports = function(crowi) {
     createdAt: { type: Date, default: Date.now }
   });
 
+  /*
+   * preparation for https://github.com/weseek/crowi-plus/issues/216
+   */
+  // // create a XSS Filter instance
+  // // TODO read options
+  // this.xss = new Xss(true);
+  // // prevent XSS when pre save
+  // revisionSchema.pre('save', function(next) {
+  //   this.body = xss.process(this.body);
+  //   next();
+  // });
+
   revisionSchema.statics.findLatestRevision = function(path, cb) {
     this.find({path: path})
       .sort({createdAt: -1})

+ 27 - 0
lib/util/xss.js

@@ -0,0 +1,27 @@
+class Xss {
+
+  constructor(isAllowAllAttrs) {
+    const xss = require('xss');
+
+    // create the option object
+    let option = {
+      stripIgnoreTag: true,
+      css: false,
+    };
+    if (isAllowAllAttrs) {
+      // allow all attributes
+      option.onTagAttr = function(tag, name, value, isWhiteAttr) {
+        return `${name}="${value}"`;
+      }
+    }
+    // create the XSS Filter instance
+    this.myxss = new xss.FilterXSS(option);
+  }
+
+  process(markdown) {
+    return this.myxss.process(markdown);
+  }
+
+}
+
+module.exports = Xss;

+ 2 - 1
package.json

@@ -125,7 +125,8 @@
     "uglifycss": "^0.0.27",
     "webpack": "^3.1.0",
     "webpack-bundle-analyzer": "^2.9.0",
-    "webpack-merge": "~4.1.0"
+    "webpack-merge": "~4.1.0",
+    "xss": "^0.3.5"
   },
   "devDependencies": {
     "chai": "^4.1.0",

+ 2 - 0
resource/js/util/CrowiRenderer.js

@@ -4,6 +4,7 @@ import hljs from 'highlight.js';
 import MarkdownFixer from './PreProcessor/MarkdownFixer';
 import Linker        from './PreProcessor/Linker';
 import ImageExpander from './PreProcessor/ImageExpander';
+import XssFilter     from './PreProcessor/XssFilter';
 
 import Emoji         from './PostProcessor/Emoji';
 import Mathjax       from './PostProcessor/Mathjax';
@@ -22,6 +23,7 @@ export default class CrowiRenderer {
       new MarkdownFixer(crowi),
       new Linker(crowi),
       new ImageExpander(crowi),
+      new XssFilter(crowi),
     ];
     this.postProcessors = [
       new Emoji(crowi),

+ 14 - 0
resource/js/util/PreProcessor/XssFilter.js

@@ -0,0 +1,14 @@
+import Xss from '../../../../lib/util/xss';
+
+export default class XssFilter {
+
+  constructor(crowi) {
+    // TODO read options
+    this.xss = new Xss(true);
+  }
+
+  process(markdown) {
+    return this.xss.process(markdown);
+  }
+
+}

+ 11 - 0
yarn.lock

@@ -1705,6 +1705,10 @@ cssesc@^0.1.0:
   version "0.1.0"
   resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4"
 
+cssfilter@0.0.10:
+  version "0.0.10"
+  resolved "https://registry.yarnpkg.com/cssfilter/-/cssfilter-0.0.10.tgz#c6d2672632a2e5c83e013e6864a42ce8defd20ae"
+
 "cssnano@>=2.6.1 <4":
   version "3.10.0"
   resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-3.10.0.tgz#4f38f6cea2b9b17fa01490f23f1dc68ea65c1c38"
@@ -6358,6 +6362,13 @@ xmlhttprequest-ssl@~1.5.4:
   version "1.5.4"
   resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.4.tgz#04f560915724b389088715cc0ed7813e9677bf57"
 
+xss@^0.3.5:
+  version "0.3.5"
+  resolved "https://registry.yarnpkg.com/xss/-/xss-0.3.5.tgz#cc1d6400a010809e79e5401c3a523fef8792b44c"
+  dependencies:
+    commander "^2.9.0"
+    cssfilter "0.0.10"
+
 xtend@^4.0.0, xtend@~4.0.1:
   version "4.0.1"
   resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"