1

Я хочу использовать AWS Lambda для запуска кода JavaScript, который пользователи представляют в Интернете. Моя функция лямбда вернет возвращаемое значение, stderr и stdout. Какие проблемы я мог бы натолкнуться на это?Использование JavaScript eval() в AWS Lambda

Удаляет ли злоумышленник код, вызывающий проблемы для функции лямбда? Могут ли изменения, внесенные пользователями, например, в среду узлов или файловую систему, сохраняться через вызовы? Есть ли способ предотвратить это?

Вместо eval() я могу записать файл (ы) в файловой системе Lambda и называют:

const userCodeProcess = require('child_process').fork('user_code.js') 
userCodeProcess.on('message', response.send) 

ответ

3

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

  • Filesystem - Ваши пользователи могут представить код, который может вносить изменения в вашу файловую систему, и эти изменения будут сохраняться через функции, вызываемые на повторно использовать контейнер. Не все запросы пользовательского кода будут выполняться в одном и том же контейнере, но если два запроса будут делаться близко друг к другу, то один и тот же контейнер и то же самое «царапающее» дисковое пространство будет доступно. Способ потенциально предотвратить это, если вы можете ограничить включенные функции, такие как fs, определенным каталогам, которые вы определяете при вызове функции, чтобы вы могли создавать случайную директорию для каждого запроса в каталоге /tmp. Я не уверен, что это возможно. Вы должны убедиться, что пользователи не могут потребовать снова fs. Лучшая рекомендация - использовать что-то вроде safe-eval, о чем я расскажу позже.
  • Переменные среды - Код, выполняемый в eval, может обращаться к переменным среды окружения. Если вам нужно делать какие-либо запросы к базам данных, другим продуктам AWS и т. Д., Тогда вам нужно будет предоставить политику для функции Lambda, если вы не указали жесткие коды учетных данных, и эта информация может быть доступна с помощью кода пользователя. Вы должны убедиться, что все учетные данные, которые вы предоставляете системе, не входят в переменные среды, и если они есть, то вам будет удобно, когда ваши пользователи получат доступ к ним.
  • Throttling - Вы можете столкнуться с проблемами дросселирования. По умолчанию AWS допускает только 100 одновременных вызовов. Если вы не ограничиваете запрос, в котором ваши пользователи представляют свою собственную JS, тогда вы можете столкнуться с проблемами отказа в запросах из-за превышения лимита. Недавно я попросил увеличить лимит, и мне удалось увеличить мой объем до 3000 одновременных запросов без необходимости их оценки того, может ли их текущая инфраструктура справиться с этим, поэтому они могут дать вам и не-проблему.
  • Затраты - Я уверен, что вы подумали о тайм-аутах функции, но вы должны убедиться, что у вас ограничено время выполнения функции, чтобы ваши пользователи не уставали ваши счета AWS. Кроме того, это может показаться небольшим, но в больших масштабах добавляются ответы на запросы в 6 Мбайт запросов, поэтому передача и передача данных может быть большой проблемой и что-то, что вы можете ограничить в своем коде.
  • Ограничения Ваши пользователи могут столкнуться, сами с лимитами с контейнером /tmp. Они могут столкнуться с проблемами максимального размера возврата полезной нагрузки. Другие предельные вопросы могут быть исследованы here.

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

Рекомендация

Основываясь на немного дополнительных исследований я просто сделал, вы можете запустить свой яваскрипта код в некоторый тип контекста, так что пользователи могут только узел доступа API конечных точек, которые вы хотите их to, а также ваши собственные системные переменные. Использование такого инструмента, как safe-eval, может работать. Другие люди задавали вопрос об исполнении eval в контексте, например here, или, возможно, вы могли бы добавить use strict; и определить свои функциональные переменные каждый раз, когда вы вызываете eval, например, описанный here.

Кроме того, перед тем, как закрыть функцию и вернуть свои stderr и stdout, вы можете просто очистить свой каталог /tmp. Моя забота об этом заключается в том, что AWS использует один и тот же контейнер при одновременном выполнении двух запросов, и вы удаляете пространство «царапины» двух выполняемых одновременно функций. Я не смог найти решающего ответа на это в своих исследованиях.

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

Дополнительное чтение от AWS относительно повторного использования контейнера - here.

+0

Благодарим вас за подробный и продуманный ответ. Тестирование всего сейчас. –

1

Просто имейте в виду, что помимо eval() вы также можете запускать произвольный код, создавая анонимные функции в среде выполнения nodejs.

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

// POST https://g0623a10zf.execute-api.ap-southeast-2.amazonaws.com/prod/exec-script 
// Content-Type: text/plain 
// 
// return process.env; 

exports.handler = (event, context, callback) => { 
    var err = '', result; 
    try { 
     // ie: result = new Function('return process.env;')(); 
     result = new Function(event.body)(); 
    } catch (e) { 
     console.log(err = e); 
    } 
    context.succeed({ 
     statusCode: err ? '500' : '200', 
     body: err || result 
    }); 
    // Terminate runtime 
    callback(err, result); 
}; 

Очевидно, что вы до сих пор все проблемы безопасности, которые @forrestmid поднятые (и некоторые другие), но вы можете пропустить немного, где вы пишете в файл, а затем выполнить его.

Существует также дополнительная польза от этого подхода, который не позволяет звонить на модули nodejs require, что уберет большую часть вашей головной боли. То есть Каждая лямбда выполняется с предварительно установленным модулем aws-sdk, поэтому злонамеренные пользователи могут искать способы использования каких-либо незащищенных ресурсов AWS, сначала сделав require('aws-sdk').