From b58704a5ce079b2769ea14ebd08792452a5c74e0 Mon Sep 17 00:00:00 2001 From: Mrugesh Mohapatra <1884376+raisedadead@users.noreply.github.com> Date: Tue, 28 Jul 2020 14:05:56 +0530 Subject: [PATCH] fix: harden username blocklist (#39281) * fix: harden username blocklist Co-authored-by: Oliver Eyton-Williams --- api-server/common/models/user.js | 21 +- api-server/package-lock.json | 13 + api-server/package.json | 1 + api-server/server/utils/constants.js | 535 ++++++++++++++++++++++++++- 4 files changed, 560 insertions(+), 10 deletions(-) diff --git a/api-server/common/models/user.js b/api-server/common/models/user.js index ecf56f0bbb..543a17bceb 100644 --- a/api-server/common/models/user.js +++ b/api-server/common/models/user.js @@ -13,6 +13,7 @@ import debugFactory from 'debug'; import { isEmail } from 'validator'; import _ from 'lodash'; import generate from 'nanoid/generate'; +import badwordFilter from 'bad-words'; import { apiLocation } from '../../../config/env'; @@ -25,7 +26,7 @@ import { renderSignInEmail } from '../utils'; -import { blacklistedUsernames } from '../../server/utils/constants.js'; +import { blocklistedUsernames } from '../../server/utils/constants.js'; import { wrapHandledError } from '../../server/utils/create-handled-error.js'; import { saveUser, observeMethod } from '../../server/utils/rx.js'; import { getEmailSender } from '../../server/utils/url-utils'; @@ -160,10 +161,10 @@ export default function(User) { // increase user accessToken ttl to 900 days User.settings.ttl = 900 * 24 * 60 * 60 * 1000; - // username should not be in blacklist + // username should not be in blocklist User.validatesExclusionOf('username', { - in: blacklistedUsernames, - message: 'is taken' + in: blocklistedUsernames, + message: 'is not available' }); // username should be unique @@ -347,10 +348,14 @@ export default function(User) { if (!username && (!email || !isEmail(email))) { return Promise.resolve(false); } - log('checking existence'); - - // check to see if username is on blacklist - if (username && blacklistedUsernames.indexOf(username) !== -1) { + log('check if username is available'); + // check to see if username is on blocklist + const usernameFilter = new badwordFilter(); + if ( + username && + (blocklistedUsernames.includes(username) || + usernameFilter.isProfane(username)) + ) { return Promise.resolve(true); } diff --git a/api-server/package-lock.json b/api-server/package-lock.json index 90f06d89e9..0f3298604b 100644 --- a/api-server/package-lock.json +++ b/api-server/package-lock.json @@ -2722,6 +2722,19 @@ } } }, + "bad-words": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/bad-words/-/bad-words-3.0.3.tgz", + "integrity": "sha512-To+nGz+U8SpEQieZ2kSadY/1hVO88UXAslCJuTgLjDOuGrs/tNW2BYwl0fctxcRLooe0nzYN1pGzgvRIrd0BeA==", + "requires": { + "badwords-list": "^1.0.0" + } + }, + "badwords-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/badwords-list/-/badwords-list-1.0.0.tgz", + "integrity": "sha1-XphW2/E0gqKVw7CzBK+51M/FxXk=" + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", diff --git a/api-server/package.json b/api-server/package.json index 2936f7e187..3db276cbd7 100644 --- a/api-server/package.json +++ b/api-server/package.json @@ -18,6 +18,7 @@ "accepts": "^1.3.7", "auth0-js": "^9.13.2", "axios": "^0.19.2", + "bad-words": "^3.0.3", "body-parser": "^1.19.0", "chai": "~3.4.1", "compression": "^1.7.4", diff --git a/api-server/server/utils/constants.js b/api-server/server/utils/constants.js index 39c469a8f2..ee2faf92ff 100644 --- a/api-server/server/utils/constants.js +++ b/api-server/server/utils/constants.js @@ -4,7 +4,7 @@ for (let i = 0; i < 26; i++) { alphabet = alphabet.concat(String.fromCharCode(97 + i)); } -export const blacklistedUsernames = [ +let blocklist = [ ...alphabet.split(''), 'about', 'academic-honesty', @@ -59,6 +59,7 @@ export const blacklistedUsernames = [ 'pmi-acp-agile-project-managers', 'privacy-policy', 'privacy', + 'profile', 'project-completed', 'reset', 'services', @@ -83,5 +84,535 @@ export const blacklistedUsernames = [ 'update-my-theme', 'update-my-username', 'user', - 'wiki' + 'username', + 'wiki', + + // some more names from https://github.com/marteinn/The-Big-Username-Blacklist-JS/blob/master/src/list.js + '.htaccess', + '.htpasswd', + '.well-known', + '400', + '401', + '403', + '404', + '405', + '406', + '407', + '408', + '409', + '410', + '411', + '412', + '413', + '414', + '415', + '416', + '417', + '421', + '422', + '423', + '424', + '426', + '428', + '429', + '431', + '500', + '501', + '502', + '503', + '504', + '505', + '506', + '507', + '508', + '509', + '510', + '511', + 'about', + 'about-us', + 'abuse', + 'access', + 'account', + 'accounts', + 'ad', + 'add', + 'admin', + 'administration', + 'administrator', + 'ads', + 'advertise', + 'advertising', + 'aes128-ctr', + 'aes128-gcm', + 'aes192-ctr', + 'aes256-ctr', + 'aes256-gcm', + 'affiliate', + 'affiliates', + 'ajax', + 'alert', + 'alerts', + 'alpha', + 'amp', + 'analytics', + 'api', + 'app', + 'apps', + 'asc', + 'assets', + 'atom', + 'auth', + 'authentication', + 'authorize', + 'autoconfig', + 'autodiscover', + 'avatar', + 'backup', + 'banner', + 'banners', + 'beta', + 'billing', + 'billings', + 'blog', + 'blogs', + 'board', + 'bookmark', + 'bookmarks', + 'broadcasthost', + 'business', + 'buy', + 'cache', + 'calendar', + 'campaign', + 'captcha', + 'careers', + 'cart', + 'cas', + 'categories', + 'category', + 'cdn', + 'cgi', + 'cgi-bin', + 'chacha20-poly1305', + 'change', + 'channel', + 'channels', + 'chart', + 'chat', + 'checkout', + 'clear', + 'client', + 'close', + 'cms', + 'com', + 'comment', + 'comments', + 'community', + 'compare', + 'compose', + 'config', + 'connect', + 'contact', + 'contest', + 'cookies', + 'copy', + 'copyright', + 'count', + 'create', + 'crossdomain.xml', + 'css', + 'curve25519-sha256', + 'customer', + 'customers', + 'customize', + 'dashboard', + 'db', + 'deals', + 'debug', + 'delete', + 'desc', + 'destroy', + 'dev', + 'developer', + 'developers', + 'diffie-hellman-group-exchange-sha256', + 'diffie-hellman-group14-sha1', + 'disconnect', + 'discuss', + 'dns', + 'dns0', + 'dns1', + 'dns2', + 'dns3', + 'dns4', + 'docs', + 'documentation', + 'domain', + 'download', + 'downloads', + 'downvote', + 'draft', + 'drop', + 'ecdh-sha2-nistp256', + 'ecdh-sha2-nistp384', + 'ecdh-sha2-nistp521', + 'edit', + 'editor', + 'email', + 'enterprise', + 'error', + 'errors', + 'event', + 'events', + 'example', + 'exception', + 'exit', + 'explore', + 'export', + 'extensions', + 'false', + 'family', + 'faq', + 'faqs', + 'favicon.ico', + 'features', + 'feed', + 'feedback', + 'feeds', + 'file', + 'files', + 'filter', + 'follow', + 'follower', + 'followers', + 'following', + 'fonts', + 'forgot', + 'forgot-password', + 'forgotpassword', + 'form', + 'forms', + 'forum', + 'forums', + 'friend', + 'friends', + 'ftp', + 'get', + 'git', + 'go', + 'group', + 'groups', + 'guest', + 'guidelines', + 'guides', + 'head', + 'header', + 'help', + 'hide', + 'hmac-sha', + 'hmac-sha1', + 'hmac-sha1-etm', + 'hmac-sha2-256', + 'hmac-sha2-256-etm', + 'hmac-sha2-512', + 'hmac-sha2-512-etm', + 'home', + 'host', + 'hosting', + 'hostmaster', + 'htpasswd', + 'http', + 'httpd', + 'https', + 'humans.txt', + 'icons', + 'images', + 'imap', + 'img', + 'import', + 'index', + 'info', + 'insert', + 'investors', + 'invitations', + 'invite', + 'invites', + 'invoice', + 'is', + 'isatap', + 'issues', + 'it', + 'jobs', + 'join', + 'js', + 'json', + 'keybase.txt', + 'learn', + 'legal', + 'license', + 'licensing', + 'like', + 'limit', + 'live', + 'load', + 'local', + 'localdomain', + 'localhost', + 'lock', + 'login', + 'logout', + 'lost-password', + 'mail', + 'mail0', + 'mail1', + 'mail2', + 'mail3', + 'mail4', + 'mail5', + 'mail6', + 'mail7', + 'mail8', + 'mail9', + 'mailer-daemon', + 'mailerdaemon', + 'map', + 'marketing', + 'marketplace', + 'master', + 'me', + 'media', + 'member', + 'members', + 'message', + 'messages', + 'metrics', + 'mis', + 'mobile', + 'moderator', + 'modify', + 'more', + 'mx', + 'my', + 'net', + 'network', + 'new', + 'news', + 'newsletter', + 'newsletters', + 'next', + 'nil', + 'no-reply', + 'nobody', + 'noc', + 'none', + 'noreply', + 'notification', + 'notifications', + 'ns', + 'ns0', + 'ns1', + 'ns2', + 'ns3', + 'ns4', + 'ns5', + 'ns6', + 'ns7', + 'ns8', + 'ns9', + 'null', + 'oauth', + 'oauth2', + 'offer', + 'offers', + 'online', + 'openid', + 'order', + 'orders', + 'overview', + 'owner', + 'page', + 'pages', + 'partners', + 'passwd', + 'password', + 'pay', + 'payment', + 'payments', + 'photo', + 'photos', + 'pixel', + 'plans', + 'plugins', + 'policies', + 'policy', + 'pop', + 'pop3', + 'popular', + 'portfolio', + 'post', + 'postfix', + 'postmaster', + 'poweruser', + 'preferences', + 'premium', + 'press', + 'previous', + 'pricing', + 'print', + 'privacy', + 'privacy-policy', + 'private', + 'prod', + 'product', + 'production', + 'profile', + 'profiles', + 'project', + 'projects', + 'public', + 'purchase', + 'put', + 'quota', + 'redirect', + 'reduce', + 'refund', + 'refunds', + 'register', + 'registration', + 'remove', + 'replies', + 'reply', + 'report', + 'request', + 'request-password', + 'reset', + 'reset-password', + 'response', + 'return', + 'returns', + 'review', + 'reviews', + 'robots.txt', + 'root', + 'rootuser', + 'rsa-sha2-2', + 'rsa-sha2-512', + 'rss', + 'rules', + 'sales', + 'save', + 'script', + 'sdk', + 'search', + 'secure', + 'security', + 'select', + 'services', + 'session', + 'sessions', + 'settings', + 'setup', + 'share', + 'shift', + 'shop', + 'signin', + 'signup', + 'site', + 'sitemap', + 'sites', + 'smtp', + 'sort', + 'source', + 'sql', + 'ssh', + 'ssh-rsa', + 'ssl', + 'ssladmin', + 'ssladministrator', + 'sslwebmaster', + 'stage', + 'staging', + 'stat', + 'static', + 'statistics', + 'stats', + 'status', + 'store', + 'style', + 'styles', + 'stylesheet', + 'stylesheets', + 'subdomain', + 'subscribe', + 'sudo', + 'super', + 'superuser', + 'support', + 'survey', + 'sync', + 'sysadmin', + 'system', + 'tablet', + 'tag', + 'tags', + 'team', + 'telnet', + 'terms', + 'terms-of-use', + 'test', + 'testimonials', + 'theme', + 'themes', + 'today', + 'tools', + 'topic', + 'topics', + 'tour', + 'training', + 'translate', + 'translations', + 'trending', + 'trial', + 'true', + 'umac-128', + 'umac-128-etm', + 'umac-64', + 'umac-64-etm', + 'undefined', + 'unfollow', + 'unlike', + 'unsubscribe', + 'update', + 'upgrade', + 'usenet', + 'user', + 'username', + 'users', + 'uucp', + 'var', + 'verify', + 'video', + 'view', + 'void', + 'vote', + 'webmail', + 'webmaster', + 'website', + 'widget', + 'widgets', + 'wiki', + 'wpad', + 'write', + 'www', + 'www-data', + 'www1', + 'www2', + 'www3', + 'www4', + 'you', + 'yourname', + 'yourusername', + 'zlib' ]; + +export const blocklistedUsernames = [...new Set(blocklist)];