@LamerFromSpace
Студент-быдлокодер

Как безопасно сделать авторизацию?

Есть домашний сервер, размещённый за CloudFlare, к которому мне и паре знакомых нужно иногда обращаться. Нужно поставить на него пароль, тк информация там личная

Я это сделал так:
1. Юзер заходит на сайт, у него в куках проверяется кука auth, нету - кидает на страницу /login.
Кука проверяется на всех возможных страницах сайта, кроме /login .
Все хэндлеры (опять же, кроме /login) завернуты в функцию Auth таким образом:
mux := http.NewServeMux()

mux.HandleFunc("/", handlers.Index)
mux.HandleFunc("/settings", handlers.Settings)

mux.HandleFunc("/ajax/fetchDataReset", ajax.FetchDataReset)
mux.HandleFunc("/ajax/fetchDataUpdate", ajax.FetchDataUpdate)
mux.HandleFunc("/ajax/fetchDataUpdateAll", ajax.FetchDataUpdateAll)
	
private := handlers.Auth(mux)
...
log.Fatalln(http.ListenAndServe(":8080", private))

Функция Auth:
func Auth(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
               *проверка куки, если нет/неверная - редирект на /login*
               next.ServeHTTP(w, r)
        }
}


2. На странице логина ему на GET запрос отдается html страница, которая после загрузки шлет ajax GET запрос серверу, на который сервер отвечает строкой, сгенерированной так:
randomBytes := make([]byte, 64)
_, err := rand.Read(randomBytes) // из пакета crypt/rand
if err != nil {
	panic(err)
}
randStr := base64.URLEncoding.EncodeToString(randomBytes)[:64] // строка, возвращаемая сервером

Сама рандом строка записывается на сервере в мапу, где ключ к ней - значение куки __cfduid (кука ставится CloudFlare)
Время жизни этой строки ограничено

3. У пользователя на сайте через JS prompt запрашивается ввод пароля, затем пароль конкатенируется с рандомной строкой, которую отдал сервер, хэшируется и отсылается POST ajax запросом на сервер:
var pass = prompt("Введите пароль для доступа к сайту");
const msgUint8 = new TextEncoder().encode(randStr+pass);                       
const hashBuffer = await crypto.subtle.digest('SHA-512', msgUint8);       
const hashArray = Array.from(new Uint8Array(hashBuffer));               
const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
return hashHex; // Далее отправляется POSTом серверу


Сервер получает эту хэшированную строку, у себя так же хэширует randStr+pass (пароль захардкожен на стороне сервера) и сравнивает результат с тем, что пришло от клиента, если совпадает, выставляется такая кука:
http.Cookie{
	Name:     "__Host-auth",
	Value:    hash, // хэш от randStr+pass
	Path:     "/",
	Secure:   true,
	SameSite: http.SameSiteStrictMode,
	HttpOnly: true,
})


Эта кука и проверяется в функции Auth при каждом обращении к серверу, её значение сравнивается со значением хэша, записанном в ту же мапу, где хранятся рандомные строки с ключом __cfduid.

Насколько это рабочий и безопасный способ?
Как можно сделать лучше и менее коряво

UPD: Понял свою ошибку, соединение между клиентом и CloudFlare идёт по https, а вот между CloudFlare и моим сервером по http. Установка на сервер CloudFlare Origin CA сертификата решит эту проблему?
  • Вопрос задан
  • 462 просмотра
Пригласить эксперта
Ответы на вопрос 2
Jump
@Jump
Системный администратор со стажем.
Сервер получает эту хэшированную строку, у себя так же хэширует randStr+pass
Пароль хранится на сервере? А его там быть не должно!
Ответ написан
IgorPI
@IgorPI
JWT
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы