Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Task/validation #43

Open
wants to merge 10 commits into
base: dev
Choose a base branch
from
Open

Task/validation #43

wants to merge 10 commits into from

Conversation

mevain
Copy link
Collaborator

@mevain mevain commented Nov 12, 2024

Я тут добавила валидацию полей и заново сделала защиту от xss и csrf

@mevain mevain requested a review from vr009 November 12, 2024 12:57
@mevain
Copy link
Collaborator Author

mevain commented Nov 12, 2024

Только я не все хендлеры обернула, потому что все post put и delete обернуты в MiddlewareAuth, и я не очень понимаю, их в обе нужно обернуть или оставить одну?

.env Outdated
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

файл надо убрать

Copy link
Collaborator

@vr009 vr009 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Очень усложнила схему, переизобретать jwt не стоит, прокидывать userID доп заголовками тоже не очень, это и не нужно

Login: user.Login,
Email: user.Email,
tokenExpTime := time.Now().Unix() + 3600
secretKey := os.Getenv("CSRF_SECRET")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Такое лучше конфигурировать при старте сервиса и прокидывать в поля структуры хэндлера

cookies.txt Outdated
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

тоже что-то лишнее

Comment on lines 26 to 42
func (tk *HashToken) Create(userUUID uuid.UUID, tokenExpTime int64) (string, error) {
h := hmac.New(sha256.New, tk.Secret)
data := fmt.Sprintf("%s:%d", userUUID.String(), tokenExpTime)
h.Write([]byte(data))
token := hex.EncodeToString(h.Sum(nil)) + ":" + strconv.FormatInt(tokenExpTime, 10)
return token, nil
}

func (tk *HashToken) Check(userUUID uuid.UUID, inputToken string) (bool, error) {
tokenData := strings.Split(inputToken, ":")
if len(tokenData) != 2 {
return false, fmt.Errorf("invalid token format")
}
tokenExpStr := strings.TrimSpace(tokenData[1])
tokenExp, err := strconv.ParseInt(tokenExpStr, 10, 64)
if err != nil {
return false, fmt.Errorf("invalid token expiration")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

И все таки, а чем тебя jwt не устроил?)

}

response := UserResponseWithCSRF{
User: user,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Прям с паролем!

func CSRFMiddleware(tk *HashToken, next http.Handler, logger *slog.Logger) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
csrfToken := r.Header.Get("X-CSRF-Token")
userUUIDStr := r.Header.Get("X-User-UUID")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А зачем этот заголовок, у пользователя разве нет другого способа аутентификации?

@vr009
Copy link
Collaborator

vr009 commented Nov 13, 2024

Смотри, давай лучше немного шаг назад сделаем и подсветим две проблемы твоего подхода:

  1. Формат токена. От токена надо чтобы он идентифицировал пользователя, для этого мы либо генерируем какую-то уникальную строку которая будет токеном и сохраняем соответствующую информацию об ассоциированном пользователе в базу. Либо мы храним информацию о пользователе в токене, но тогда мы должны убедиться, что токен нельзя подделать, для этого ты используешь hmac - это правильно, но можно просто использовать jwt токены, которые используют тот же механизм.

  2. Передача токена. Главная задача - обойти проблему автоматического добавления кук браузером. В csrf аттаках это активно используется, поэтому задача на бэкенде - как-то понимать что куки с которыми пришел запрос исходит от браузера который находится на нашем сайте. По сути из-за автоматики с куками мы это никак не различаем, поэтому нам нужен какой-то дополнительный механизм, которому мы будем доверять, что пользователь отправляет запросы не с левого источника. Для этого придумали samesite параметр кук, но придумали достаточно поздно, те теоретически какие-то старые браузеры не будут понимать этот параметр и могут все равно быть уязвимы к тому чтобы пользователь зашел на другой сайт и открыв картинку нечаянно отправит какой нибудь модификационный запрос. Поэтому samesite берем на борт и можем считать что большую часть кейсов покрыли, но надо бы добавить что-то еще что точно будет помогать независимо от клиента. Вот здесь мы можем воспользоваться кастомными хедерами которые прокидывает наш клиентский код. Соотв на бэке ты получаешь куку пользователя, таким образом аутентифицируешь его, затем берешь csrf токен из хэдера, проверяешь токен на валидность (подпись итд) вытаскиваешь userID, сверяешь с тем что пришло с аутентификационной инфой и пропускаешь запрос дальше. Таким образом злоумышленнику чтобы совершить crsf аттаку придется проставлять кастомный хэдер самостоятельно, а тривиально сделать это нелегко

@mevain mevain requested a review from vr009 November 14, 2024 20:54
@@ -33,6 +36,11 @@ type Handler struct {
logger *slog.Logger
}

type UserResponseWithToken struct {
User models.User `json:"user"`
Token string `json:"csrf_token"`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Это уже называется access_token

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

В json можно просто token или access_token. CSRF тут уже не при чем

@@ -18,19 +18,19 @@ const (

func MiddlewareAuth(jwtService jwt.JWTInterface, next http.Handler, logger *slog.Logger) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("X-CSRF-Token")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CSRF тут уже не при чем, ты поменяла механизм передачи токена. Теперь это скорее вот эта схема https://swagger.io/docs/specification/v3_0/authentication/bearer-authentication/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants