Безопасный запрос пароля
Я работаю над пакетом 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)
}
Любые советы или предложения приветствуются. Я не хочу случайно раскрывать чьи-либо пароли или передавать секретные данные.