Skip to content

Commit 3782835

Browse files
committed
feat: Additional routes with SQLi vulns
1 parent 9861e16 commit 3782835

File tree

3 files changed

+123
-19
lines changed

3 files changed

+123
-19
lines changed

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ module github.com/octodemo/advanced-security-go
22

33
go 1.17
44

5-
require github.com/mattn/go-sqlite3 v1.14.8 // indirect
5+
require github.com/mattn/go-sqlite3 v1.14.8

main.go

+48-11
Original file line numberDiff line numberDiff line change
@@ -48,20 +48,57 @@ func main() {
4848
log.Fatal(err)
4949
}
5050

51-
http.HandleFunc("/books", booksIndex)
51+
http.HandleFunc("/books", handler)
5252
http.ListenAndServe(":3000", nil)
5353
}
5454

55-
// booksIndex sends a HTTP response listing all books.
56-
func booksIndex(w http.ResponseWriter, r *http.Request) {
57-
bks, err := models.AllBooks()
58-
if err != nil {
59-
log.Println(err)
60-
http.Error(w, http.StatusText(500), 500)
61-
return
62-
}
55+
func handler(w http.ResponseWriter, r *http.Request) {
56+
name := r.URL.Query().Get("name")
57+
author := r.URL.Query().Get("author")
58+
read := r.URL.Query().Get("read")
59+
60+
if len(name) > 0 {
61+
bks, err := models.NameQuery(name)
62+
if err != nil {
63+
http.Error(w, http.StatusText(500), 500)
64+
return
65+
}
66+
67+
for _, bk := range bks {
68+
fmt.Fprintf(w, "%s, %s, %s\n", bk.Title, bk.Author, bk.Read)
69+
}
70+
71+
} else if len(author) > 0 {
72+
bks, err := models.AuthorQuery(author)
73+
if err != nil {
74+
http.Error(w, http.StatusText(500), 500)
75+
return
76+
}
77+
78+
for _, bk := range bks {
79+
fmt.Fprintf(w, "%s, %s, %s\n", bk.Title, bk.Author, bk.Read)
80+
}
81+
82+
} else if len(read) > 0 {
83+
bks, err := models.ReadQuery(read)
84+
if err != nil {
85+
http.Error(w, http.StatusText(500), 500)
86+
return
87+
}
88+
89+
for _, bk := range bks {
90+
fmt.Fprintf(w, "%s, %s, %s\n", bk.Title, bk.Author, bk.Read)
91+
}
92+
93+
} else {
94+
bks, err := models.AllBooks()
95+
if err != nil {
96+
http.Error(w, http.StatusText(500), 500)
97+
return
98+
}
6399

64-
for _, bk := range bks {
65-
fmt.Fprintf(w, "%s, %s, %s\n", bk.Title, bk.Author, bk.Read)
100+
for _, bk := range bks {
101+
fmt.Fprintf(w, "%s, %s, %s\n", bk.Title, bk.Author, bk.Read)
102+
}
66103
}
67104
}

models/models.go

+74-7
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ package models
22

33
import (
44
"database/sql"
5+
"fmt"
56
)
67

7-
// Create an exported global variable to hold the database connection pool.
88
var DB *sql.DB
99

1010
type Book struct {
@@ -13,28 +13,95 @@ type Book struct {
1313
Read string
1414
}
1515

16-
// AllBooks returns a slice of all books in the books table.
16+
// Get all books in the books table.
1717
func AllBooks() ([]Book, error) {
18-
// Note that we are calling Query() on the global variable.
19-
rows, err := DB.Query("SELECT * FROM books")
18+
query := "SELECT * FROM books"
19+
rows, err := DB.Query(query)
2020
if err != nil {
2121
return nil, err
2222
}
2323
defer rows.Close()
2424

25+
bks, err := makeBookSlice(rows)
26+
if err != nil {
27+
return nil, err
28+
}
29+
30+
return bks, nil
31+
}
32+
33+
// Query for books by name. This function contains a SQL Injection issue.
34+
// The user input is not parameterized. Instead of using fmt.Sprintf() to build
35+
// the query, you should be using a parameterized query.
36+
func NameQuery(r string) ([]Book, error) {
37+
// Fix: rows, err := db.Query("SELECT * FROM books WHERE name = ?", r)
38+
rows, err := DB.Query(fmt.Sprintf("SELECT * FROM books WHERE name = '%s'", r))
39+
if err != nil {
40+
return nil, err
41+
}
42+
defer rows.Close()
43+
44+
bks, err := makeBookSlice(rows)
45+
if err != nil {
46+
return nil, err
47+
}
48+
49+
return bks, nil
50+
}
51+
52+
// Query for books by Author. This function contains a SQL Injection issue.
53+
// The user input is not parameterized. Instead of using fmt.Sprintf() to build
54+
// the query, you should be using a parameterized query.
55+
func AuthorQuery(r string) ([]Book, error) {
56+
// Fix: rows, err := db.Query("SELECT * FROM books WHERE author = ?", r)
57+
rows, err := DB.Query(fmt.Sprintf("SELECT * FROM books WHERE author = '%s'", r))
58+
if err != nil {
59+
return nil, err
60+
}
61+
defer rows.Close()
62+
63+
bks, err := makeBookSlice(rows)
64+
if err != nil {
65+
return nil, err
66+
}
67+
68+
return bks, nil
69+
}
70+
71+
// Query for books by read. This function contains a SQL Injection issue.
72+
// The user input is not parameterized. Instead of using fmt.Sprintf() to build
73+
// the query, you should be using a parameterized query.
74+
func ReadQuery(r string) ([]Book, error) {
75+
// Fix: rows, err := db.Query("SELECT * FROM books WHERE read = ?", r)
76+
rows, err := DB.Query(fmt.Sprintf("SELECT * FROM books WHERE read = '%s'", r))
77+
if err != nil {
78+
return nil, err
79+
}
80+
defer rows.Close()
81+
82+
bks, err := makeBookSlice(rows)
83+
if err != nil {
84+
return nil, err
85+
}
86+
87+
return bks, nil
88+
}
89+
90+
// A helper function to cast the query results to a slice
91+
func makeBookSlice(r *sql.Rows) ([]Book, error) {
2592
var bks []Book
2693

27-
for rows.Next() {
94+
for r.Next() {
2895
var bk Book
2996

30-
err := rows.Scan(&bk.Title, &bk.Author, &bk.Read)
97+
err := r.Scan(&bk.Title, &bk.Author, &bk.Read)
3198
if err != nil {
3299
return nil, err
33100
}
34101

35102
bks = append(bks, bk)
36103
}
37-
if err = rows.Err(); err != nil {
104+
if err := r.Err(); err != nil {
38105
return nil, err
39106
}
40107

0 commit comments

Comments
 (0)