Как лучше всего работать с паролями с открытым текстом в Go

# #go #passwords

Вопрос:

Я создаю простую программу для регистрации моего IP-адреса в OpenDNS при его изменении. Я знаю о ddclient, но я хочу написать свой собственный только в учебных целях.

Чтобы иметь возможность выполнять любые операции с OpenDNS, я должен вызвать URL-адрес, указывающий моего пользователя, и передать, поэтому пример curl будет выглядеть примерно так: curl -u user:password https://updates.opendns.com/nic/update?hostname=xxxxamp;myip=123.123.123.123

В Go я создал следующую функцию:

 func registerNewIpToOpenDns(ip string) (int, error) {

    openDnsURL := "https://updates.opendns.com/nic/update?hostname=xxxxamp;myip="   ip
    req, err := http.NewRequest("GET", openDnsURL, nil)
    if err != nil {
        return 0, err
    }
    req.SetBasicAuth("USER", "PASS")

    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        return 0, err
    }
    defer resp.Body.Close()

    return resp.StatusCode, nil
}
 

Итак, как я должен выполнить ввод пользователя/пройти в эту программу? Я сделаю этот проект «общедоступным» на Github.

Я думал создать файл что-то вроде «ввода» и добавить его в .gitignore. Поэтому, если кто-то еще захочет использовать программу, ему просто нужно будет создать свой собственный файл «ввода», и программа будет читать из него.

А ты как думаешь?

Ответ №1:

Поместите данные конфигурации, которые не были бы верны для всех, в переменные среды.

Используется os.Getenv() для извлечения переменных во время выполнения. Убедитесь, что они настроены на что-то допустимое (по крайней мере, не пустая строка) как часть конфигурации вашей программы.

Затем вы можете задать переменные среды в systemd файле конфигурации , если вы запускаете эту systemd программу, или в файле .bash_config для пользователя, посвященного этому процессу, или в любом другом месте, наиболее удобном для выполнения вашей программы.

Или создайте файл конфигурации, который вы можете прочитать из своей программы. Обычно я использую кодировку Json для подобной конфигурации, но вы можете использовать что угодно. Чтение секретов из файлов конфигурации, возможно, может быть несколько безопаснее, чем переменные среды, которые часто могут быть проанализированы системными процессами.

Когда я создаю файл конфигурации, я обычно моделирую свою конфигурацию с помощью структуры,

 type Config struct {
   Username string
   Password string
}
 

Затем, в рамках инициализации моей программы, я бы сделал что-то вроде

 const ConfigFileEnv "ConfigFile" // avoid typing errors 
var config Config
... 
if f, err := os.Open(os.Getenv(ConfigFileEnv); err != nil {
  panic(fmt.Errorf("Couldn't open config file %s: %w",
    os.Getenv(ConfigFileEnv),
    err,
  ))
} else if err := json.NewDecoder(f).Decode(amp;config); err != nil {
   panic(fmt.Errorf("Couldn't decode json from config file %s: %w", 
      os.Getenv(ConfigFileEnv),
      err
   )
}
// Now config file has been loaded into config
...
req.SetBasicAuth(config.Username, config.Password)
 

Рабочий минимальный пример (без вашей логики): https://github.com/farrellit/stackoverflow/tree/main/69335827

Комментарии:

1. Привет, Дэниел, прежде всего, спасибо тебе за твой ответ. Я искал и в итоге нашел некоторые решения, такие как godotenv и viper, в этом случае я должен использовать одно из них или ваш стандартный библиотечный подход? Зачем нам нужна структура в этом случае?

2. Это действительно зависит от вас, как от исполнителя. Если вы считаете, что функции godotenv или viper желательны, непременно используйте их. Что касается того, почему структура, это по 2 причинам: во-первых, структуры хорошо работают с Json в Go, и 2, потому что каждый раз, когда у меня есть более одного скаляра, который идет вместе, я обычно тянусь к a struct , чтобы удержать их вместе. Это проще передать ,и особенно удобно, если я создаю методы, которые работают со структурой (представьте func (c *Config)Validate() error функцию для проверки конфигурации).