Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/iphone/44.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
SetGID/SetUID在Go[lang]二进制上是否安全?_Go_Sudo_Setuid - Fatal编程技术网

SetGID/SetUID在Go[lang]二进制上是否安全?

SetGID/SetUID在Go[lang]二进制上是否安全?,go,sudo,setuid,Go,Sudo,Setuid,我使用YAML和MySQL驱动程序编写了一个简单的程序,目的是提供一个简单的实用程序来更新数据库,而不向执行程序的用户公开用户名和密码凭据 (我很清楚,我也可以用Python或其他脚本语言编写这篇文章,并使用来管理权限委派,但我想在这里尝试一种不同的方法,供我自己借鉴) 在构建程序之后,我使用了chgrp sys dbcreds.yaml&&chmod 0640 dbcreds.yaml和chgrp sys./myprog&&chmod g+s./myprog(作为根)。。。一切似乎都正常。(我

我使用YAML和MySQL驱动程序编写了一个简单的程序,目的是提供一个简单的实用程序来更新数据库,而不向执行程序的用户公开用户名和密码凭据

(我很清楚,我也可以用Python或其他脚本语言编写这篇文章,并使用来管理权限委派,但我想在这里尝试一种不同的方法,供我自己借鉴)

在构建程序之后,我使用了
chgrp sys dbcreds.yaml&&chmod 0640 dbcreds.yaml
chgrp sys./myprog&&chmod g+s./myprog
(作为根)。。。一切似乎都正常。(我还测试了在setGID步骤之前,访问被拒绝,这是应该的)

我还测试了
strace
,结果是权限被拒绝(应该是这样的)。(为了好玩,我也在上面运行了
ltrace-S
;这是在Linux下运行的。正如预期的那样,我没有看到很多正常的libc函数调用…通过,我很惊讶在该列表中看到了一些pthread_….()和一个malloc()调用。我猜GO运行时毕竟链接到了一些系统库函数)

我的问题:这安全吗?是否有任何已知的方法可以导致Go程序(如下面的)在读取这些私有凭据后转储或暴露其内存?有没有办法在我看了我的证件后放弃我的SGID特权?在Go二进制文件中是否有SUID/SGID漏洞利用的例子?有更好的方法吗?是否有一种主动预防核心转储或确保敏感数据(凭据)不在核心转储中的方法

另一个注意事项是:我发现/yaml.v2中的gopkg.in语义有点令人不安。在我的YAML文件中,我有如下内容:

---
user me
pw mypassword
但是在我的代码中,我必须使用UserPw(大写),而不是像我预期的那样使用小写。我认为这是作者的一项实施决定。是这样吗

#!go
package main

import (
    "fmt"
    "database/sql"
    _ "github.com/go-sql-driver/mysql"
    "gopkg.in/yaml.v2"
    "io/ioutil"
    "os"
    "strconv"
)

type Creds struct {
    User string
    Pw   string
}

func main() {

    filename := "./dbcreds.yaml"
    var creds Creds
    conf, err := ioutil.ReadFile(filename)
    if err != nil {
        panic(err)
    }
    err = yaml.Unmarshal(conf, &creds)
    if err != nil {
        panic(err)
    }

    var arg1 int
    arg1, err = strconv.Atoi(os.Args[1])
    if err != nil {
        panic(err.Error()) // Just for example purpose. You should use proper error handling instead of panic
    }

    fmt.Println("arg1: ", arg1, "\n")
    dsn := fmt.Sprintf("%s:%s@/mydatabase", creds.User, creds.Pw)
    db, err := sql.Open("mysql", dsn)
    if err != nil {
        panic(err.Error())
    }
    defer db.Close()

    err = db.Ping()
    if err != nil {
        panic(err.Error())
    }

    stmtOut, err := db.Prepare("SELECT quant FROM c WHERE id >= ?")
    if err != nil {
        panic(err.Error())
    }
    defer stmtOut.Close()

    rows, err := stmtOut.Query(arg1)
    if err != nil {
        panic(err.Error())
    }
    defer rows.Close()

    for rows.Next() {
        var quant int
        err = rows.Scan(&quant)
        if err != nil {
            panic(err.Error())
        }
        fmt.Println(quant)
    }
}

setuid/setgid Go程序相当安全,但有一个主要的警告。Go setuid/setgid程序通常不比C/C++setuid/setgid程序更安全,也不比C/C++setuid/setgid程序更安全

确实,您可以通过使用环境变量GOTRACEBACK=crash运行Go程序,然后向其发送信号,来强制Go程序转储core。但是,这对于您来说是可以的,因为Go程序将(尝试)通过向自身发送SIGABRT信号来创建堆芯转储。内核不会为被信号终止的setuid/setgid程序生成内核转储

Go的主要警告是,在GNU/Linux系统上,您不能退回到原始用户ID。这是因为如何在GNU/Linux上为多线程程序实现setuid(以及setgid、setgroups、setreuid、setregid、setresuid和setresgid)。详情载于


在最后一个注释中,Uw和Pw需要大写,因为标准reflect包不允许写入未报告的字段。

您只能封送/解封到公共结构成员中。这些由首字母大写字母标识。(un)封送处理程序(例如JSON)为您处理大小写转换。