L
L
LamerFromSpace2019-08-14 04:00:41
JavaScript
LamerFromSpace, 2019-08-14 04:00:41

How to securely authorize?

There is a home server hosted by CloudFlare that I and a couple of my friends need to access occasionally. You need to put a password on it, because the information is personal there.
I did it like this:
1. The user enters the site, he checks the auth cookie in his cookies, if not, he throws it on the /login page.
The cookie is checked on all possible pages of the site, except for /login .
All handlers (again, except /login) are wrapped in an Auth function like this:

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 function:
func Auth(next http.Handler) http.Handler {
  return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
               *проверка куки, если нет/неверная - редирект на /login*
               next.ServeHTTP(w, r)
        }
}

2. On the login page, an html page is given to him on a GET request, which, after loading, sends an ajax GET request to the server, to which the server responds with a line generated like this:
randomBytes := make([]byte, 64)
_, err := rand.Read(randomBytes) // из пакета crypt/rand
if err != nil {
  panic(err)
}
randStr := base64.URLEncoding.EncodeToString(randomBytes)[:64] // строка, возвращаемая сервером

The random string itself is written to the map on the server, where the key to it is the cookie value __cfduid (the cookie is set by CloudFlare)
The lifetime of this string is limited to
3. The user on the site is prompted to enter a password via JS prompt, then the password is concatenated with a random string given by the server , hashed and sent as a POST ajax request to the server:
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ом серверу

The server receives this hashed string, also hashes randStr+pass (the password is hardcoded on the server side) and compares the result with what came from the client, if it matches, the following cookie is set:
http.Cookie{
  Name:     "__Host-auth",
  Value:    hash, // хэш от randStr+pass
  Path:     "/",
  Secure:   true,
  SameSite: http.SameSiteStrictMode,
  HttpOnly: true,
})

This cookie is checked in the Auth function each time the server is accessed, its value is compared with the hash value written to the same map where random strings with the __cfduid key are stored.
Is this a working and safe way?
How can I do better and less clumsily
UPD: I realized my mistake, the connection between the client and CloudFlare goes via https, but between CloudFlare and my server via http. Will installing a certificate on the CloudFlare Origin CA server solve this problem?

Answer the question

In order to leave comments, you need to log in

2 answer(s)
I
Igor, 2019-08-14
@IgorPI

JWT

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question