Node.js 在AWS Lambda中使用JavaScript eval()
我想使用AWS Lambda运行用户通过web提交的JavaScript代码。我的Lambda函数将返回返回值,Node.js 在AWS Lambda中使用JavaScript eval(),node.js,amazon-web-services,aws-lambda,aws-sdk,child-process,Node.js,Amazon Web Services,Aws Lambda,Aws Sdk,Child Process,我想使用AWS Lambda运行用户通过web提交的JavaScript代码。我的Lambda函数将返回返回值,stderr和stdout。这样做会遇到什么问题 恶意用户是否能够提交导致Lambda函数出现问题的代码?用户所做的更改(例如对节点环境或文件系统所做的更改)是否会在调用过程中保持不变?有什么办法可以防止吗 我可以将文件写入Lambda文件系统并调用: const userCodeProcess = require('child_process').fork('user_code.js
stderr
和stdout
。这样做会遇到什么问题
恶意用户是否能够提交导致Lambda函数出现问题的代码?用户所做的更改(例如对节点环境或文件系统所做的更改)是否会在调用过程中保持不变?有什么办法可以防止吗
我可以将文件写入Lambda文件系统并调用:
const userCodeProcess = require('child_process').fork('user_code.js')
userCodeProcess.on('message', response.send)
用户将能够向Lambda函数提交代码,这些代码在某些情况下可能会导致问题:
- 文件系统-用户可以提交可以对文件系统进行更改的代码,这些更改将在重用容器上调用的函数之间保持。并非所有的用户代码请求都将在同一个容器上运行,但是如果两个请求放在一起,则相同的容器和相同的“临时”磁盘空间将可访问。一种潜在的防止这种情况的方法是,如果您可以将包含的函数(如
)限制在函数调用时定义的特定目录中,这样您就可以为fs
目录中的每个请求创建一个随机目录。我不确定这是否可能。您必须确保用户不能再单独要求/tmp
。一个更好的建议是使用类似于fs
,我将在后面详细讨论safe eval
- 环境变量-在eval中运行的代码可以访问节点环境变量。如果需要向数据库、其他AWS产品等发出任何请求,则需要向Lambda函数提供策略,除非您硬编码凭据,并且用户代码可以访问该信息。您必须确保您提供给系统的任何凭据都不在环境变量中,如果在环境变量中,那么您可以允许用户访问它们
- 节流-您可能会遇到节流问题。默认情况下,AWS只允许100次并发调用。如果您不限制用户提交自己的JS的请求,那么您可能会遇到由于达到该限制而被拒绝的请求问题。我最近请求增加限制,我可以将我的请求增加到3000个并发请求,而不需要他们评估当前的基础结构是否能够处理它,所以他们可能也不会给您带来任何问题
- 费用-我相信您已经考虑过函数超时,但您希望确保对函数运行时间进行限制,这样您的用户就不会为AWS账单增加负担。此外,它可能看起来很小,但在大范围内,一堆6MB的请求响应加在一起,因此数据传入和传出可能是一件大事,您可能希望在代码中加以限制
- 限制您的用户自己可能会遇到容器
目录的限制。他们可能会遇到最大有效负载返回大小的问题。可以研究其他极限问题/tmp
eval
的问题,例如,或者您可以预先编写使用strict每次调用eval
,都要定义函数变量,如所述
此外,在关闭函数并返回stderr
和stdout
之前,只需清除/tmp
目录即可。我关心的是,如果AWS在同时执行两个请求时使用相同的容器,那么您将删除同时执行的两个函数的“scratch”空间。在我的研究中,我还没有找到一个决定性的答案
在这一点上,我仍然要说,您的/tmp
目录是您将遇到最潜在问题的地方。如果您能够找到一种方法来限制使用单个目录,而不能够导航到父目录,或者AWS是否会在另一个函数中使用容器的同时重用容器,那么我认为您可能可以使用Lambda来执行用户提供的代码,而无需太多担心。或者,您可以通过从您使用的任何上下文方法中排除文件系统来阻止用户访问您的文件系统
AWS关于容器重用的附加阅读是。请记住,除了eval()
之外,您还可以通过在nodejs运行时内实例化匿名函数来运行任意代码
这将使您能够从输入代码中返回值,而无需使用子进程
// 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
调用,这将减轻您的许多头痛。也就是说,每个lambda都是使用预先安装的aws sdk
模块执行的,因此恶意用户可以通过首先执行require来查看利用任何不安全aws资源的方法(