如何创建用于执行不可信代码的Golang沙箱环境

如何创建用于执行不可信代码的Golang沙箱环境 你好,

我对创建一个Go沙箱很感兴趣,用于执行通过curl传递的任意、不受信任的Go代码。

我相信最著名的此类沙箱是 https://play.golang.org/

我找到了存放此代码的GitHub仓库(https://github.com/golang/playground),并且正在尝试运行他们在仓库中提供的示例。

GitHub上的README似乎表明我可以通过Docker镜像 + curl来执行任意代码。

以下是README中的示例:

docker build -t golang/playground .
docker run -d --name=play --rm -p 8080:8080 golang/playground
# 运行一些Go代码
cat /path/to/hello_world.go | go run client.go | curl -s --upload-file - localhost:8080/compile

虽然这看起来很简单,但它并没有正常工作。

问题似乎出在一个“SANDBOX_BACKEND_URL”环境变量上。

错误信息

#Golang Error
cmdFunc error: POST "http://sandbox_dev.sandnet/run": Post "http://sandbox_dev.sandnet/run": dial     tcp: lookup sandbox_dev.sandnet on 127.0.0.11:53: no such host

#http/mux Error
2020/10/17 20:39:26 http: panic serving 172.17.0.1:60486:
no SANDBOX_BACKEND_URL environment and no default defined for project ""

有人能帮我理解这个错误并帮助我执行示例中的代码吗?


更多关于如何创建用于执行不可信代码的Golang沙箱环境的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

截至目前我所尝试的方法

Github 仓库中有一个 Makefile,其中包含一些用于运行 Docker 化环境的步骤。

Makefile 的相关内容如下:

runlocal:
    docker network create sandnet || true
    docker kill play_dev || true
    docker run --name=play_dev --rm --network=sandnet -ti -p 127.0.0.1:8081:8080/tcp golang/
    playground --backend-url="http://sandbox_dev.sandnet/run"

当我创建 Docker 网络并使用设置的 --backend-url 运行容器时,遇到了同样的问题。

更多关于如何创建用于执行不可信代码的Golang沙箱环境的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


这是一个典型的沙箱环境配置问题。错误表明沙箱后端服务没有正确配置。

问题分析

SANDBOX_BACKEND_URL 环境变量用于指定实际执行代码的沙箱后端服务地址。在 playground 架构中,前端接收编译请求,然后转发到后端沙箱环境执行。

解决方案

1. 完整部署方案

你需要同时启动前端和后端服务:

# 克隆仓库
git clone https://github.com/golang/playground.git
cd playground

# 构建并启动后端沙箱
cd sandbox
docker build -t go-sandbox .
docker run -d --name sandbox-backend -p 8081:8081 go-sandbox

# 构建并启动前端服务(设置正确的后端URL)
cd ..
docker build -t playground-frontend .
docker run -d --name playground \
  -p 8080:8080 \
  -e SANDBOX_BACKEND_URL=http://host.docker.internal:8081 \
  playground-frontend

2. 使用 Docker Compose(推荐)

创建 docker-compose.yml

version: '3'
services:
  sandbox:
    build: ./sandbox
    container_name: sandbox-backend
    ports:
      - "8081:8081"
    networks:
      - playground-net

  frontend:
    build: .
    container_name: playground-frontend
    ports:
      - "8080:8080"
    environment:
      - SANDBOX_BACKEND_URL=http://sandbox:8081
    depends_on:
      - sandbox
    networks:
      - playground-net

networks:
  playground-net:
    driver: bridge

然后运行:

docker-compose up -d

3. 测试代码执行

创建测试文件 hello.go

package main

import "fmt"

func main() {
    fmt.Println("Hello from sandbox!")
}

执行代码:

cat hello.go | go run client.go | curl -s --upload-file - http://localhost:8080/compile

4. 直接使用 client.go 的示例

查看 client.go 的用法:

// client.go 使用示例
package main

import (
    "fmt"
    "io"
    "net/http"
    "os"
)

func main() {
    if len(os.Args) < 2 {
        fmt.Println("Usage: go run client.go <filename.go>")
        return
    }
    
    file, err := os.Open(os.Args[1])
    if err != nil {
        panic(err)
    }
    defer file.Close()
    
    resp, err := http.Post("http://localhost:8080/compile", 
        "application/x-www-form-urlencoded", file)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()
    
    io.Copy(os.Stdout, resp.Body)
}

运行:

go run client.go hello.go

关键配置说明

  • SANDBOX_BACKEND_URL: 必须指向实际运行代码的沙箱容器
  • 网络配置: 确保前端容器能访问后端容器(使用 Docker 网络或 host.docker.internal)
  • 端口映射: 前端 8080 对外,后端 8081 供内部通信

如果使用 Linux,可能需要修改 host.docker.internal 为实际的容器 IP 或使用 Docker 网络别名。

回到顶部