login and registration unsecured

This commit is contained in:
Vomitblood 2025-01-14 03:50:45 +08:00
parent 53c0ada12e
commit ffbdd9d427
11 changed files with 71 additions and 22 deletions

View file

@ -41,7 +41,9 @@ PGPASSWORD=asdfpassword
### SQL Injection ### SQL Injection
- `/unsecure-register-sql`
- `/secure-register-sql` - `/secure-register-sql`
- `/unsecure-login-sql`
- `/secure-login-sql` - `/secure-login-sql`
#### 1. Parameterization of Queries #### 1. Parameterization of Queries

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View file

@ -17,7 +17,7 @@ export const HeaderLogo: FC<HeaderLogoProps> = ({ sx }) => {
alt="Logo" alt="Logo"
height={40} height={40}
priority priority
src="images/logo.gif" src="images/logo.webp"
width={40} width={40}
/> />
<Typography <Typography

View file

@ -9,9 +9,9 @@ export const ServerUrlInput = () => {
return ( return (
<TextField <TextField
fullWidth fullWidth
label='Backend server URL' label="Backend server URL"
onChange={(event) => setServerUrl(event.target.value)} // onChange={(event) => setServerUrl(event.target.value)}
size='small' size="small"
value={serverUrl} value={serverUrl}
/> />
); );

View file

@ -30,12 +30,12 @@ export const Home = () => {
CSPJ Application Attack Simulator CSPJ Application Attack Simulator
</Typography> </Typography>
</Box> </Box>
<Button {/* <Button
href="https://github.com/cspj-nyp/cspj-application" href="https://github.com/cspj-nyp/cspj-application"
sx={{ mb: 2 }} sx={{ mb: 2 }}
> >
Need help getting started? Need help getting started?
</Button> </Button> */}
</Box> </Box>
<Grid2 <Grid2
container container

View file

@ -1,10 +1,11 @@
import { Box, TextField, Typography } from "@mui/material"; import { LoadingButton } from "@mui/lab";
import { Box, FormControlLabel, Switch, TextField, Typography } from "@mui/material";
import { fetch } from "@tauri-apps/plugin-http";
import { useAtom } from "jotai"; import { useAtom } from "jotai";
import { useState } from "react"; import { useState } from "react";
import { useNotification } from "../../../contexts/NotificationContext"; import { useNotification } from "../../../contexts/NotificationContext";
import { serverUrlAtom } from "../../../lib/jotai"; import { serverUrlAtom } from "../../../lib/jotai";
import { HeaderLogo } from "../../Generic/HeaderLogo"; import { HeaderLogo } from "../../Generic/HeaderLogo";
import { LoadingButton } from "@mui/lab";
export const SqlInjectionLogin = () => { export const SqlInjectionLogin = () => {
// contexts // contexts
@ -18,6 +19,7 @@ export const SqlInjectionLogin = () => {
const [passwordValueRaw, setPasswordValueRaw] = useState<string>(""); const [passwordValueRaw, setPasswordValueRaw] = useState<string>("");
const [errorMsg, setErrorMsg] = useState<string>(""); const [errorMsg, setErrorMsg] = useState<string>("");
const [loginLoading, setLoginLoading] = useState<boolean>(false); const [loginLoading, setLoginLoading] = useState<boolean>(false);
const [secured, setSecured] = useState<boolean>(false);
const nextClickEvent = async () => { const nextClickEvent = async () => {
// reset the error messages // reset the error messages
@ -35,9 +37,11 @@ export const SqlInjectionLogin = () => {
// start loading indicator // start loading indicator
setLoginLoading(true); setLoginLoading(true);
const endpointUrl = serverUrl + (secured ? "/secure-login-sql" : "/unsecure-login-sql");
try { try {
// make request good // make request good
const response = await fetch(serverUrl + "/register-sql", { const response = await fetch(endpointUrl, {
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
@ -100,7 +104,7 @@ export const SqlInjectionLogin = () => {
label="Email" label="Email"
onChange={(e: { target: { value: string } }) => setEmailValueRaw(e.target.value)} onChange={(e: { target: { value: string } }) => setEmailValueRaw(e.target.value)}
size="small" size="small"
type="email" type="text"
value={emailValueRaw} value={emailValueRaw}
sx={{ mb: 2 }} sx={{ mb: 2 }}
variant="outlined" variant="outlined"
@ -122,9 +126,20 @@ export const SqlInjectionLogin = () => {
sx={{ sx={{
display: "flex", display: "flex",
flexDirection: "row", flexDirection: "row",
justifyContent: "end", justifyContent: "space-between",
}} }}
> >
<FormControlLabel
control={
<Switch
checked={secured}
onChange={(e) => {
setSecured(e.target.checked);
}}
/>
}
label="Use secure endpoint"
/>
<LoadingButton <LoadingButton
loading={loginLoading} loading={loginLoading}
type="submit" type="submit"

View file

@ -1,11 +1,11 @@
import { LoadingButton } from "@mui/lab"; import { LoadingButton } from "@mui/lab";
import { Box, LinearProgress, TextField, Typography } from "@mui/material"; import { Box, FormControlLabel, LinearProgress, Switch, TextField, Typography } from "@mui/material";
import { fetch } from "@tauri-apps/plugin-http"; import { fetch } from "@tauri-apps/plugin-http";
import { useAtom } from "jotai"; import { useAtom } from "jotai";
import { useState } from "react"; import { useState } from "react";
import { useNotification } from "../../../contexts/NotificationContext";
import { serverUrlAtom } from "../../../lib/jotai"; import { serverUrlAtom } from "../../../lib/jotai";
import { HeaderLogo } from "../../Generic/HeaderLogo"; import { HeaderLogo } from "../../Generic/HeaderLogo";
import { useNotification } from "../../../contexts/NotificationContext";
export const SqlInjectionRegister = () => { export const SqlInjectionRegister = () => {
// contexts // contexts
@ -25,6 +25,7 @@ export const SqlInjectionRegister = () => {
); );
const [passwordStrengthInfo, setPasswordStrengthInfo] = useState("Enter a password"); const [passwordStrengthInfo, setPasswordStrengthInfo] = useState("Enter a password");
const [registerLoading, setRegisterLoading] = useState<boolean>(false); const [registerLoading, setRegisterLoading] = useState<boolean>(false);
const [secured, setSecured] = useState<boolean>(false);
let newPasswordStrengthInfo = "Enter a password"; let newPasswordStrengthInfo = "Enter a password";
@ -105,9 +106,12 @@ export const SqlInjectionRegister = () => {
// start loading indicator // start loading indicator
setRegisterLoading(true); setRegisterLoading(true);
// construct endpoint url
const endpointUrl = serverUrl + (secured ? "/secure-register-sql" : "/unsecure-register-sql");
try { try {
// make request good // make request good
const response = await fetch(serverUrl + "/secure-register-sql", { const response = await fetch(endpointUrl, {
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
@ -171,7 +175,7 @@ export const SqlInjectionRegister = () => {
label="Email" label="Email"
onChange={(e: { target: { value: string } }) => setEmailValueRaw(e.target.value)} onChange={(e: { target: { value: string } }) => setEmailValueRaw(e.target.value)}
size="small" size="small"
type="email" type="text"
value={emailValueRaw} value={emailValueRaw}
sx={{ mb: 2 }} sx={{ mb: 2 }}
variant="outlined" variant="outlined"
@ -237,9 +241,20 @@ export const SqlInjectionRegister = () => {
sx={{ sx={{
display: "flex", display: "flex",
flexDirection: "row", flexDirection: "row",
justifyContent: "end", justifyContent: "space-between",
}} }}
> >
<FormControlLabel
control={
<Switch
checked={secured}
onChange={(e) => {
setSecured(e.target.checked);
}}
/>
}
label="Use secure endpoint"
/>
<LoadingButton <LoadingButton
loading={registerLoading} loading={registerLoading}
type="submit" type="submit"

View file

@ -13,4 +13,5 @@ type ServerConnection = "connected" | "connecting" | "disconnected";
export const serverConnectionAtom = atom<ServerConnection>("disconnected"); export const serverConnectionAtom = atom<ServerConnection>("disconnected");
// store the url of the backend server // 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");

View file

@ -8,6 +8,7 @@ import (
"net/http" "net/http"
"github.com/jackc/pgx/v5/pgxpool" "github.com/jackc/pgx/v5/pgxpool"
"golang.org/x/crypto/bcrypt"
) )
// db connection info // db connection info
@ -75,6 +76,17 @@ func DbHealthCheck(w http.ResponseWriter, r *http.Request) {
// setup demo db // setup demo db
func SetupDemoDb(w http.ResponseWriter, r *http.Request) { 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 // create table and insert demo data
createTableSQL := ` createTableSQL := `
CREATE TABLE IF NOT EXISTS users ( CREATE TABLE IF NOT EXISTS users (
@ -87,13 +99,13 @@ func SetupDemoDb(w http.ResponseWriter, r *http.Request) {
// avoid duplicate entries and specify roles // avoid duplicate entries and specify roles
insertDataSQL := ` insertDataSQL := `
INSERT INTO users (email, password, role) VALUES INSERT INTO users (email, password, role) VALUES
('alice@example.com', 'asdfalicepassword', 'user'), ('alice@example.com', $1, 'user'),
('bob@example.com', 'asdfbobpassword', 'user'), ('bob@example.com', $2, 'user'),
('charlie@example.com', 'asdfcharliepassword', 'admin') ('charlie@example.com', $3, 'admin')
` `
// execute create table // execute create table
_, err := DbPool.Exec(context.Background(), createTableSQL) _, err = DbPool.Exec(context.Background(), createTableSQL)
if err != nil { if err != nil {
http.Error(w, "Failed to create table", http.StatusInternalServerError) http.Error(w, "Failed to create table", http.StatusInternalServerError)
log.Printf("Error creating table: %v", err) log.Printf("Error creating table: %v", err)
@ -101,7 +113,7 @@ func SetupDemoDb(w http.ResponseWriter, r *http.Request) {
} }
// execute insert demo data // execute insert demo data
_, err = DbPool.Exec(context.Background(), insertDataSQL) _, err = DbPool.Exec(context.Background(), insertDataSQL, hashedPassword, hashedPassword, hashedPassword)
if err != nil { if err != nil {
http.Error(w, "Failed to insert demo data", http.StatusInternalServerError) http.Error(w, "Failed to insert demo data", http.StatusInternalServerError)
log.Printf("Error inserting demo data: %v", err) log.Printf("Error inserting demo data: %v", err)

View file

@ -21,8 +21,11 @@ func ServeApi() {
http.HandleFunc("/setup-demo-db", db.SetupDemoDb) http.HandleFunc("/setup-demo-db", db.SetupDemoDb)
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("/unsecure-register-sql", sql_injection.UnsecureRegisterSql)
http.HandleFunc("/secure-register-sql", sql_injection.SecureRegisterSql) http.HandleFunc("/secure-register-sql", sql_injection.SecureRegisterSql)
http.HandleFunc("/unsecure-login-sql", sql_injection.UnsecureLoginSql)
http.HandleFunc("/secure-login-sql", sql_injection.SecureLoginSql) http.HandleFunc("/secure-login-sql", sql_injection.SecureLoginSql)
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 {
log.Fatalf("Failed to start server: %v", err) log.Fatalf("Failed to start server: %v", err)

View file

@ -59,6 +59,7 @@ func UnsecureRegisterSql(w http.ResponseWriter, r *http.Request) {
// hash the password // hash the password
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(credentials.Password), bcrypt.DefaultCost) hashedPassword, err := bcrypt.GenerateFromPassword([]byte(credentials.Password), bcrypt.DefaultCost)
fmt.Println(hashedPassword)
if err != nil { if err != nil {
http.Error(w, "Error hashing password", http.StatusInternalServerError) http.Error(w, "Error hashing password", http.StatusInternalServerError)
return return