Bezbednost: open redirect i kolačići bez Secure atributa
- _next parametar: sanitizacija preko url.Parse (Host+Scheme prazan = relativan URL) umesto ručnog string check-a koji CodeQL nije prepoznavao - Kolačići: dodat Secure atribut (true u produkciji, false u razvoju) na 4 mesta: ntech_sesija brisanje (auth.go, prijava.go), ntech_flash_greska postavljanje i brisanje (auth.go, dashboard.go)
This commit is contained in:
@@ -3,6 +3,7 @@ package handler
|
|||||||
import (
|
import (
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
|
|
||||||
appdb "ntech/internal/db"
|
appdb "ntech/internal/db"
|
||||||
"ntech/internal/db/sqlite"
|
"ntech/internal/db/sqlite"
|
||||||
@@ -19,10 +20,12 @@ func (h *Handler) Dashboard(w http.ResponseWriter, r *http.Request) {
|
|||||||
if kol, err := r.Cookie("ntech_flash_greska"); err == nil {
|
if kol, err := r.Cookie("ntech_flash_greska"); err == nil {
|
||||||
flashGreska = kol.Value
|
flashGreska = kol.Value
|
||||||
http.SetCookie(w, &http.Cookie{
|
http.SetCookie(w, &http.Cookie{
|
||||||
Name: "ntech_flash_greska",
|
Name: "ntech_flash_greska",
|
||||||
Value: "",
|
Value: "",
|
||||||
Path: "/",
|
Path: "/",
|
||||||
MaxAge: -1,
|
MaxAge: -1,
|
||||||
|
HttpOnly: true,
|
||||||
|
Secure: os.Getenv("NTECH_ENV") == "production",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
@@ -264,8 +265,12 @@ func (h *Handler) SacuvajPodesavanja(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sledeci := "/podesavanja"
|
sledeci := "/podesavanja"
|
||||||
if next := r.FormValue("_next"); strings.HasPrefix(next, "/") && (len(next) == 1 || (next[1] != '/' && next[1] != '\\')) {
|
if next := r.FormValue("_next"); next != "" {
|
||||||
sledeci = next
|
if u, err := url.Parse(next); err == nil && u.Host == "" && u.Scheme == "" {
|
||||||
|
if p := u.RequestURI(); p != "" {
|
||||||
|
sledeci = p
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// backup podešavanja — pri neispravnom unosu javljamo jasnu grešku
|
// backup podešavanja — pri neispravnom unosu javljamo jasnu grešku
|
||||||
|
|||||||
@@ -262,11 +262,13 @@ func (h *Handler) Odjava(w http.ResponseWriter, r *http.Request) {
|
|||||||
_ = h.SesijeRepo.Obrisi(r.Context(), kolacic.Value)
|
_ = h.SesijeRepo.Obrisi(r.Context(), kolacic.Value)
|
||||||
}
|
}
|
||||||
http.SetCookie(w, &http.Cookie{
|
http.SetCookie(w, &http.Cookie{
|
||||||
Name: imeKolacica,
|
Name: imeKolacica,
|
||||||
Value: "",
|
Value: "",
|
||||||
Path: "/",
|
Path: "/",
|
||||||
Expires: time.Unix(0, 0),
|
Expires: time.Unix(0, 0),
|
||||||
MaxAge: -1,
|
MaxAge: -1,
|
||||||
|
Secure: os.Getenv("NTECH_ENV") == "production",
|
||||||
|
HttpOnly: true,
|
||||||
})
|
})
|
||||||
http.Redirect(w, r, "/prijava", http.StatusSeeOther)
|
http.Redirect(w, r, "/prijava", http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"ntech/internal/db/sqlite"
|
"ntech/internal/db/sqlite"
|
||||||
@@ -34,11 +35,13 @@ func RequireAuth(db *sql.DB, totpKljuc []byte) func(http.Handler) http.Handler {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
// nevažeći token — briši kolačić i preusmeri
|
// nevažeći token — briši kolačić i preusmeri
|
||||||
http.SetCookie(w, &http.Cookie{
|
http.SetCookie(w, &http.Cookie{
|
||||||
Name: "ntech_sesija",
|
Name: "ntech_sesija",
|
||||||
Value: "",
|
Value: "",
|
||||||
Path: "/",
|
Path: "/",
|
||||||
Expires: time.Unix(0, 0),
|
Expires: time.Unix(0, 0),
|
||||||
MaxAge: -1,
|
MaxAge: -1,
|
||||||
|
Secure: os.Getenv("NTECH_ENV") == "production",
|
||||||
|
HttpOnly: true,
|
||||||
})
|
})
|
||||||
http.Redirect(w, r, "/prijava", http.StatusSeeOther)
|
http.Redirect(w, r, "/prijava", http.StatusSeeOther)
|
||||||
return
|
return
|
||||||
@@ -154,6 +157,7 @@ func postaviFlashGresku(w http.ResponseWriter, poruka string) {
|
|||||||
Path: "/",
|
Path: "/",
|
||||||
MaxAge: 60,
|
MaxAge: 60,
|
||||||
HttpOnly: true,
|
HttpOnly: true,
|
||||||
|
Secure: os.Getenv("NTECH_ENV") == "production",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user