Безопасный запрос пароля

Я работаю над пакетом config который определяет параметры конфигурации и команды для использования в пакетных сетевых устройствах. Прямо сейчас config.New функция принимает исходный текст yaml, который может содержать значения текстовых шаблонов. Для auth введите файл yaml, вы можете указать значение шаблона auth: {{.Password}} запрашивать у пользователя пароль при выполнении шаблона.

Эта функция безопасна? Исходный исходный файл yaml не изменяется при выполнении шаблона, и, насколько я могу судить, указанное пользователем значение пароля доступно только через *Config структура возвращается из config.New, К сожалению, поля Config должен быть экспортирован для того, чтобы viper, Представляет ли это проблему безопасности?

Вот мой код:

package config

import (
    "fmt"
    "github.com/spf13/viper"
    "golang.org/x/crypto/ssh/terminal"
    "io"
    "os"
    "text/template"
)

// Config contains network device configuration options and commands.
type Config struct {
    Hosts   string `yaml:"hosts"`   // hosts to configure
    User    string `yaml:"user"`    // username for host login
    Auth    string `yaml:"auth"`    // SSH authentication method
    Allow   string `yaml:"allow"`   // allow either all or known hosts
    Timeout int    `yaml:"timeout"` // duration to wait to establish a connection
    Config []struct {
        Vendor string   `yaml:"vendor"` // vendor that supports `cmds`
        Cmds   []string `yaml:"cmds"`   // configuration commands to run
    } `yaml:"config"`               // list of vendor-configuration command sets
}

// New creates a new Config from a yaml or text template file.
func New(src string) (*Config, error) {
    var cfg Config
    pr, pw := io.Pipe()
    tmpl, err := template.New("config").Parse(src)
    if err != nil {
        return nil, err
    }
    tmplErr := make(chan error, 1)
    go func(tmpl *template.Template, cfg Config, pw *io.PipeWriter, tmplErr chan<- error) {
        defer pw.Close()
        if err := tmpl.Execute(pw, &cfg); err != nil {
            tmplErr <- err
        }
        close(tmplErr)
    }(tmpl, cfg, pw, tmplErr)
    select {
    case err := <-tmplErr:
        return nil, err
    default:
        v := viper.New()
        v.SetConfigType("yaml")
        if err := v.ReadConfig(pr); err != nil {
            return nil, err
        }
        if err := v.Unmarshal(&cfg); err != nil {
            return nil, err
        }
        return &cfg, nil
    }
}

// Password prompts the user for their password.
func (c *Config) Password() string {
    fmt.Fprint(os.Stderr, "Password: ")
    password, err := terminal.ReadPassword(int(os.Stdin.Fd()))
    if err != nil {
        panic(err)
    }
    fmt.Fprintln(os.Stderr)
    return string(password)
}

пример main.go:

package main

import (
    "fmt"
    ".../config"
    "log"
)

const TestConfig = `
# Example configuration for restarting access points.
---
hosts  : access_points
user   : user
auth   : &password {{.Password}} # Prompt for password and store the value.
allow  : known_hosts             # Only allow connections to known hosts.
timeout: 5

config:
  - vendor: cisco
    cmds:
      - enable
      - *password                # Pass the password value to enter enabled mode.
      - capwap ap restart
      - exit
`

func main() {
    cfg, err := config.New(TestConfig)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(cfg.Auth)
}

Любые советы или предложения приветствуются. Я не хочу случайно раскрывать чьи-либо пароли или передавать секретные данные.

0 ответов

Другие вопросы по тегам