added sql injection simulation for authentication on server

This commit is contained in:
Vomitblood 2024-11-12 11:53:55 +08:00
parent 7232aed4ef
commit 0afbdd97d9
4 changed files with 96 additions and 12 deletions

View file

@ -33,6 +33,7 @@ PGPASSWORD=asdfpassword
!only listening on localhost is supported. DO NOT run this on a public ip. !only listening on localhost is supported. DO NOT run this on a public ip.
- `/health`
- `/setup-demo-db` - `/setup-demo-db`
- `/nuke-db` - `/nuke-db`
- `/fetch-all-users` - `/fetch-all-users`
@ -40,7 +41,9 @@ PGPASSWORD=asdfpassword
### SQL Injection ### SQL Injection
- `/sql-execute` - `/sql-execute`
- `/login-sql`
- `/secure-sql-execute` - `/secure-sql-execute`
- `/secure-login-sql`
- `/secure-get-user` - `/secure-get-user`
#### 1. Parameterization of Queries #### 1. Parameterization of Queries

View file

@ -45,20 +45,20 @@ func ConnectToDb() (*pgxpool.Pool, error) {
func SetupDemoDb(w http.ResponseWriter, r *http.Request) { func SetupDemoDb(w http.ResponseWriter, r *http.Request) {
// create table and insert demo data // create table and insert demo data
createTableSQL := ` createTableSQL := `
CREATE TABLE IF NOT EXISTS users ( CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY, id SERIAL PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL, username VARCHAR(50) UNIQUE NOT NULL,
email VARCHAR(100) NOT NULL, email VARCHAR(100) NOT NULL,
password VARCHAR(100) NOT NULL password VARCHAR(100) NOT NULL
);` );`
// also avoid duplicate entries // also avoid duplicate entries
insertDataSQL := ` insertDataSQL := `
INSERT INTO users (username, email, password) VALUES INSERT INTO users (username, email, password) VALUES
('alice', 'alice@example.com', 'asdfalicepassword'), ('alice', 'alice@example.com', 'asdfalicepassword'),
('bob', 'bob@example.com', 'asdfbobpassword'), ('bob', 'bob@example.com', 'asdfbobpassword'),
('charlie', 'charlie@example.com', 'asdfcharliepassword') ('charlie', 'charlie@example.com', 'asdfcharliepassword')
ON CONFLICT (username) DO NOTHING;` ON CONFLICT (username) DO NOTHING;`
// execute create table // execute create table
_, err := DbPool.Exec(context.Background(), createTableSQL) _, err := DbPool.Exec(context.Background(), createTableSQL)

View file

@ -21,7 +21,9 @@ func ServeApi() {
http.HandleFunc("/nuke-db", db.NukeDb) http.HandleFunc("/nuke-db", db.NukeDb)
http.HandleFunc("/fetch-all-users", db.FetchAllUsers) http.HandleFunc("/fetch-all-users", db.FetchAllUsers)
http.HandleFunc("/execute-sql", sql_injection.ExecuteSql) http.HandleFunc("/execute-sql", sql_injection.ExecuteSql)
http.HandleFunc("/login-sql", sql_injection.LoginSql)
http.HandleFunc("/secure-execute-sql", sql_injection.SecureExecuteSql) http.HandleFunc("/secure-execute-sql", sql_injection.SecureExecuteSql)
http.HandleFunc("/secure-login-sql", sql_injection.SecureLoginSql)
http.HandleFunc("/secure-get-user", sql_injection.SecureGetUser) http.HandleFunc("/secure-get-user", sql_injection.SecureGetUser)
log.Println("Server is running on http://localhost:5000") log.Println("Server is running on http://localhost:5000")
if err := http.ListenAndServe(":5000", nil); err != nil { if err := http.ListenAndServe(":5000", nil); err != nil {

View file

@ -46,6 +46,50 @@ func ExecuteSql(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(response)) w.Write([]byte(response))
} }
// unsecure login
// login endpoint with sql injection vulnerability
func LoginSql(w http.ResponseWriter, r *http.Request) {
// parse the request body to get username and password
var credentials struct {
Username string `json:"username"`
Password string `json:"password"`
}
// decode the json body
if err := json.NewDecoder(r.Body).Decode(&credentials); err != nil {
http.Error(w, "Invalid request format", http.StatusBadRequest)
return
}
defer r.Body.Close()
// construct the unsafe query
query := fmt.Sprintf(
"SELECT id, username FROM users WHERE username = '%s' AND password = '&s'",
credentials.Username,
credentials.Password,
)
// execute the query without sanitizing the input
var id int
var username string
err := db.DbPool.QueryRow(context.Background(), query).Scan(&id, &username)
if err != nil {
http.Error(w, "Invalid credentials", http.StatusUnauthorized)
return
}
// if the user is found, return success response
response := map[string]interface{}{
"message": "Login successful",
"user_id": id,
"username": username,
}
if err := json.NewEncoder(w).Encode(response); err != nil {
http.Error(w, "Failed to encode response", http.StatusInternalServerError)
log.Printf("JSON encoding error: %v", err)
}
}
// secure version // secure version
// only allow parameterized queries with validation // only allow parameterized queries with validation
func SecureExecuteSql(w http.ResponseWriter, r *http.Request) { func SecureExecuteSql(w http.ResponseWriter, r *http.Request) {
@ -95,7 +139,7 @@ func SecureExecuteSql(w http.ResponseWriter, r *http.Request) {
// return json response // return json response
jsonResp, err := json.Marshal(response) jsonResp, err := json.Marshal(response)
if err != nil { if err != nil {
http.Error(w, "Failed to encode response as JSON", http.StatusInternalServerError) http.Error(w, "Failed to encode response", http.StatusInternalServerError)
return return
} }
@ -103,6 +147,41 @@ func SecureExecuteSql(w http.ResponseWriter, r *http.Request) {
w.Write(jsonResp) w.Write(jsonResp)
} }
// secure login
func SecureLoginSql(w http.ResponseWriter, r *http.Request) {
var credentials struct {
Username string `json:"username"`
Password string `json:"password"`
}
if err := json.NewDecoder(r.Body).Decode(&credentials); err != nil {
http.Error(w, "Invalid request format", http.StatusBadRequest)
return
}
defer r.Body.Close()
// secure version using parameterized queries
query := "SELECT id, username FROM users WHERE username = $1 AND password = $2"
var id int
var username string
err := db.DbPool.QueryRow(context.Background(), query, credentials.Username, credentials.Password).Scan(&id, &username)
if err != nil {
http.Error(w, "Invalid credentials", http.StatusUnauthorized)
return
}
// send back the response if great success
response := map[string]interface{}{
"message": "Login successful",
"user_id": id,
"username": username,
}
if err := json.NewEncoder(w).Encode(response); err != nil {
http.Error(w, "Failed to encode response", http.StatusInternalServerError)
log.Printf("JSON encoding error: %v", err)
}
}
// even more secure // even more secure
func SecureGetUser(w http.ResponseWriter, r *http.Request) { func SecureGetUser(w http.ResponseWriter, r *http.Request) {
// decode the json body // decode the json body