diff --git a/README.md b/README.md index f6aebcc..354acb8 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,9 @@ PGPASSWORD=asdfpassword ### SQL Injection +- `/unsecure-register-sql` - `/secure-register-sql` +- `/unsecure-login-sql` - `/secure-login-sql` #### 1. Parameterization of Queries diff --git a/client/public/images/logo.webp b/client/public/images/logo.webp new file mode 100644 index 0000000..4f28713 Binary files /dev/null and b/client/public/images/logo.webp differ diff --git a/client/src/components/Generic/HeaderLogo.tsx b/client/src/components/Generic/HeaderLogo.tsx index 3702651..ecdcc9f 100644 --- a/client/src/components/Generic/HeaderLogo.tsx +++ b/client/src/components/Generic/HeaderLogo.tsx @@ -17,7 +17,7 @@ export const HeaderLogo: FC = ({ sx }) => { alt="Logo" height={40} priority - src="images/logo.gif" + src="images/logo.webp" width={40} /> { return ( setServerUrl(event.target.value)} - size='small' + label="Backend server URL" + // onChange={(event) => setServerUrl(event.target.value)} + size="small" value={serverUrl} /> ); diff --git a/client/src/components/Pages/Home/Home.tsx b/client/src/components/Pages/Home/Home.tsx index 930898a..3060274 100644 --- a/client/src/components/Pages/Home/Home.tsx +++ b/client/src/components/Pages/Home/Home.tsx @@ -30,12 +30,12 @@ export const Home = () => { CSPJ Application Attack Simulator - + */} { // contexts @@ -18,6 +19,7 @@ export const SqlInjectionLogin = () => { const [passwordValueRaw, setPasswordValueRaw] = useState(""); const [errorMsg, setErrorMsg] = useState(""); const [loginLoading, setLoginLoading] = useState(false); + const [secured, setSecured] = useState(false); const nextClickEvent = async () => { // reset the error messages @@ -35,9 +37,11 @@ export const SqlInjectionLogin = () => { // start loading indicator setLoginLoading(true); + const endpointUrl = serverUrl + (secured ? "/secure-login-sql" : "/unsecure-login-sql"); + try { // make request good - const response = await fetch(serverUrl + "/register-sql", { + const response = await fetch(endpointUrl, { method: "POST", headers: { "Content-Type": "application/json", @@ -100,7 +104,7 @@ export const SqlInjectionLogin = () => { label="Email" onChange={(e: { target: { value: string } }) => setEmailValueRaw(e.target.value)} size="small" - type="email" + type="text" value={emailValueRaw} sx={{ mb: 2 }} variant="outlined" @@ -122,9 +126,20 @@ export const SqlInjectionLogin = () => { sx={{ display: "flex", flexDirection: "row", - justifyContent: "end", + justifyContent: "space-between", }} > + { + setSecured(e.target.checked); + }} + /> + } + label="Use secure endpoint" + /> { // contexts @@ -25,6 +25,7 @@ export const SqlInjectionRegister = () => { ); const [passwordStrengthInfo, setPasswordStrengthInfo] = useState("Enter a password"); const [registerLoading, setRegisterLoading] = useState(false); + const [secured, setSecured] = useState(false); let newPasswordStrengthInfo = "Enter a password"; @@ -105,9 +106,12 @@ export const SqlInjectionRegister = () => { // start loading indicator setRegisterLoading(true); + // construct endpoint url + const endpointUrl = serverUrl + (secured ? "/secure-register-sql" : "/unsecure-register-sql"); + try { // make request good - const response = await fetch(serverUrl + "/secure-register-sql", { + const response = await fetch(endpointUrl, { method: "POST", headers: { "Content-Type": "application/json", @@ -171,7 +175,7 @@ export const SqlInjectionRegister = () => { label="Email" onChange={(e: { target: { value: string } }) => setEmailValueRaw(e.target.value)} size="small" - type="email" + type="text" value={emailValueRaw} sx={{ mb: 2 }} variant="outlined" @@ -237,9 +241,20 @@ export const SqlInjectionRegister = () => { sx={{ display: "flex", flexDirection: "row", - justifyContent: "end", + justifyContent: "space-between", }} > + { + setSecured(e.target.checked); + }} + /> + } + label="Use secure endpoint" + /> ("disconnected"); // store the url of the backend server -export const serverUrlAtom = atom(""); +// TODO: let user enter their own backend server url +export const serverUrlAtom = atom("http://localhost:5000"); diff --git a/server/internal/db/db.go b/server/internal/db/db.go index 88d1369..7847787 100644 --- a/server/internal/db/db.go +++ b/server/internal/db/db.go @@ -8,6 +8,7 @@ import ( "net/http" "github.com/jackc/pgx/v5/pgxpool" + "golang.org/x/crypto/bcrypt" ) // db connection info @@ -75,6 +76,17 @@ func DbHealthCheck(w http.ResponseWriter, r *http.Request) { // setup demo db func SetupDemoDb(w http.ResponseWriter, r *http.Request) { + // default password for demo users + defaultPassword := "Password!23" + + // Hash the default password + hashedPassword, err := bcrypt.GenerateFromPassword([]byte(defaultPassword), bcrypt.DefaultCost) + if err != nil { + http.Error(w, "Error hashing password", http.StatusInternalServerError) + log.Printf("Error hashing password: %v", err) + return + } + // create table and insert demo data createTableSQL := ` CREATE TABLE IF NOT EXISTS users ( @@ -87,13 +99,13 @@ func SetupDemoDb(w http.ResponseWriter, r *http.Request) { // avoid duplicate entries and specify roles insertDataSQL := ` INSERT INTO users (email, password, role) VALUES - ('alice@example.com', 'asdfalicepassword', 'user'), - ('bob@example.com', 'asdfbobpassword', 'user'), - ('charlie@example.com', 'asdfcharliepassword', 'admin') + ('alice@example.com', $1, 'user'), + ('bob@example.com', $2, 'user'), + ('charlie@example.com', $3, 'admin') ` // execute create table - _, err := DbPool.Exec(context.Background(), createTableSQL) + _, err = DbPool.Exec(context.Background(), createTableSQL) if err != nil { http.Error(w, "Failed to create table", http.StatusInternalServerError) log.Printf("Error creating table: %v", err) @@ -101,7 +113,7 @@ func SetupDemoDb(w http.ResponseWriter, r *http.Request) { } // execute insert demo data - _, err = DbPool.Exec(context.Background(), insertDataSQL) + _, err = DbPool.Exec(context.Background(), insertDataSQL, hashedPassword, hashedPassword, hashedPassword) if err != nil { http.Error(w, "Failed to insert demo data", http.StatusInternalServerError) log.Printf("Error inserting demo data: %v", err) diff --git a/server/internal/http_server/http_server.go b/server/internal/http_server/http_server.go index 3772679..ba22a59 100644 --- a/server/internal/http_server/http_server.go +++ b/server/internal/http_server/http_server.go @@ -21,8 +21,11 @@ func ServeApi() { http.HandleFunc("/setup-demo-db", db.SetupDemoDb) http.HandleFunc("/nuke-db", db.NukeDb) http.HandleFunc("/fetch-all-users", db.FetchAllUsers) + http.HandleFunc("/unsecure-register-sql", sql_injection.UnsecureRegisterSql) http.HandleFunc("/secure-register-sql", sql_injection.SecureRegisterSql) + http.HandleFunc("/unsecure-login-sql", sql_injection.UnsecureLoginSql) http.HandleFunc("/secure-login-sql", sql_injection.SecureLoginSql) + log.Println("Server is running on http://localhost:5000") if err := http.ListenAndServe(":5000", nil); err != nil { log.Fatalf("Failed to start server: %v", err) diff --git a/server/internal/sql_injection/sql_injection.go b/server/internal/sql_injection/sql_injection.go index 273ce6d..892151d 100644 --- a/server/internal/sql_injection/sql_injection.go +++ b/server/internal/sql_injection/sql_injection.go @@ -59,6 +59,7 @@ func UnsecureRegisterSql(w http.ResponseWriter, r *http.Request) { // 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