Aula 09 - Golang - Fiber - Register User
Nessa aula vamos adicionar o pacote
bcrypt para poder fazer o hash do password do usuário, para isso acesse:
pkg.go.dev
E pesquise
bcrypt, aí então é só escolher a primeira opção que aparece.
Instalando bcrypt no projeto
Se o projeto tiver rodando, pare ele e instale com:
go get -u golang.org/x/crypto/bcrypt
Bcrypt é um padrão da indústria testado e comprovado para resistir a ameaças de hackers e outros agentes mal-intencionados.
O que ele faz é
aplicar uma
funçao de hash na senha em texto puro, para depois, na hora de armazenar, salvar no banco só o hash gerado e não a senha original.
A ideia por trás do
hash de senhas dos usuários, é deixar as
passwords seguras contra ataques de hackers, ou qualquer tipo de invasão de sistema, enfim, qualquer ação maliciosa.
Há
3 formas que as empresas armazenam as passwords:
texto puro(
plain text),
encriptografando a
senha, ou usando uma
função de
hash.
Texto puro
Texto puro é obviamente a maneira mais perigosa de armazenar senhas.
Se hackers violarem o banco de dados da empresa, eles conseguem ver todas as senhas dos usuários.
Muitas pessoas têm o mau hábito de usar a mesma senha para várias contas, é provável que 1 senha comprometida pode levar a mais contas comprometidas.
Encriptografando a senha
Uma alternativa possível ao armazenamento de texto puro é a criptografia.
As empresas pegam as senhas dos usuários e antes de armazenar, criptografa elas com uma chave.
Isso impediria que hackers obtivessem as senhas reais dos usuários, mas ainda é muito arriscado.
Na camada de criptografia ainda é uma senha de texto puro e por isso se o invasor consegue roubar a chave de criptografia também, ele pode desbloquear todas as senhas.
A criptografia foi projetada para funcionar de duas maneiras: você pode criptografar as senhas de um usuário para manter ela segura, mas, você também pode descriptografá-la para revelar a senha novamente.
Isso é muito prático quando você quer compartilhar dados de forma segura, mas não é bom se você quer impedir que invasores violem sua senha.
Isso nos leva à terceira técnica de armazenar senhas que é usando
função de hash.
Função de Hash
Como funciona?
As funções hash pega uma entrada, que pode ser um texto como senha ou um arquivo, e transforma em uma string de texto sempre com o mesmo comprimento.
Existem muitas funções diferentes de hash disponíveis:
MD4,
MD5,
SHA-1,
WHIRLPOOL, etc.
As funções de hash são muito diferentes da criptografia porque elas só funcionam unidirecionamente.
Você pode calcular o hash de uma senha, mas você não pode pegar um hash e transformá-lo de volta aos dados originais.
Ao usar
hashes, as empresas podem verificar se você está logando com a senha correta, sem ter que armazenar sua senha real.
No entanto, elas não são perfeitas também.
A maioria dos algoritmos de hashing são otimizados para velocidade, quanto mais hashes por segundo, melhor e mais seguro é o hash que elas podem calcular.
Mas de qualquer forma, existe uma vulnerabilidade a ataques de força bruta.
O hacker pode simplesmente tentar calcular todas as senhas possíveis, e conseguir reverter o hash.
Uma GPU moderna pode fazer isso com uma velocidade de 292 milhões de hashes por segundo (292,2 MH/s), é só uma questão de tempo antes de uma senha hash ser quebrada usando essa técnica.
E se isso não for rápido o suficiente, hackers também podem usar rainbow table para acelerar o processo.
Estas são listas de hashes pré-computados que podem ser usadas para encontrar rapidamente senhas fracas e comumente usadas.
Veja na ilustração abaixo como funciona a função de hash.

Veja a tabela abaixo, mostrando a aplicação da
função de hash MD5 nas senhas:
a,
ab,
abc, e
abc1.
Perceba que o hash gerado é sempre do mesmo tamanho, independente do tamanho da senha.
Vamos importar o
bcrypt e usar para fazer o hash da senha com o custo de
14 para gerar o hash.
fiber-project/controllers/authController.go
package controllers
import (
"fiber-project/models"
"github.com/gofiber/fiber/v2"
"golang.org/x/crypto/bcrypt"
)
func Register(c *fiber.Ctx) error {
var data map[string]string
if err := c.BodyParser(&data); err != nil {
return err
}
if data["password"] != data["confirm_password"] {
c.Status(400)
return c.JSON(fiber.Map{
"message": "Passwords do not match!",
})
}
password, _ := bcrypt.GenerateFromPassword([]byte(data["password"]), 14)
user := models.User{
FirstName: data["first_name"],
LastName: data["last_name"],
Email: data["email"],
Password: password,
}
return c.JSON(user)
}
Temos que trocar o campo
Password de
string para
[]byte no
modelo user.
fiber-project/models/user.go
package models
type User struct {
Id uint
FirstName string
LastName string
Email string `gorm:"unique"`
Password []byte
}
Nesse ponto podemos fazer um teste com o postman, no endpoint
http://localhost:8000/api/register
Saída:
{
"Id": 0,
"FirstName": "a",
"LastName": "a",
"Email": "a@mail.com",
"Password": "JDJhJDE0JC44TG9tVGRzb29GeGQxUWJpcW9MaWUuZFJiWThFaFo0V2lMOWdWQjAzL1NmSTJuc2s2aFJ5"
}
E fazer uma
request POST e vê se a saída mostra a senha depois de passar pela função hash.
Agora vamos salvar a senha no banco.
Para isso, vamos precisar do
fiber-project/database/connect.go dentro do
fiber-project/controllers/authController.go.
Para fazer isso, vamos criar uma variável chamada
DB, e ela será um ponteiro para o
*gorm.DB que é o drive para acesso ao banco
A variável
connection ela abre a conexão com o
mysql, e o drive que tá referenciado pela variável DB, vai apontar para a connection.
fiber-project/database/connect.go
package database
import (
"fmt"
"fiber-project/models"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
var DB *gorm.DB
func Connect() {
var dsn = "toticavalcanti:mysql1234@/fluent_admin?charset=utf8mb4&parseTime=True&loc=Local"
var v = "Não conseguiu conectar ao banco de dados"
connection, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
panic(v)
}
DB = connection
connection.AutoMigrate(&models.User{})
fmt.Println("Conexão OK!")
}
Ponteiros
Exemplo de uso de ponteiro
Agora podemos salvar o usuário e sua senha depois de passar pela função de
hash.
fiber-project/controllers/authController.go
package controllers
import (
"fiber-project/database"
"fiber-project/models"
"github.com/gofiber/fiber/v2"
"golang.org/x/crypto/bcrypt"
)
func Register(c *fiber.Ctx) error {
var data map[string]string
if err := c.BodyParser(&data); err != nil {
return err
}
if data["password"] != data["confirm_password"] {
c.Status(400)
return c.JSON(fiber.Map{
"message": "Passwords do not match!",
})
}
password, _ := bcrypt.GenerateFromPassword([]byte(data["password"]), 14)
user := models.User{
FirstName: data["first_name"],
LastName: data["last_name"],
Email: data["email"],
Password: password,
}
database.DB.Create(&user)
return c.JSON(user)
}
Teste novamente usando o Postman.
{
"Id": 1,
"FirstName": "a",
"LastName": "a",
"Email": "a@mail.com",
"Password": "JDJhJDE0JC44TG9tVGRzb29GeGQxUWJpcW9MaWUuZFJiWThFaFo0V2lMOWdWQjAzL1NmSTJuc2s2aFJ5"
}
Nos vemos na próxima então ;)
Até lá!
Código da aula: Github
Redes Sociais:
Novamente deixo meus link de afiliados:
Obrigado, até a próxima e bons estudos. ;)