removed bcrypt; too secure haha
This commit is contained in:
parent
ffbdd9d427
commit
ec31b5318a
12
README.md
12
README.md
|
@ -41,6 +41,8 @@ PGPASSWORD=asdfpassword
|
||||||
|
|
||||||
### SQL Injection
|
### SQL Injection
|
||||||
|
|
||||||
|
Use `' OR 1=1; --`
|
||||||
|
|
||||||
- `/unsecure-register-sql`
|
- `/unsecure-register-sql`
|
||||||
- `/secure-register-sql`
|
- `/secure-register-sql`
|
||||||
- `/unsecure-login-sql`
|
- `/unsecure-login-sql`
|
||||||
|
@ -50,13 +52,3 @@ PGPASSWORD=asdfpassword
|
||||||
|
|
||||||
Used `pool.Query()` with a parameterized query, instead of dynamically constructing the SQL query by directly inserting the user input.
|
Used `pool.Query()` with a parameterized query, instead of dynamically constructing the SQL query by directly inserting the user input.
|
||||||
Parameterized queries separate the SQL code from the data, so user input is never directly put into the query's structure. Placeholders are used instead, and the data is passed as parameters. The DB will treat them as data, not executable code.
|
Parameterized queries separate the SQL code from the data, so user input is never directly put into the query's structure. Placeholders are used instead, and the data is passed as parameters. The DB will treat them as data, not executable code.
|
||||||
|
|
||||||
#### 2. Input Validation and Query Type Restriction
|
|
||||||
|
|
||||||
Only allow `SELECT` statement by verifying that the input query starts with it.
|
|
||||||
Sanitized the input to ensure that no other types of statements could be executed.
|
|
||||||
The input is checked against a list of allowed query terms, and if it doesn't match, the query is rejected.
|
|
||||||
|
|
||||||
#### 3. Controlled JSON Input for Parameters
|
|
||||||
|
|
||||||
Instead of using raw SQL strings, we restructured the input to ONLY expect JSON data with `query` and `params` fields.
|
|
||||||
|
|
|
@ -9,7 +9,6 @@ import (
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
"github.com/Vomitblood/cspj-application/server/internal/db"
|
"github.com/Vomitblood/cspj-application/server/internal/db"
|
||||||
"golang.org/x/crypto/bcrypt"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// secure register endpoint
|
// secure register endpoint
|
||||||
|
@ -57,17 +56,9 @@ func UnsecureRegisterSql(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash the password
|
|
||||||
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(credentials.Password), bcrypt.DefaultCost)
|
|
||||||
fmt.Println(hashedPassword)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, "Error hashing password", http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// over here the validations has passed, so insert into the db
|
// over here the validations has passed, so insert into the db
|
||||||
// also use concatenation here
|
// also use concatenation here
|
||||||
insertSQL := fmt.Sprintf("INSERT INTO users (email, password, role) VALUES ('%s', '%s', 'user')", credentials.Email, string(hashedPassword))
|
insertSQL := fmt.Sprintf("INSERT INTO users (email, password, role) VALUES ('%s', '%s', 'user')", credentials.Email, credentials.Password)
|
||||||
_, err = db.DbPool.Exec(context.Background(), insertSQL)
|
_, err = db.DbPool.Exec(context.Background(), insertSQL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "Error inserting user into the database", http.StatusInternalServerError)
|
http.Error(w, "Error inserting user into the database", http.StatusInternalServerError)
|
||||||
|
@ -126,17 +117,10 @@ func SecureRegisterSql(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash the password
|
|
||||||
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(credentials.Password), bcrypt.DefaultCost)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, "Error hashing password", http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// over here the validations has passed, so insert into the db
|
// over here the validations has passed, so insert into the db
|
||||||
// use parameterization
|
// use parameterization
|
||||||
insertSQL := `INSERT INTO users (email, password, role) VALUES ($1, $2, $3)`
|
insertSQL := `INSERT INTO users (email, password, role) VALUES ($1, $2, $3)`
|
||||||
_, err = db.DbPool.Exec(context.Background(), insertSQL, credentials.Email, hashedPassword, "user")
|
_, err = db.DbPool.Exec(context.Background(), insertSQL, credentials.Email, credentials.Password, "user")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "Error inserting user into the database", http.StatusInternalServerError)
|
http.Error(w, "Error inserting user into the database", http.StatusInternalServerError)
|
||||||
log.Printf("Error inserting user: %v", err)
|
log.Printf("Error inserting user: %v", err)
|
||||||
|
@ -149,7 +133,6 @@ func SecureRegisterSql(w http.ResponseWriter, r *http.Request) {
|
||||||
log.Println("User registered successfully:", credentials.Email)
|
log.Println("User registered successfully:", credentials.Email)
|
||||||
}
|
}
|
||||||
|
|
||||||
// very secure login endpoint
|
|
||||||
func UnsecureLoginSql(w http.ResponseWriter, r *http.Request) {
|
func UnsecureLoginSql(w http.ResponseWriter, r *http.Request) {
|
||||||
// decode the json body
|
// decode the json body
|
||||||
var requestData struct {
|
var requestData struct {
|
||||||
|
@ -157,43 +140,29 @@ func UnsecureLoginSql(w http.ResponseWriter, r *http.Request) {
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// declare new json decoder with custom property
|
// decode the request body
|
||||||
jsonDecoder := json.NewDecoder(r.Body)
|
|
||||||
// rejects any unknown fields in the json, more strict
|
|
||||||
jsonDecoder.DisallowUnknownFields()
|
|
||||||
|
|
||||||
if err := json.NewDecoder(r.Body).Decode(&requestData); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&requestData); err != nil {
|
||||||
http.Error(w, "Invalid request format", http.StatusBadRequest)
|
http.Error(w, "Invalid request format", http.StatusBadRequest)
|
||||||
log.Println("Failed to decode JSON body or extra fields present:", err)
|
log.Println("Failed to decode JSON body:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate that user is provided
|
// make insecure sql command
|
||||||
if requestData.Email == "" || requestData.Password == "" {
|
query := fmt.Sprintf("SELECT id, email, password FROM users WHERE email = '%s' AND password = '%s'", requestData.Email, requestData.Password)
|
||||||
http.Error(w, "Invalid request format", http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// retrieve the user data
|
|
||||||
// construct sql command using concatenation
|
|
||||||
query := fmt.Sprintf("SELECT id, email, password FROM users WHERE email = '%s'", requestData.Email)
|
|
||||||
var id int
|
var id int
|
||||||
var email string
|
var email string
|
||||||
var hashedPassword string
|
var password string
|
||||||
err := db.DbPool.QueryRow(context.Background(), query).Scan(&id, &email, &hashedPassword)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, "Invalid email or password", http.StatusNotFound)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// compare the provided password with the stored hashed password
|
// execute the query to retrieve the data
|
||||||
err = bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(requestData.Password))
|
err := db.DbPool.QueryRow(context.Background(), query).Scan(&id, &email, &password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "Invalid email or password", http.StatusUnauthorized)
|
http.Error(w, "Invalid email or password", http.StatusUnauthorized)
|
||||||
|
log.Println("Error during query execution:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// send back the user data as a JSON response
|
// if the email and password match then send back the user data
|
||||||
response := map[string]interface{}{
|
response := map[string]interface{}{
|
||||||
"id": id,
|
"id": id,
|
||||||
"email": email,
|
"email": email,
|
||||||
|
@ -248,17 +217,16 @@ func SecureLoginSql(w http.ResponseWriter, r *http.Request) {
|
||||||
// retrieve the email and password from the database
|
// retrieve the email and password from the database
|
||||||
var id int
|
var id int
|
||||||
var email string
|
var email string
|
||||||
var hashedPassword string
|
var storedPassword string
|
||||||
query := "SELECT id, email, password FROM users WHERE email = $1"
|
query := "SELECT id, email, password FROM users WHERE email = $1"
|
||||||
err = db.DbPool.QueryRow(context.Background(), query, requestData.Email).Scan(&id, &email, &hashedPassword)
|
err = db.DbPool.QueryRow(context.Background(), query, requestData.Email).Scan(&id, &email, &storedPassword)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "Invalid email or password", http.StatusNotFound)
|
http.Error(w, "Invalid email or password", http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// compare the provided password and the stored password hashes
|
// compare the provided password with the stored plain-text password
|
||||||
err = bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(requestData.Password))
|
if storedPassword != requestData.Password {
|
||||||
if err != nil {
|
|
||||||
http.Error(w, "Invalid email or password", http.StatusUnauthorized)
|
http.Error(w, "Invalid email or password", http.StatusUnauthorized)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue