DoS Attack Demo and Prevention in Go

DoS Attack Demo and Prevention in Go

Demonstrates and provides solution to following DoS (Denial of Service) attacks in Go:

  • Slowloris
  • Large file

The solutions are trivially simple to implement in Go often consisting of a simple configuration directive or making use of a standard library function.

Slowloris

Send requests to the server extremely slow. The notable thing about this DoS is it takes very little resource in terms of memory or CPU. The goal is to send a large number of requests that all send extremely slow requests – thus making the server use all its connection while waiting on the requests to complete.

Solution: specify a read timeout. For example, on the standard Go web server, you can configure as follows with the directive “ReadTimeout: 1 * time.Second”:

srv := &http.Server{
    Addr:        ":3000",
    Handler:     mux,
    ReadTimeout: 1 * time.Second,
    //WriteTimeout: 10 * time.Second,
    //IdleTimeout:  1 * time.Minute,
}

Large File

Send very large requests to server. The goal is to overwhelm the server as it tries to process the large requests often gigabytes in size. In contrast to Slowloris, this type of attack requires more memory and CPU to send large files from the client.

Solution: use LimitReader to limit the number of bytes to read from the request. For example, here we specify a 100K limit to the reader:

io.LimitReader(r.Body, 100_000)

Source Code

The full source code and how to run the demos can be found here:

https://github.com/sanjib/go-dos

Golang SQL Injection in MariaDB / MySQL

Golang SQL Injection in MariaDB / MySQL

Here is a hand-on demonstration of an SQL injection attack in Go using MariaDB / MySQL with driver multiStatements parameter set to true. By default this is set to false, so if you are testing make sure it’s set to true. After testing the SQL injection, the demonstration continues by using SQL statement parameters – which mitigates any possible SQL injection.

Example SQL injection (include space after — below) code:

'); truncate messages; -- 

Get the code from the repository: https://github.com/sanjib/go-sql-injection-demo

There are 3 relevant files:

  • main.go
  • home.tmpl
  • db.sql

Simply run the main.go file using “go run .” in the current folder where the files are placed. The home.tmpl is a template file which is used in the code. The db.sql contains the schema for you to create the table.

You should also change the openDB() function where the DSN (data source name) to include your username, password and database name to your own MariaDB / MySQL database. For example, I have used:

db, err = sql.Open("mysql", "root@/va_test1?parseTime=true&multiStatements=true")

Replace, “root” with your username and “va_test1” with your database name. If you have a password, use it after the username preceded with a colon. For example:

db, err = sql.Open("mysql", "your_username:your_password@/your_database_name?parseTime=true&multiStatements=true")

A 2-line Go Server for Local Web Development

Use case: JavaScript service worker development with multiple tabs/clients where you don’t want automatic browser reloads or posts.

Local dev servers with automatic browser reloads or posts can be problematic when developing service workers with multiple clients. For example, you want to test a scenario by posting messages on one client (single browser tab) and broadcasting to the same or all clients (multiple open tabs). With automatic browser reloads the post might happen on all clients (all browser tabs) and debugging can be elusive. You might have the same URL open in 2 different tabs and a post on one tab might trigger the post on the other tab as well with some automatic reload dev servers.

The solution is to use a server that doesn’t do automatic reloads or posts. Instead of installing one, you can just write your own.

Here is a trivial 2-line Go server that you can use to serve your static HTML, CSS and JavaScript files locally. Though it looks more than 2 lines, it’s essence are these 2 functions: http.Handle for pattern “/” for current folder to be used as a file server and running the server with http.ListenAndServe on port 3000.

package main

import (
	"fmt"
	"log"
	"net/http"
)

func main() {
	fs := http.FileServer(http.Dir("."))
	http.Handle("/", http.StripPrefix("/", fs))
	fmt.Println("running server on port 3000...")
	log.Fatal(http.ListenAndServe(":3000", nil))
}

If you are on Windows, you can download the executable file and run it on the root level directory of your source code. For example:

Files:

EditPlus Setup for Go

EditPlus Setup for Go

This article shows how to setup EditPlus for editing Go files.

  1. Syntax highlighting
  2. Build and run Go files

EditPlus is a small program for editing files; it’s fast and doesn’t use much memory. I use it for writing experimental programs and tests in Go.

Program: EditPlus
Operating System: Windows 10

Syntax Highlighting

Download the Go “stx” file go2.zip from this page: https://www.editplus.com/others.html. If you search for “Google” on that page, you should be able to find the following line:

Google’s Go programming language stx – sethborg (2011-01-17)

There is another older version: Google’s “Go” stx – Nate Eriksmoen (2009-11-14)

Extract the go2.zip file and move the go.stx file to your EditPlus “user settings” directory. Your “user settings” directory should be something like:

C:\Users\your-name\AppData\Roaming\EditPlus

Then go to “Tools” -> “Preferences” -> “File: Settings & Syntax”. Add an entry for Go with the following settings:

File extensions: go
Syntax file: go.stx

Your Go code should now have syntax highlighting enabled as can be seen below (before/after):

Build and Run Go Files

In EditPlus, click “Tools” -> “Configure User Tools”. Click “Add Tools” with the following settings:

Menu text: go run
Command: C:\Program Files\Go\bin\go.exe
Argument: run $(FileName)
Initial: $(FileDir)
Action: Capture output

Now you can use the “Tools” -> “go run” command to build and run your Go files from EditPlus.

My shortcut is set to “Ctrl+1”. So, now every time I hit “Ctrl+1”, I can see the output of the Go program within the EditPlus output window as shown below:

One final setting you may like is to turn off the “Ding” sound after each time the Go program runs. To do that, go to “Tools” -> “Preferences” -> “General”, then click “Turn off sounds”:

Download a File Using Go

Downloading a file from the Internet using Go is remarkably easy. Especially coupled with concurrency it makes downloading multiple files fast. The following code below shows how to download a single file using Go.

Goal: Download a test image file, the Google logo
https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png

  1. First get the file using http.Get
  2. Extract the filename from the URL by splitting it with “/”, then get the last part
  3. Create an empty file with the filename
  4. Dump the data into the file from the “res” object in step 1
package main

import (
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"strings"
)

func main() {
	// 1. Get the file
	url := "https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png"
	res, err := http.Get(url)
	if err != nil {
		log.Println(err)
		return
	}

	// 2. Extract filename
	parts := strings.Split(url, "/")
	filename := parts[len(parts)-1]

	// 3. Create an empty file
	file, err := os.Create(filename)
	if err != nil {
		log.Println(err)
		return
	}

	// 4. Dump the data
	defer res.Body.Close()
	n, err := io.Copy(file, res.Body)
	if err != nil {
		log.Println(err)
		return
	}

	fmt.Printf("wrote: %q, size: %.2f kb\n", filename, float64(n)/1024)
}

Send Email With Go and MailJet

The following steps show how to send mail with Go using the standard smtp package. To test I used MailJet as the mail server but you can also use Mandrill or SendGrid.

First let’s setup MailJet as the mail server. Then write the Go code and send a test email.

MailJet Setup

After creating your free MailJet account, you should make sure you complete the 2 steps below (under Account Settings):

  • Add a Sender Domain or Address
  • Setup SPF/DKIM Authentication

Personally, I found validating an entire domain very convenient. That way I can use the domain for all my projects mail sending requirements. For example:

project-1@mydomain.com
project-2@mydomain.com

project-n@mydomain.com

But you don’t have to use a custom domain if you don’t want to. You can add a single sender email address from which the mail will be sent from.

Next, you need to setup an API key and Secret – these will be the username and password in Go code. You can set the API key and Secret under Account Settings:

Go Code

Please make sure you specify the following constants and variables with your own:

  • username, password: These are your API key and secret
  • host, port: the port should be 587, you can find your host under your account settings:
  • from: the email address from which mail will be sent from. I presume you have set this in the steps above under MailJet account settings: Add a Sender Domain or Address, Setup SPF/DKIM Authentication.
  • to: you can specify any address that you own for testing. The test email will be sent to this address. I specified my own personal email address which you should replace with your own.

Type the following code in your favorite editor, then run the code in a terminal: go run main.go

package main

import (
	"fmt"
	"log"
	"net/smtp"
	"time"
)

func main() {
	const (
		username = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" // your 32 digit API key
		password = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" // your 32 digit secret
		host     = "XXX.mailjet.com"                  // your MailJet host
		port     = "587"                              // recommended port for TLS
		from     = "FROM-EMAIL@YOUR-VALID-DOMAIN.COM" // your validated domain
		addr     = host + ":" + port
	)

	to := []string{
		"TO-RECIPIENT-EMAIL@DOMAIN.COM",
	}
	subject := "Test mail using Go with MailJet"
	message := fmt.Sprintf(`Subject:%s
Hi,

This is a test message sent with Go and MailJet.

Thanks!

Sent on %v`, subject, time.Now())

	auth := smtp.PlainAuth("", username, password, host)
	err := smtp.SendMail(addr, auth, from, to, []byte(message))
	if err != nil {
		log.Println("send mail:", err)
		return
	}
	fmt.Println("mail sent successfully")
}

If you configured everything correctly and ran the code, you should receive an email like the one shown in the screenshot below. I received my test email at my personal Gmail address. My from address was: “test-project@dovetail.one”

Here is a video of the code in action where I configure the code, run it and receive a test mail.