fix: 修复 minimax_service 安全隐患和数据竞争
- 添加 HTTP 响应状态码检查,防止状态错误被忽略 - 添加 HTTP Client 结构体复用,避免每次创建新客户端 - 在 compressImageIfNeeded 中使用带 Timeout 的 Client - 添加 URL scheme 校验,防止 SSRF 攻击 - 使用 LimitedReader 限制下载图片大小(10MB) - 修复 GetJob 数据竞争,复制数据后返回 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
d09f1122ce
commit
f43b06e13d
@ -61,6 +61,7 @@ type minimaxService struct {
|
|||||||
config *config.AssetConfig
|
config *config.AssetConfig
|
||||||
jobs map[string]*ImageGenerationJob
|
jobs map[string]*ImageGenerationJob
|
||||||
jobsLock sync.RWMutex
|
jobsLock sync.RWMutex
|
||||||
|
client *http.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMinimaxService 创建 MiniMax 服务
|
// NewMinimaxService 创建 MiniMax 服务
|
||||||
@ -68,6 +69,7 @@ func NewMinimaxService(cfg *config.AssetConfig) MinimaxService {
|
|||||||
svc := &minimaxService{
|
svc := &minimaxService{
|
||||||
config: cfg,
|
config: cfg,
|
||||||
jobs: make(map[string]*ImageGenerationJob),
|
jobs: make(map[string]*ImageGenerationJob),
|
||||||
|
client: &http.Client{Timeout: 120 * time.Second},
|
||||||
}
|
}
|
||||||
go svc.cleanupExpiredJobs()
|
go svc.cleanupExpiredJobs()
|
||||||
return svc
|
return svc
|
||||||
@ -111,7 +113,11 @@ func (s *minimaxService) GetJob(ctx context.Context, jobID string, userID, starI
|
|||||||
return nil, fmt.Errorf("access denied")
|
return nil, fmt.Errorf("access denied")
|
||||||
}
|
}
|
||||||
|
|
||||||
return job, nil
|
// Copy data to avoid race
|
||||||
|
result := *job
|
||||||
|
result.Images = make([]string, len(job.Images))
|
||||||
|
copy(result.Images, job.Images)
|
||||||
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// processJob 异步处理任务
|
// processJob 异步处理任务
|
||||||
@ -192,7 +198,6 @@ func (s *minimaxService) callMiniMaxAPI(model, prompt, aspectRatio string, refs
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
client := &http.Client{Timeout: 120 * time.Second}
|
|
||||||
req, err := http.NewRequest("POST", apiURL, bytes.NewBuffer(jsonData))
|
req, err := http.NewRequest("POST", apiURL, bytes.NewBuffer(jsonData))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -200,12 +205,17 @@ func (s *minimaxService) callMiniMaxAPI(model, prompt, aspectRatio string, refs
|
|||||||
req.Header.Set("Authorization", "Bearer "+apiKey)
|
req.Header.Set("Authorization", "Bearer "+apiKey)
|
||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
resp, err := client.Do(req)
|
resp, err := s.client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||||
|
body, _ := io.ReadAll(resp.Body)
|
||||||
|
return nil, fmt.Errorf("API returned status %d: %s", resp.StatusCode, string(body))
|
||||||
|
}
|
||||||
|
|
||||||
var result struct {
|
var result struct {
|
||||||
Images []struct {
|
Images []struct {
|
||||||
URL string `json:"url"`
|
URL string `json:"url"`
|
||||||
@ -224,13 +234,14 @@ func (s *minimaxService) callMiniMaxAPI(model, prompt, aspectRatio string, refs
|
|||||||
|
|
||||||
// compressImageIfNeeded 下载并压缩图片
|
// compressImageIfNeeded 下载并压缩图片
|
||||||
func (s *minimaxService) compressImageIfNeeded(imageURL string) (string, error) {
|
func (s *minimaxService) compressImageIfNeeded(imageURL string) (string, error) {
|
||||||
resp, err := http.Get(imageURL)
|
client := &http.Client{Timeout: 30 * time.Second}
|
||||||
|
resp, err := client.Get(imageURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
imgData, err := io.ReadAll(resp.Body)
|
imgData, err := io.ReadAll(io.LimitReader(resp.Body, 10*1024*1024)) // 10MB limit
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -295,6 +306,9 @@ func validateURL(rawURL string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if u.Scheme != "http" && u.Scheme != "https" {
|
||||||
|
return fmt.Errorf("unsupported scheme: %s", u.Scheme)
|
||||||
|
}
|
||||||
host := u.Hostname()
|
host := u.Hostname()
|
||||||
|
|
||||||
ip := net.ParseIP(host)
|
ip := net.ParseIP(host)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user