Been doing a ton of research. I am a mere padawan, however, I have a project where I must run a user's untrusted Python3 code from a website.
I also apologize in advance if this question has some moving parts.
- I am looking for an as safe as possible approach. This doesn't need to be 100% perfect unless there is a big risk of leaking extremely sensitive data.
Main questions:
- Does my AWS-lambda plan run an extreme risk for leaking sensitive data?
- Are there any other simple precautions that I should take which could make this work safer in AWS-lambda?
- Are there ways for exec() to break out of the AWS-lambda container and make any other network connections if all I have connected to it is the single AWS-api-gateway for the REST call?
- Do I even need to limit
__builtins__and locals, or are AWS-lambda containers safe enough?
BackGround
It seems most companies use Kubernetes and Docker containers to execute untrusted python code (such a Leetcode, Programiz, or hackerRank).
See these helpful links:
- https://www.programiz.com/blog/online-python-compiler-engineering/
- https://aws.amazon.com/blogs/compute/running-executables-in-aws-lambda/
My Plan
I am thinking that I can POST my arbitrary Python code to an AWS Lambda Function as a microservice, using their containerization/scaling rather than build my own. In the Lambda container, I can just run the code through a simple exec or eval function, perhaps with some limitation like this:
"
safe_list = ['math','acos', 'asin', 'atan', 'print','atan2', 'ceil', 'cos', 'cosh', 'de grees', 'e', 'exp', 'fabs', 'floor', 'fmod', 'frexp', 'hypot', 'ldexp', 'log', 'log10', 'modf', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh']
safe_dict = dict([ (k, locals().get(k, None)) for k in safe_list ])
safe_dict['abs'] = abs
exec(userCode,{"**__builtins__"**:None},safe_dict )
Special Note:
- I am not too concerned about infinite loops or crashing things, because I will just timeout and tell the user to try again.
- All I need to do is run pretty simple python code (generally less than a few lines) and return exceptions, stdout, prints, and run a check on the result. Need to run:
- Math operators, lists, loops, lambda functions, maps, filters, declare methods, declare classes with properties, print.
- This doesn't need to be a perfect project for hundreds of thousands of users. I just want to have a live site for a resume booster and maybe make a little money on ads to help with costs.
- If there are severe limitations, I can eventually implement it in Kubernetes (as in the above link), but hopefully, this solution will work well enough.
- I just want this to work relatively well and not take too long to build or cost too much money.
- I do not want to leak any sensitive information.
Security things I am already planning on doing:
- AWS lambda: Limit the time out to around 1-2 seconds
- AWS lambda: Limit the memory usage to 128mb
- My Own Code: Use regex to make sure no one is passing in double underscores badstuff
- Keeping this microservice as minimal as possible (only connecting a single AWS-API-gateway).
Other notes:
- I don't think I can use restrictedPython or PyPy's sandbox feature in AWS Lambda because I don't have access to those dependencies OOB. I'm hoping that those are not necessary for this use case.
- If it's impossible to do this with exec(), are there safe python interpreters on GitHub or someplace that I can literally copy-paste into files in AWS-lambda and just call them?
- I am planning on allowing the user to print from exec with something like this:
"
@contextlib.contextmanager
def stdoutIO(stdout=None):
old = sys.stdout
if stdout is None:
stdout = StringIO()
sys.stdout = stdout
yield stdout
sys.stdout = old
with stdoutIO() as s:
try:
exec(userCode)
except:
print("Something wrong with the code")
print( s.getvalue())
print(i)
Please let me know if you have any questions or suggestions.
___ Edit ** adding architecture diagram ___
