Aula 08 - Golang para Web - Senhas Encriptadas com Hashing

Se gostarem do conteúdo dêem um joinha 👍 na página do Código Fluente no Facebook

Link do código fluente no Pinterest

Meus links de afiliados:

Hostinger

Digital Ocean

One.com

Código da aula: Github

Melhore seu NETWORKING

Participe de comunidades de desenvolvedores:

Fiquem a vontade para me adicionar ao linkedin.

E também para me seguir no GITHUB.

Ah, se puder, clica na estrela nos meus repositórios pra dá uma força ao meu perfil no GITHUB.

Senhas encriptadas usando bcrypt

Utilizaremos o bcrypt para manipular a autenticação de senha dos usuários. A ideia básica é que você nunca armazene a senha do usuário no seu banco de dados, ao invés disso, sempre aplique uma função de hash. Ela é um tipo especial de função unidirecional que transforma o senha do usuário em um novo valor que não pode ser facilmente revertido para recuperar. Esse valor de transformado pela função de hash é o que a gente armazena no banco de dados. Quando o usuário faz o login, a mesma transformação é aplicada para a senha, o resultado é comparado com o que foi armazenado no banco de dados e se o resultado é o mesmo que o valor armazenado, o login é feito. Dessa forma, se um invasor tiver acesso ao seu banco de dados, eles só conseguirão ver as senhas com o hash. Eles podem até tentar quebrar as senhas usando força bruta, tentando combinações diferentes e aplicando a mesma função hash que usamos até tentar encontrar. Mas, algoritmos como bcrypt, são projetados com um parâmetro de custo que nos permite ajustar quanto poder computacional o hash vai precisar. Isso permite aumentar o custo dos hashes para que fique mais difícil ainda quebrar as senhas com força bruta.

Instalação do bcrypt

Digite no terminal:

go get golang.org/x/crypto/bcrypt
Agora podemos importar ele no código. Veja as modificações que iremos fazer nessa aula: Vamos deletar a função testGetHandler que fizemos na aula passada. Vamos adicionar dois novos manipuladores ao nosso aplicativo para registrar novos usuários, o registerGetHandler e o registerPostHandler. E também o register.html na pasta de templates. Vamos alterar a login.html para inserir o campo de senha. Vamos também pegar uma sessão existente ou criar uma nova no indexGetHandler usando o store.Get. Existem melhores maneiras de lidar com isso, diferente de como vamos fazer nessa aula, porque essa abordagem tem algumas falhas, uma delas é que estamos forçando o usuário a estar logado, para acessar a página principal. Você poderá perceber, que quando entrar na:

localhost:8000/register

Vai ser redirecionado para a página de login. A gente vai melhorar isso mais na frente.

Então partiu código! 💻🤘🏻

Veja os códigos.


<!DOCTYPE html>
<html>
  <head>
    <title>Register</title>
  </head>
  <body>
    <form method="POST">
      <div>Username: <input name="username"></div>
      <div>Password: <input name="password"></div>
      <div>
        <button type="submit">Register</button>
      </div>
    </form>
  </body>
</html>

<!DOCTYPE html>
<html>
  <head>
    <title>Login</title>
  </head>
  <body>
    <form method="POST">
      <div>Username: <input name="username"></div>
      <div>Password: <input name="password"></div>
      <div>
        <button type="submit">Login</button>
      </div>
    </form>
  </body>
</html>

Seguindo


package main

import (
	"html/template"
	"net/http"

	"github.com/go-redis/redis"
	"github.com/gorilla/mux"
	"github.com/gorilla/sessions"
	"golang.org/x/crypto/bcrypt"
)

//globals variables
var client *redis.Client
var store = sessions.NewCookieStore([]byte("t0p-s3cr3t"))
var templates *template.Template

func main() {
	client = redis.NewClient(&redis.Options{
		Addr: "localhost:6379",
	})
	templates = template.Must(template.ParseGlob("templates/*.html"))
	r := mux.NewRouter()
	r.HandleFunc("/", indexGetHandler).Methods("GET")
	r.HandleFunc("/", indexPostHandler).Methods("POST")
	r.HandleFunc("/login", loginGetHandler).Methods("GET")
	r.HandleFunc("/login", loginPostHandler).Methods("POST")
	r.HandleFunc("/register", registerGetHandler).Methods("GET")
	r.HandleFunc("/register", registerPostHandler).Methods("POST")
	fs := http.FileServer(http.Dir("./static/"))
	r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", fs))
	http.Handle("/", r)
	http.ListenAndServe(":8080", nil)
}

//request hello handle
func indexGetHandler(w http.ResponseWriter, r *http.Request) {
	session, _ := store.Get(r, "session")
	_, ok := session.Values["username"]
	if !ok {
		http.Redirect(w, r, "/login", 302)
		return
	}
	comments, err := client.LRange("comments", 0, 10).Result()
	if err != nil {
		return
	}
	templates.ExecuteTemplate(w, "index.html", comments)
}

func indexPostHandler(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	comment := r.PostForm.Get("comment")
	client.LPush("comments", comment)
	http.Redirect(w, r, "/", 302)
}

func loginGetHandler(w http.ResponseWriter, r *http.Request) {
	templates.ExecuteTemplate(w, "login.html", nil)
}

func loginPostHandler(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	username := r.PostForm.Get("username")
	password := r.PostForm.Get("password")
	hash, err := client.Get("user: " + username).Bytes()
	if err != nil {
		return
	}
	err = bcrypt.CompareHashAndPassword(hash, []byte(password))
	if err != nil {
		return
	}
	session, _ := store.Get(r, "session")
	session.Values["username"] = username
	session.Save(r, w)
	http.Redirect(w, r, "/", 302)
}

func registerGetHandler(w http.ResponseWriter, r *http.Request) {
	templates.ExecuteTemplate(w, "register.html", nil)
}

func registerPostHandler(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	username := r.PostForm.Get("username")
	password := r.PostForm.Get("password")
	cost := bcrypt.DefaultCost
	hash, err := bcrypt.GenerateFromPassword([]byte(password), cost)
	if err != nil {
		return
	}
	client.Set("user: "+username, hash, 0)
	http.Redirect(w, r, "/login", 302)
}

//request contact page handle
func contactHandler(w http.ResponseWriter, r *http.Request) {
	templates.ExecuteTemplate(w, "contact.html", "This is the contact page!")
}

//request about page handle
func aboutHandler(w http.ResponseWriter, r *http.Request) {
	templates.ExecuteTemplate(w, "about.html", "This is the about page!")
}

Acesse:

localhost:8000

Por agora é só, nos vemos próxima. ;)

Código da aula: Github

Se gostarem do conteúdo dêem um joinha 👍 na página do Código Fluente no Facebook

Link do código fluente no Pinterest

Novamente deixo meus link de afiliados:

Hostinger

Digital Ocean

One.com

Obrigado, até a próxima e bons estudos. ;)