使用ClamAV扫描后,如何验证GCS文件是否上传至Clean/Quarantined Bucket(Golang)
场景描述
我们有三个Google Cloud Storage(GCS)Bucket:unscanned、clean、quarantined,使用ClamAV作为恶意软件扫描工具。文件先上传至unscanned Bucket,经扫描后会被转移至clean或quarantined Bucket。使用Golang作为后端语言,需要确认上传的文件最终被转移到了哪个Bucket。
尝试使用Cloud Storage Pub/Sub订阅时,调用Receive方法出现报错:"This method is not supported for this subscription type",甚至官方示例代码也触发该错误。同时考虑过查询ClamAV扫描日志来判断文件是否感染,但不确定这是否是正确做法。
可行的验证方案
1. 监听目标Bucket的对象创建事件(实时通知)
你遇到的Pub/Sub报错是因为创建的是推送类型订阅,而Receive方法仅支持拉取类型订阅。如果要继续用Pub/Sub实现实时通知,建议给clean和quarantined Bucket分别配置拉取订阅,当文件被移入这两个Bucket时,会触发对象创建的事件消息。
Golang实现代码示例:
package main import ( "context" "fmt" "log" "cloud.google.com/go/pubsub" ) func main() { ctx := context.Background() // 替换为你的GCP项目ID client, err := pubsub.NewClient(ctx, "your-gcp-project-id") if err != nil { log.Fatalf("创建Pub/Sub客户端失败: %v", err) } defer client.Close() // 监听clean Bucket的订阅(需提前创建拉取类型订阅) cleanSub := client.Subscription("clean-bucket-sub") err = cleanSub.Receive(ctx, func(ctx context.Context, m *pubsub.Message) { fmt.Printf("文件已移入clean Bucket: %s\n", string(m.Data)) m.Ack() // 确认消息已处理 }) if err != nil { log.Fatalf("接收clean Bucket消息失败: %v", err) } // 同理监听quarantined Bucket的订阅 quarantinedSub := client.Subscription("quarantined-bucket-sub") err = quarantinedSub.Receive(ctx, func(ctx context.Context, m *pubsub.Message) { fmt.Printf("文件已移入quarantined Bucket: %s\n", string(m.Data)) m.Ack() }) if err != nil { log.Fatalf("接收quarantined Bucket消息失败: %v", err) } }
2. 直接查询GCS对象元数据(按需验证)
如果不需要实时通知,可在需要验证时直接查询clean和quarantined Bucket中是否存在目标文件。
Golang实现代码示例:
package main import ( "context" "fmt" "log" "cloud.google.com/go/storage" ) // 检查文件所在的目标Bucket func checkFileLocation(ctx context.Context, client *storage.Client, fileName string) { // 检查clean Bucket cleanBucket := client.Bucket("clean") _, err := cleanBucket.Object(fileName).Attrs(ctx) if err == nil { fmt.Printf("文件 %s 位于clean Bucket\n", fileName) return } if err != storage.ErrObjectNotExist { log.Printf("检查clean Bucket出错: %v", err) } // 检查quarantined Bucket quarantinedBucket := client.Bucket("quarantined") _, err = quarantinedBucket.Object(fileName).Attrs(ctx) if err == nil { fmt.Printf("文件 %s 位于quarantined Bucket\n", fileName) return } if err != storage.ErrObjectNotExist { log.Printf("检查quarantined Bucket出错: %v", err) } fmt.Printf("文件 %s 未在目标Bucket中(可能仍在扫描或已被删除)\n", fileName) } func main() { ctx := context.Background() client, err := storage.NewClient(ctx) if err != nil { log.Fatalf("创建GCS客户端失败: %v", err) } defer client.Close() // 替换为你要验证的文件名 checkFileLocation(ctx, client, "target-file-name") }
3. 解析ClamAV扫描日志(间接推断)
如果你的ClamAV扫描服务会输出包含文件名和**扫描结果(安全/恶意)**的日志,完全可以通过解析日志来推断文件最终位置:扫描结果为安全则文件会被移至clean,恶意则移至quarantined。
可以将ClamAV日志输出到Cloud Logging,再用Golang的Cloud Logging客户端查询特定文件的扫描记录,进而确认文件去向。
内容的提问来源于stack exchange,提问作者Filip Pancevski

