When working with strings that are intended to be displayed as HTML or used in SQL queries, it's essential to escape special characters. This is to ensure that they're rendered correctly in web browsers and to prevent SQL injection attacks, respectively.
Escaping HTML in Go
To escape special characters in strings for HTML rendering, you can use the html/template package in Go. Here’s how you can get started:
Basic Example
package main
import (
"html/template"
"os"
)
func main() {
const tpl = `<p>Hello, {{.}}</p>`
t := template.Must(template.New("escape").Parse(tpl))
t.Execute(os.Stdout, " World & Friends") // Escaped Output: <p>Hello, World & Friends</p>
}
Intermediate Example
When dealing with dynamic content, you can use template's automatic escaping:
package main
import (
"html/template"
"os"
)
type Data struct {
Name string
Message string
}
func main() {
const text = `<h1>Welcome, {{.Name}}!</h1><p>Message: {{.Message}}</p>`
t := template.Must(template.New("dynamic").Parse(text))
data := Data{
Name: "Alice & Bob",
Message: "Hello & Welcome!"
}
t.Execute(os.Stdout, data) // Name and Message will be escaped correctly
}
The automatic escaping feature of html/template ensures that any HTML special characters within {{.Name}} and {{.Message}} are safely escaped.
Escaping SQL in Go
To escape strings for SQL queries, we can use parameterized queries with Go's database/sql package. This is a crucial technique as it helps prevent SQL injection.
Basic Example
package main
import (
"database/sql"
"log"
_ "github.com/go-sql-driver/mysql"
)
func main() {
db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/dbname")
if err != nil {
log.Fatal(err)
}
defer db.Close()
name := "Harvey \" Danger"
result, err := db.Exec("INSERT INTO users (name) VALUES (?)", name)
if err != nil {
log.Fatal(err)
}
id, err := result.LastInsertId()
if err != nil {
log.Fatal(err)
}
log.Printf("Inserted new user with ID %d", id)
}
Intermediate Example
Using prepared statements can enhance performance and safety, especially with repeated query execution:
package main
import (
"database/sql"
"log"
_ "github.com/go-sql-driver/mysql"
)
func main() {
db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/dbname")
if err != nil {
log.Fatal(err)
}
defer db.Close()
stmt, err := db.Prepare("INSERT INTO users (name) VALUES (?)")
if err != nil {
log.Fatal(err)
}
defer stmt.Close()
names := []string{"Alice", "Bob & Charlie", "Dana \" Duncan"}
for _, name := range names {
_, err = stmt.Exec(name)
if err != nil {
log.Fatal(err)
}
}
}
Prepared statements keep you safe from SQL injection attacks by treating the inputs as data rather than executable code.
Advanced Concepts
For more complex scenarios, such as cleaning data that is both part of HTML content and SQL, you may consider implementing a mixed strategy or using a library designed for sanitizing inputs.
As you use these tools and techniques, always remember the nuances required for both HTML and SQL strings to be correctly formatted and secure.