Golang安全编码手册-上篇

本文档为Go语言开发者提供编码效率提升及安全编码规范的手册。内容涵盖常见的编码问题及其解决方案,包括错误处理、数据结构使用、命令执行的安全实践、SQL注入防范、文件权限设置等。

前言

本手册为go语言开发人员,为提升编码效率和为满足安全编码规范的随手参考书。内容条目以安全编码为主和常易忽视的编码细节为主,来自于以下三个方面的总结:

1、gosec、govet等go语言安全编码扫描工具,的规则的解读;

2、字节跳动、uber等使用go语言较成熟的大厂,的go语言编码规范的一些提取;

3、我们平时工作中对go语言代码走查,达成一致意见的总结。

本手册每个条目,包含条目的目的,为什么这么做以及正例和反例。条目分类开头的关键字,说明如下:

G开头: 表示go语言基本要求的编码规范;

S开头: 表示来自于安全类问题规范;

P开头: 表示来自于性能累问题的规范。

本手册分为上篇和下篇,下篇暂不发布,内容为对上篇的补充和增加。

G01-handle error

基本要求。

Bad-错误示例Good-正确示例
json.Unmarshal(b, &xxxx) // warning: Errors unhandled.

 

    err := json.Unmarshal(b, &xxxx) // or : _ = json.Unmarshal(b, &xxxx) 
    if err != nil {
        return errors.Wrap(err, "Unmarshal xxxx failed, jsonStr")
    }

 

 

 

 

 

 

G02-nil是一个有效的长度为0的slice

基本要求。

Bad-错误示例Good-正确示例
if x == "" {
  return []int{}
}

 

if x == "" {
  return nil
}

 

 

 

 

 

 

S01-命令执行exec.Command的正确姿势

命令和参数需要分离,将后面的参数使用append([]string{}, args...)。参见gosec的G204

Bad-错误示例Good-正确示例
out, err := exec.Command("docker","run", "-d", "--net=host", "--entrypoint=/usr/local/bin/h2load", "gohttp2/curl")...).Output()  // Subprocess launched with variable
	if err != nil {
		t.Skipf("Failed to run h2load in docker: %v, %s", err, out)
	}

 

out, err := exec.Command("docker", append([]string{"run", "-d", "--net=host", "--entrypoint=/usr/local/bin/h2load", "gohttp2/curl"}, args...)...).Output()
	if err != nil {
		t.Skipf("Failed to run h2load in docker: %v, %s", err, out)
	}

 

 

 

 

 

 

 

 

S02-SQL语句使用format且关键字小写

format可以防止SQL注入,需要小写的关键字有:SELECT FROM、 WHERE、 INSERT INTO、 UPDATE、 DELETE FROM等。也可参见gosec的G201

Bad-错误示例Good-正确示例
fmt.Sprintf("INSERT INTO %s (%s) VALUES (%s)",schema.Name, head, value)  // warnning

 

fmt.Sprintf("insert into %s (%s) values (%s)",schema.Name, head, value)

 

 

 

 

 

 

 

S03-文件的权限chmod的正确姿势

创建文件夹和文件时注意权限和非root运行,降低权限,如果必须要0664,可以将0664改为0600|0064。原因参见gosec的G301和G302

Bad-错误示例Good-正确示例
os.OpenFile(logName, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0664) // Expect file permissions to be 0600 or less

 

os.OpenFile(logName, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0600|0064)

 

 

 

 

 

 

 

S04-对文件路径对输入检验

将路径/文件参数用path.Clean()或filepath.Clean()进行校验,注意必须要in line,参见gosec的G304

Bad-错误示例Good-正确示例
func File2lines(filePath string) ([]string, error) {
    f, err := os.Open(filePath) //Warning here
    if err != nil {
        return nil, err
    }
    defer f.Close()
    return linesFromReader(f)
}

 

func File2lines(filePath string) ([]string, error) {
    f, err := os.Open(filepath.Clean(filePath)) //check file path
    if err != nil {
        return nil, err
    }
    defer f.Close()
    return linesFromReader(f)
}

 

 

 

 

 

 

 

P01-strconv比fmt效率高

将原语转换为字符串或从字符串转换时,strconv比fmt效率高。

Bad-错误示例Good-正确示例
for i := 0; i < b.N; i++ {
  s := fmt.Sprint(rand.Int())
}

 

for i := 0; i < b.N; i++ {
  s := strconv.Itoa(rand.Int())
}

 

 

 

 

 

 

 

P02-字符串转化字节效率低

不要反复从固定字符串创建字节slice。相反,请执行一次转换并捕获结果。

Bad-错误示例Good-正确示例
for i := 0; i < b.N; i++ {
  w.Write([]byte("Hello world"))
}

 

data := []byte("Hello world")
for i := 0; i < b.N; i++ {
  w.Write(data)
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值