Istnieje kilka opcji przechowywania haseł i innych sekretów, których program w Pythonie musi używać, w szczególności program, który musi działać w tle, gdzie nie może po prostu poprosić użytkownika o wpisanie hasła.
Problemy, których należy unikać:
- Sprawdzanie hasła w kontroli źródła, gdzie inni programiści, a nawet opinia publiczna, mogą je zobaczyć.
- Inni użytkownicy na tym samym serwerze odczytują hasło z pliku konfiguracyjnego lub kodu źródłowego.
- Posiadanie hasła w pliku źródłowym, gdzie inni mogą je zobaczyć przez ramię podczas jego edycji.
Opcja 1: SSH
Nie zawsze jest to opcja, ale prawdopodobnie jest najlepsza. Twój klucz prywatny nigdy nie jest przesyłany przez sieć, SSH wykonuje tylko obliczenia matematyczne, aby udowodnić, że masz właściwy klucz.
Aby to działało, potrzebujesz:
- Baza danych lub cokolwiek, do czego uzyskujesz dostęp, musi być dostępne przez SSH. Spróbuj wyszukać „SSH” oraz dowolną usługę, do której uzyskujesz dostęp. Na przykład „ssh postgresql” . Jeśli to nie jest funkcja w Twojej bazie danych, przejdź do następnej opcji.
- Utwórz konto, aby uruchomić usługę, która będzie wykonywać wywołania bazy danych, i wygeneruj klucz SSH .
- Albo dodaj klucz publiczny do usługi, do której będziesz dzwonić, albo utwórz konto lokalne na tym serwerze i zainstaluj tam klucz publiczny.
Opcja 2: zmienne środowiskowe
Ten jest najprostszy, więc może być dobrym miejscem do rozpoczęcia. Jest to dobrze opisane w aplikacji Twelve Factor . Podstawowym pomysłem jest to, że kod źródłowy po prostu pobiera hasło lub inne wpisy tajne ze zmiennych środowiskowych, a następnie konfiguruje te zmienne środowiskowe w każdym systemie, w którym uruchamiasz program. Może być również miłym akcentem, jeśli użyjesz wartości domyślnych, które będą działać dla większości programistów. Musisz zrównoważyć to z zapewnieniem „domyślnego bezpieczeństwa” oprogramowania.
Oto przykład, który pobiera serwer, nazwę użytkownika i hasło ze zmiennych środowiskowych.
import os
server = os.getenv('MY_APP_DB_SERVER', 'localhost')
user = os.getenv('MY_APP_DB_USER', 'myapp')
password = os.getenv('MY_APP_DB_PASSWORD', '')
db_connect(server, user, password)
Sprawdź, jak ustawić zmienne środowiskowe w systemie operacyjnym i rozważ uruchomienie usługi na własnym koncie. W ten sposób nie masz wrażliwych danych w zmiennych środowiskowych, gdy uruchamiasz programy na swoim własnym koncie. Po skonfigurowaniu tych zmiennych środowiskowych należy uważać, aby inni użytkownicy nie mogli ich odczytać. Sprawdź na przykład uprawnienia do plików. Oczywiście każdy użytkownik z uprawnieniami roota będzie mógł je przeczytać, ale nie można na to poradzić. Jeśli używasz systemd, spójrz na jednostkę usługową i uważaj, aby użyć EnvironmentFile
zamiast Environment
jakichkolwiek sekretów. Environment
wartości mogą być przeglądane przez każdego użytkownika z systemctl show
.
Opcja 3: Pliki konfiguracyjne
Jest to bardzo podobne do zmiennych środowiskowych, ale odczytujesz sekrety z pliku tekstowego. Nadal uważam, że zmienne środowiskowe są bardziej elastyczne w przypadku narzędzi do wdrażania i serwerów ciągłej integracji. Jeśli zdecydujesz się użyć pliku konfiguracyjnego, Python obsługuje kilka formatów w bibliotece standardowej, takich jak JSON , INI , netrc i XML . Możesz również znaleźć pakiety zewnętrzne, takie jak PyYAML i TOML . Osobiście uważam, że JSON i YAML są najprostsze w użyciu, a YAML pozwala na komentarze.
Trzy rzeczy do rozważenia w przypadku plików konfiguracyjnych:
- Gdzie jest plik? Może domyślna lokalizacja, jak
~/.my_app
i opcja wiersza poleceń, aby użyć innej lokalizacji.
- Upewnij się, że inni użytkownicy nie mogą odczytać pliku.
- Oczywiście nie wysyłaj pliku konfiguracyjnego do kodu źródłowego. Możesz chcieć zatwierdzić szablon, który użytkownicy będą mogli skopiować do swojego katalogu domowego.
Opcja 4: moduł Python
Niektóre projekty po prostu umieszczają swoje sekrety bezpośrednio w module Pythona.
db_server = 'dbhost1'
db_user = 'my_app'
db_password = 'correcthorsebatterystaple'
Następnie zaimportuj ten moduł, aby uzyskać wartości.
from settings import db_server, db_user, db_password
db_connect(db_server, db_user, db_password)
Jednym z projektów wykorzystujących tę technikę jest Django . Oczywiście nie powinieneś angażować settings.py
się w kontrolę źródła, chociaż możesz chcieć zatwierdzić plik o nazwie, settings_template.py
który użytkownicy mogą kopiować i modyfikować.
Widzę kilka problemów z tą techniką:
- Deweloperzy mogą przypadkowo przekazać plik do kontroli źródła. Dodanie go
.gitignore
zmniejsza to ryzyko.
- Część twojego kodu nie jest pod kontrolą źródła. Jeśli jesteś zdyscyplinowany i umieszczasz tutaj tylko ciągi i liczby, nie będzie to problem. Jeśli zaczniesz pisać tutaj klasy filtrów logowania, przestań!
Jeśli Twój projekt już korzysta z tej techniki, łatwo jest przejść do zmiennych środowiskowych. Po prostu przenieś wszystkie wartości ustawień do zmiennych środowiskowych i zmień moduł Pythona, aby czytał z tych zmiennych środowiskowych.