Ответ
Пароли пользователей никогда не должны храниться в открытом виде (plaintext). Единственный безопасный способ — хранить их хеши с использованием криптографически стойких, медленных алгоритмов.
Ключевые принципы:
-
Используйте медленный алгоритм хеширования. Быстрые алгоритмы (MD5, SHA-256) не подходят, так как они уязвимы для атак перебором (brute-force). Рекомендуемые алгоритмы:
- Bcrypt: Надежный и широко используемый стандарт.
- Scrypt: Требует больше памяти, что делает его еще более устойчивым к аппаратным атакам.
- Argon2: Победитель конкурса Password Hashing Competition, считается самым современным и надежным стандартом.
-
Используйте соль (Salt). Соль — это случайная строка, которая добавляется к паролю перед хешированием. Это предотвращает атаки с использованием "радужных таблиц" (rainbow tables). Современные библиотеки, такие как
bcryptв Go, генерируют и встраивают соль в хеш автоматически. -
Настраивайте "стоимость" (Cost Factor). У медленных алгоритмов есть параметр "стоимости" или "количества раундов", который определяет, насколько ресурсоемким будет процесс хеширования. Его нужно подбирать так, чтобы хеширование занимало приемлемое время (например, 100-500 мс) на вашем оборудовании.
Пример реализации на Go с bcrypt:
package main
import (
"fmt"
"golang.org/x/crypto/bcrypt"
)
// HashPassword хеширует пароль с использованием bcrypt
func HashPassword(password string) (string, error) {
// bcrypt.DefaultCost равен 10. Для продакшена рекомендуется 12-14.
bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14)
return string(bytes), err
}
// CheckPasswordHash сравнивает пароль с хешем
func CheckPasswordHash(password, hash string) bool {
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
return err == nil
}
func main() {
password := "mySecurePa$$w0rd"
hash, _ := HashPassword(password)
fmt.Println("Password:", password)
fmt.Println("Hash: ", hash)
match := CheckPasswordHash(password, hash)
fmt.Println("Match: ", match) // Выведет: true
} Ответ 18+ 🔞
Так, слушай, вот сижу, думаю, как же народ до сих пор не въехал в простую, блядь, истину. Пароли в открытом виде хранить — это всё равно что на двери табличку повесить «ключ под ковриком, ёпта». Пиздец, а не безопасность.
Вот смотри, главные правила, без которых ты просто манда с ушами:
-
Только медленные алгоритмы, нахуй. SHA-256, MD5 — это для проверки целостности файлов, а не для паролей. Их за секунду перебрать можно, овердохуища мощностей сейчас. Нужно такое, что бы каждый хеш считался как будто ты на велосипеде в горку едешь. Bcrypt, Scrypt, Argon2 — вот твои новые боги. Особенно Argon2 — это вообще хитрая жопа, победитель всех конкурсов.
-
Соль, блядь, соль! Без соли — это как суп без картошки, пресно и уязвимо для радужных таблиц. Это случайная строка, которая мешает хакерам использовать готовые словари. Хорошие библиотеки её сами генерируют и в хеш зашивают, так что не парься.
-
Крути стоимость. У этих алгоритмов есть настройка «тяжести». Выставляй так, чтобы хеширование занимало, ну, 100-500 миллисекунд. Быстро для тебя, но овердохуища медленно для того, кто миллиарды комбинаций перебирает.
Вот, смотри, как на Go с bcrypt это выглядит, проще простого:
package main
import (
"fmt"
"golang.org/x/crypto/bcrypt"
)
// HashPassword хеширует пароль с использованием bcrypt
func HashPassword(password string) (string, error) {
// bcrypt.DefaultCost равен 10. Для продакшена рекомендуется 12-14.
bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14)
return string(bytes), err
}
// CheckPasswordHash сравнивает пароль с хешем
func CheckPasswordHash(password, hash string) bool {
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
return err == nil
}
func main() {
password := "mySecurePa$$w0rd"
hash, _ := HashPassword(password)
fmt.Println("Password:", password)
fmt.Println("Hash: ", hash)
match := CheckPasswordHash(password, hash)
fmt.Println("Match: ", match) // Выведет: true
}
Видишь? Никакой магии. Сгенерировал хеш, сохранил его в базу. Когда пользователь логинится — берёшь введённый пароль, сравниваешь с этим хешом. Всё, пизда, безопасно. Библиотека сама и соль достанет, и проверит.
Главное — не выёбывайся и не пытайся свою криптографию написать. Возьми проверенное, и спи спокойно. А то потом будешь как тот Герасим, смотреть на утонувшую базу пользователей и мычать «Му-му...», а нихуя не исправишь.