На этой неделе твит директора службы безопасности Brave browser вызвал у общественности озабоченность по поводу безопасности нашей кодовой базы.

В твите была показана автоматическая сводка наших npm -зависимостей, у которых были большие числа, что делало его тревожным образом для сплоченных сторонников безопасности.

Наш ответ

Мы воспользовались возможностью очистить эти зависимости ради улучшения результатов этого типа автоматического аудита.

Мы разработали инструмент аудита под названием npm-audit-plz, который обходил бы ошибки, которые мы получали от обычного npm audit, которые, как мы определили, были вызваны ошибкой в ​​npm. Мы сообщили о проблеме в npm, и нам сказали, что она была зарегистрирована, но нам не предложили никаких оценок сроков для исправления.

Члены нашей команды использовали эти результаты аудита, чтобы начать изолировать зависимости, на которые чаще всего приходили флаги аудита.

@Whymarrh, @danjm и @dryajov внесли свой вклад в этот анализ.

Это привело к запросу на вытягивание, по которому проект снова прошел npm audit, при этом осталось очень мало обнаруженных npm audit уязвимостей, обсуждаемых ниже.

Мы также создали новую награду за обнаружение ошибок для всех, кто может найти вредоносную зависимость в кодовой базе MetaMask.

Как этот аудит остался незамеченным

Раньше нам требовалось выполнение этого автоматического npm audit для прохождения нашего набора тестов, который требуется для каждого объединяемого запроса на перенос.

Это принудительное требование было крайне недетерминированным и постепенно отказывалось все чаще и чаще, пока не блокировало срочное исправление ошибки. На этом этапе мы отключили требование аудита npm в нашем наборе тестов.

Оглядываясь назад, можно сказать, что это было время открыть проблему и начать внедрение альтернативного автоматизированного процесса аудита, который больше соответствовал бы нашим потребностям, но этого не произошло.

Анализ этих чисел

Большинство учтенных уязвимостей (3079) были одним модулем, который неоднократно учитывался npm audit: lodash до версии 4.17.5, который был уязвим для атаки прототипа загрязнения, которая сама по себе уязвима только для других вредоносных зависимостей. (Многие из учтенных уязвимостей и зависимостей также неоднократно учитывали одни и те же модули)

Многие из этих зависимостей были частью нашей системы сборки или локальной среды разработки, так как команда аудита npm также учитывает «зависимости разработчика», которые никогда не поставляются в производство, а также часто не используются в нашей системе сборки. (Например, наши инструменты тестирования)

Также, похоже, сработал какой-то цикл подсчета зависимостей, где мы неправильно указали одну зависимость, gaba (модуль, который мы сами поддерживаем) как devDependency.

Анализ оставшихся обнаруженных уязвимостей

После того, как мы обновили модули, которые могли, чтобы устранить эти предупреждения, оставшимися обнаруженными уязвимыми модулями являются:

=== npm audit security report ===                        
                                                                                
# Run  npm update fstream --depth 7  to resolve 2 vulnerabilities
┌───────────────┬──────────────────────────────────────────────────────────────┐
│ High          │ Arbitrary File Overwrite                                     │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package       │ fstream                                                      │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ ganache-core [dev]                                           │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path          │ ganache-core > web3 > web3-bzz > swarm-js > tar.gz > fstream │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info     │ https://nodesecurity.io/advisories/886                       │
└───────────────┴──────────────────────────────────────────────────────────────┘
┌───────────────┬──────────────────────────────────────────────────────────────┐
│ High          │ Arbitrary File Overwrite                                     │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package       │ fstream                                                      │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ ganache-core [dev]                                           │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path          │ ganache-core > web3 > web3-bzz > swarm-js > tar.gz > tar >   │
│               │ fstream                                                      │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info     │ https://nodesecurity.io/advisories/886                       │
└───────────────┴──────────────────────────────────────────────────────────────┘
# Run  npm update tar --depth 6  to resolve 1 vulnerability
┌───────────────┬──────────────────────────────────────────────────────────────┐
│ High          │ Arbitrary File Overwrite                                     │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package       │ tar                                                          │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ ganache-core [dev]                                           │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path          │ ganache-core > web3 > web3-bzz > swarm-js > tar.gz > tar     │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info     │ https://nodesecurity.io/advisories/803                       │
└───────────────┴──────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────────────┐
│                                Manual Review                                 │
│            Some vulnerabilities require your attention to resolve            │
│                                                                              │
│         Visit https://go.npm.me/audit-guide for additional guidance          │
└──────────────────────────────────────────────────────────────────────────────┘
┌───────────────┬──────────────────────────────────────────────────────────────┐
│ Low           │ Insecure Credential Storage                                  │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package       │ web3                                                         │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Patched in    │ No patch available                                           │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ abi-decoder                                                  │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path          │ abi-decoder > web3                                           │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info     │ https://nodesecurity.io/advisories/877                       │
└───────────────┴──────────────────────────────────────────────────────────────┘
┌───────────────┬──────────────────────────────────────────────────────────────┐
│ Low           │ Insecure Credential Storage                                  │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package       │ web3                                                         │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Patched in    │ No patch available                                           │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ gaba                                                         │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path          │ gaba > web3                                                  │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info     │ https://nodesecurity.io/advisories/877                       │
└───────────────┴──────────────────────────────────────────────────────────────┘
┌───────────────┬──────────────────────────────────────────────────────────────┐
│ Low           │ Insecure Credential Storage                                  │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package       │ web3                                                         │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Patched in    │ No patch available                                           │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ web3                                                         │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path          │ web3                                                         │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info     │ https://nodesecurity.io/advisories/877                       │
└───────────────┴──────────────────────────────────────────────────────────────┘
┌───────────────┬──────────────────────────────────────────────────────────────┐
│ Low           │ Regular Expression Denial of Service                         │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package       │ braces                                                       │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Patched in    │ >=2.3.1                                                      │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ gulp-stylefmt [dev]                                          │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path          │ gulp-stylefmt > stylefmt > stylelint > micromatch > braces   │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info     │ https://nodesecurity.io/advisories/786                       │
└───────────────┴──────────────────────────────────────────────────────────────┘
┌───────────────┬──────────────────────────────────────────────────────────────┐
│ Low           │ Regular Expression Denial of Service                         │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package       │ braces                                                       │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Patched in    │ >=2.3.1                                                      │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ gulp-stylefmt [dev]                                          │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path          │ gulp-stylefmt > stylefmt > stylelint-order > stylelint >     │
│               │ micromatch > braces                                          │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info     │ https://nodesecurity.io/advisories/786                       │
└───────────────┴──────────────────────────────────────────────────────────────┘
┌───────────────┬──────────────────────────────────────────────────────────────┐
│ Low           │ Regular Expression Denial of Service                         │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package       │ braces                                                       │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Patched in    │ >=2.3.1                                                      │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ gulp-watch [dev]                                             │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path          │ gulp-watch > anymatch > micromatch > braces                  │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info     │ https://nodesecurity.io/advisories/786                       │
└───────────────┴──────────────────────────────────────────────────────────────┘
┌───────────────┬──────────────────────────────────────────────────────────────┐
│ Low           │ Regular Expression Denial of Service                         │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package       │ braces                                                       │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Patched in    │ >=2.3.1                                                      │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ qunitjs [dev]                                                │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path          │ qunitjs > chokidar > anymatch > micromatch > braces          │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info     │ https://nodesecurity.io/advisories/786                       │
└───────────────┴──────────────────────────────────────────────────────────────┘
┌───────────────┬──────────────────────────────────────────────────────────────┐
│ Low           │ Regular Expression Denial of Service                         │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Package       │ braces                                                       │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Patched in    │ >=2.3.1                                                      │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Dependency of │ qunitjs [dev]                                                │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ Path          │ qunitjs > findup-sync > micromatch > braces                  │
├───────────────┼──────────────────────────────────────────────────────────────┤
│ More info     │ https://nodesecurity.io/advisories/786                       │
└───────────────┴──────────────────────────────────────────────────────────────┘
found 11 vulnerabilities (8 low, 3 high) in 255418 scanned packages
  run `npm audit fix` to fix 3 of them.
  8 vulnerabilities require manual review. See the full report for details.

Их контекст в MetaMask:

  • ganache-core: Используется в нашем наборе тестов (уязвимость может затронуть только машину, на которой выполняются наши тесты).
  • fstream: Используется внутри web3.js, уязвим только при использовании в среде node.js, чего MetaMask никогда не бывает.
  • tar: Используется внутри ganache-core, уязвим только при распаковке файла, чего не делает MetaMask. Также используется только в нашем тестовом наборе.
  • web3: Небезопасно при использовании для хранения учетных данных, чего мы не делаем.
  • braces: склонен к отказу в обслуживании при подаче ненадежных входных данных, но используется только в нашей системе сборки.

Пара других примечательных отмеченных модулей, которые есть в нашем devDependencies, но не ставят под угрозу основной продукт:

Большая проблема

В конечном итоге атаки на цепочки поставок представляют собой постоянную и фундаментальную угрозу безопасности любого проекта, и мы знаем, что как кошелек мы являемся целью постоянно растущей ценности, поэтому мы не можем относиться к безопасности достаточно серьезно.

Мы видели, как биткойн-кошелек JavaScript был взломан в прошлом году из-за одной уязвимой зависимости, и это случилось снова только на прошлой неделе. Мы серьезно думаем о таких атаках, потому что мы являемся главной целью для того же самого.

После взлома event-stream было много ответов, и многие люди (даже в ветке твиттера, вдохновившей на этот инцидент) быстро обвиняют JavaScript и экосистему узлов в поощрении простого или чрезмерного использования зависимостей. .

Хотя это правда, что нам нужно быть невероятно осторожными с нашими зависимостями и нести ответственность за как можно большую часть нашего кода, мы считаем, что есть лучший ответ на этот долгий срок - лучшая изоляция зависимостей. Если мы сможем жестко регулировать доступ любой данной зависимости к разрешениям приложения, мы сможем ограничить ее возможное повреждение.

К счастью, работа в Agoric продемонстрировала, что JavaScript - это почти язык объектных возможностей, что означает (отчасти), что он очень близок к обеспечению изоляции зависимостей друг от друга, за исключением необходимых полномочий . Предложение Realms API сделало бы этот вид безопасности встроенным в JavaScript, но в то же время полифилл Secure EcmaScript (SES) делает это уже достижимым и сейчас находится в разработке в Salesforce для их системы плагинов.

Чтобы изучить эту возможность для MetaMask, мы экспериментировали с инструментом сборки, который мы называем SESify, который расширяет наш процесс сборки браузера, чтобы также изолировать каждую зависимость в своей собственной области SES с разрешениями, строго ограниченными декларативным файлом доступа, который мы может автоматически обновляться в ответ на изменения разрешений зависимостей, вызывая ручную проверку.

По сути, это позволит нам автоматически никогда не разрешать модулю, которому не требуется доступ к сети, самопроизвольный доступ к сети, и получать предупреждение в момент, когда обновление этого модуля вводит код, который попытается получить доступ к сети.

Мы считаем, что изоляция кода - лучший инструмент, который у нас есть для борьбы с атаками зависимостей, поскольку даже npm audit обнаруживает только известные уязвимости. (Если вы заинтересованы в том, чтобы внести свой вклад в этот проект, свяжитесь с нами!)

Даже без идеальной изоляции зависимостей также может быть возможность использовать такие инструменты, как Доверие при первом использовании (TOFU) для автоматического обнаружения обновлений зависимостей, которые вводят использование новых системных API-интерфейсов, которые могут помочь автоматически обнаруживать несанкционированные обновления зависимостей.

Заключение

В MetaMask произошел сбой процесса, когда мы отключили автоматический аудит и не открыли проблему, чтобы отслеживать его повторное включение или замену.

Мы рассмотрели этот сбой протокола вместе с командой и обновили соответствующие зависимости и повторно включили автоматический аудит в нашем наборе тестов, который требуется перед каждым изменением проекта. Мы также изучаем другие решения для автоматизированного аудита, такие как github и greenkeeper.

Поскольку это означает, что мы обновили сразу много зависимостей в нашей ветке разработки, мы также объявляем новую программу вознаграждения за обнаружение ошибок в размере 3000 DAI (~ $ 3000) для поиска любого обновления зависимостей, которое вводит код, предназначенный для незаконного доступа к пользовательским ключам. Чтобы помочь рецензентам в их эффективности в этом поиске ошибок, мы также вводим новую учетную запись Twitter, где мы будем публиковать сообщения о ожидающих релиз-кандидатах.

Автоматизированные аудиты не являются последним словом в области безопасности, поэтому мы наняли Cure53 для проверки безопасности нашего расширения и продолжаем следовать стратегиям изоляции зависимостей.

Это улучшение в нашем проекте отчасти произошло благодаря сообществу открытого исходного кода, и мы благодарим всех за то, что они поощряют нас быть самым безопасным проектом, которым мы можем быть.