diff --git a/server/build.sh b/server/build.sh new file mode 100755 index 0000000..9d230dd --- /dev/null +++ b/server/build.sh @@ -0,0 +1,2 @@ +#!/bin/bash +CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o server main.go \ No newline at end of file diff --git a/server/internal/cli/cli.go b/server/internal/cli/cli.go new file mode 100644 index 0000000..46c631b --- /dev/null +++ b/server/internal/cli/cli.go @@ -0,0 +1,24 @@ +package cli + +import ( + "flag" + "fmt" + "os" + + "github.com/Vomitblood/cspj-application/server/internal/config" +) + +func GetFlags() { + logDir := flag.String("l", "", "Path to the log directory") + + flag.Parse() + + // check if the -l flag is provided + if flag.Lookup("l").Value.String() == "" { + fmt.Println("Error: The -l flag (log directory) is required.") + os.Exit(1) + } + + // store the value in a globally accessible config package + config.LogDirectory = *logDir +} diff --git a/server/internal/config/config.go b/server/internal/config/config.go new file mode 100644 index 0000000..c8e364d --- /dev/null +++ b/server/internal/config/config.go @@ -0,0 +1,3 @@ +package config + +var LogDirectory string diff --git a/server/internal/db/db.go b/server/internal/db/db.go index 2dda951..8f6c42a 100644 --- a/server/internal/db/db.go +++ b/server/internal/db/db.go @@ -87,6 +87,7 @@ func SetupDemoDb(w http.ResponseWriter, r *http.Request) { // avoid duplicate entries and specify roles insertDataSQL := ` INSERT INTO users (email, password, role) VALUES + ('asdf@gmail.com', 'asdf', 'user'), ('alice@example.com', 'asdfalicepassword', 'user'), ('bob@example.com', 'asdfbobpassword', 'user'), ('charlie@example.com', 'asdfcharliepassword', 'admin') @@ -152,7 +153,6 @@ func FetchEmails() (map[string]bool, error) { emails[email] = true } - log.Println("Fetched emails:", emails) return emails, nil } diff --git a/server/internal/log_backup/log_backup.go b/server/internal/log_backup/log_backup.go index 524a062..89be55f 100644 --- a/server/internal/log_backup/log_backup.go +++ b/server/internal/log_backup/log_backup.go @@ -3,16 +3,17 @@ package log_backup import ( "fmt" "log" + "path/filepath" + "github.com/Vomitblood/cspj-application/server/internal/config" "github.com/Vomitblood/cspj-application/server/internal/webdav" "github.com/studio-b12/gowebdav" ) -// TODO: use values from config file var localLogPaths = []string{ - "/home/vomitblood/build/cspj-application/docker/chungus/logs/host-fs-accesslog.log", - "/home/vomitblood/build/cspj-application/docker/chungus/logs/host-fs-auditlog.log", - "/home/vomitblood/build/cspj-application/docker/chungus/logs/host-fs-errorlog.log", + filepath.Join(config.LogDirectory, "host-fs-accesslog.log"), + filepath.Join(config.LogDirectory, "host-fs-auditlog.log"), + filepath.Join(config.LogDirectory, "host-fs-errorlog.log"), } var remoteFiles = []string{ diff --git a/server/internal/log_watcher/log_watcher.go b/server/internal/log_watcher/log_watcher.go index a4910da..fe2eee0 100644 --- a/server/internal/log_watcher/log_watcher.go +++ b/server/internal/log_watcher/log_watcher.go @@ -5,17 +5,14 @@ import ( "encoding/json" "log" "os" + "path/filepath" + "github.com/Vomitblood/cspj-application/server/internal/config" "github.com/Vomitblood/cspj-application/server/internal/telegram" "github.com/fsnotify/fsnotify" tg "github.com/go-telegram-bot-api/telegram-bot-api/v5" ) -const ( - // TODO: add config for user to specify log location - modsecLogFile = "/home/vomitblood/build/cspj-application/docker/chungus/logs/host-fs-auditlog.log" -) - var lastReadPosition int64 = 0 type LogEntry struct { @@ -25,16 +22,18 @@ type LogEntry struct { } func WatchFile(bot *tg.BotAPI) { + modsecLogFile := filepath.Join(config.LogDirectory, "host-fs-auditlog.log") + log.Println("Watching logfile directory:", config.LogDirectory) watcher, err := fsnotify.NewWatcher() if err != nil { - log.Fatal("Failed to initialize watcher:", err) + log.Fatal("Failed to initialize watcher: ", err) } defer watcher.Close() // add log file to watcher err = watcher.Add(modsecLogFile) if err != nil { - log.Fatal("Failed to watch log file:", err) + log.Fatal("Failed to watch log file: ", err) } log.Println("Monitoring log file for changes...") @@ -54,15 +53,16 @@ func WatchFile(bot *tg.BotAPI) { if !ok { return } - log.Println("Watcher error:", err) + log.Println("Watcher error: ", err) } } } func readNewLines(bot *tg.BotAPI) { + modsecLogFile := filepath.Join(config.LogDirectory, "host-fs-auditlog.log") file, err := os.Open(modsecLogFile) if err != nil { - log.Println("Failed to reopen log file:", err) + log.Println("Failed to reopen log file: ", err) return } defer file.Close() @@ -77,7 +77,7 @@ func readNewLines(bot *tg.BotAPI) { // try to parse json if err := json.Unmarshal([]byte(line), &logEntry); err != nil { - log.Println("⚠️ Failed to parse JSON:", err) + log.Println("⚠️ Failed to parse JSON: ", err) // skip invalid json lines // very crucial as modsecurity does not respect the json spec continue @@ -93,6 +93,6 @@ func readNewLines(bot *tg.BotAPI) { lastReadPosition, _ = file.Seek(0, os.SEEK_CUR) if err := scanner.Err(); err != nil { - log.Println("Error reading log file:", err) + log.Println("Error reading log file: ", err) } } diff --git a/server/internal/sql_injection/sql_injection.go b/server/internal/sql_injection/sql_injection.go index b8982d4..8597745 100644 --- a/server/internal/sql_injection/sql_injection.go +++ b/server/internal/sql_injection/sql_injection.go @@ -1,6 +1,7 @@ package sql_injection import ( + "bytes" "context" "encoding/json" "fmt" @@ -134,6 +135,7 @@ func SecureRegisterSql(w http.ResponseWriter, r *http.Request) { } func UnsecureLoginSql(w http.ResponseWriter, r *http.Request) { + log.Println("/unsecure-login-sql hit") // decode the json body var requestData struct { Email string `json:"email"` @@ -175,12 +177,18 @@ func UnsecureLoginSql(w http.ResponseWriter, r *http.Request) { // very secure login endpoint func SecureLoginSql(w http.ResponseWriter, r *http.Request) { - // decode the json body + log.Println("/secure-login-sql hit") var requestData struct { Email string `json:"email"` Password string `json:"password"` } + type AIResponse struct { + Confidence float64 `json:"confidence"` + Query string `json:"query"` + Result string `json:"result"` + } + // declare new json decoder with custom property jsonDecoder := json.NewDecoder(r.Body) // rejects any unknown fields in the json, more strict @@ -214,6 +222,35 @@ func SecureLoginSql(w http.ResponseWriter, r *http.Request) { return } + // make insecure sql command just to send to ai model to check + insecureQuery := fmt.Sprintf("SELECT id, email, password FROM users WHERE email = '%s' AND password = '%s'", requestData.Email, requestData.Password) + + // send the query to the ai model server + aiReqBody, _ := json.Marshal(map[string]string{"query": insecureQuery}) + aiResp, err := http.Post("http://127.0.0.1:5000/predict", "application/json", bytes.NewBuffer(aiReqBody)) + if err != nil { + http.Error(w, "Internal Server Error", http.StatusInternalServerError) + log.Println("Failed to reach AI model:", err) + return + } + defer aiResp.Body.Close() + + var aiResponse AIResponse + if err := json.NewDecoder(aiResp.Body).Decode(&aiResponse); err != nil { + http.Error(w, "Failed to decode AI response", http.StatusInternalServerError) + log.Println("Error decoding AI response:", err) + return + } + + log.Println("AI Response:", aiResponse.Result) + + // reject the original request if ai result is fail + if aiResponse.Result == "fail" { + http.Error(w, "Potential SQL injection detected", http.StatusForbidden) + log.Println("AI detected SQL injection attempt") + return + } + // retrieve the email and password from the database var id int var email string diff --git a/server/main.go b/server/main.go index 3cb7938..46cc087 100644 --- a/server/main.go +++ b/server/main.go @@ -3,6 +3,8 @@ package main import ( "log" + "github.com/Vomitblood/cspj-application/server/internal/cli" + "github.com/Vomitblood/cspj-application/server/internal/config" "github.com/Vomitblood/cspj-application/server/internal/db" "github.com/Vomitblood/cspj-application/server/internal/http_server" "github.com/Vomitblood/cspj-application/server/internal/log_watcher" @@ -11,6 +13,9 @@ import ( ) func main() { + cli.GetFlags() + log.Printf("Log directory set to: %s", config.LogDirectory) + var err error db.DbPool, err = db.ConnectToDb() if err != nil { @@ -27,7 +32,5 @@ func main() { // start log watcher go log_watcher.WatchFile(tgBot) - // - http_server.ServeApi() }