In web development, a database needs to be used to store user data, media items, comments, etc. There are several different types databases you could use, and although I will not cover them in this article here are a few:
Relational Databases (SQL)
- MySQL
- PostgreSQL
- SQLite
- SQL Server
- Oracle Database
- Sybase
Key-Value (NoSQL)
- Redis
- BerkleyDB
- memcached
Document Oriented (NoSQL)
- MongoDB
- CouchDB
My database of choice when writing a web server from scratch in Go, is MongoDB. For the example below I use mgo which is the Go driver for the MongoDB database, using BSON file format to store/retrieve entries. It is extremely easy to use and I highly recommend it.
I chose MongoDB because it is usually more secure than an SQL database, at least against SQL-injections by not being an SQL database. On the other hand there are many possible attacks that can be done against the database (though usually less severe than an SQL-injection), and I suggest doing a fair amount of research before implementation[1][2].
Using mgo
To use mgo, the first step is including the libraries. In this example I use the BSON file format and require the package conversions like so:
There are then three functions:
- Dial: session, err := mgo.Dial(url_of_database) – Establishes one or more connections with the server(s).
- Session: c := session.DB(database_name).C(collection_name) – Opens a new session in the database/collection.
- Find: err := c.Find(query).one(&result) – Searches for “query” in database/collection and returns what it has found to result. Result will not be filled if nothing is found and error will be thrown.
Example of Database Accesses
In the following example, I create a simple database to store information about a book. There are many security features I am overlooking in this article for simplicity, however there will be a more advanced post later regarding security. If you are interested I recommend securing the database using features such as, creating a database login, authenticating, auditing, and more.
The first thing to do is creating a new entry, i.e. adding a new book to the database. To do this we use a function similar to the following:
If we already have a book in the database, using a function such as “find book” would be useful:
To then use the above functions we would need to place them in a package. In this case, I chose to name the package “bkz,” and the book will be added to a users selection of books by adding them on the “/add-book” page of the website. I have previously discussed how cookies, page handling and user input is handled in Go, all of which you will see in the following function when adding a book:
As you can see above, the user.UpdateCollection(username, book) updates the collection of the “username” calling the UpdateCollection function from the user package. Adding the bookID to the users collection enables the user to both view (and in the working server download) the book. If the user does not exist, the UpdateCollection function returns an error. However, this should never occur because the function user.DoesAccountExist(username) should return false and force the default webpage to return to the login page without the proper cookie (not allowing random people to add book entries).
A case in which bkz.Find would be useful would be while loading the users books on a sidebar, using code similar to the following:
In the example above we simply iterate through a list of books the user has (a maximum of five books are listed). We then simply add links to the various info pages or a link to the “add-book” page.
If you are interested in tinkering with the code above, please feel free to visit my github.
If you stick to prepared statements / bind parameters, there’s absolutely no risk of SQL-injections in your database. It’s also significantly faster, because statements are only compiled once rather than on every execution. There’s no reason not to use them. Injection vulnerabilities are only a result of amateur developers severely misusing their database API with string concatenation.
Your example is vulnerable to a persistent cross site scripting attack. Since there is no input validation in the bookHandler and no output sanitization in the last snippet, an attacker can insert books with for example a script in the title and then use that to take control of the session when the book title is rendered.
I know it blurs examples to include that nasty security stuff, but the state of web app security in general is pretty bad. I think the world needs good examples that show how to prevent these basic attacks.
I considered that and you are probably right… However, there were quite a few other attacks that can happen and rather than trying to stick them all in here I will write a whole article on security.
It’s pretty much a catch-22 I can either make it very clear for beginners and run the risk of them implementing vulnerable code, or I write less vulnerable code and scare off new comers.
You’re adding the book to the users collection regardless of succeeded CreateBook or failed.
Indeed, I just went ahead and fixed it. Thank you for pointing that out.