golang安全防护手写SQL注入的插件库Hotcoal的使用
Golang安全防护手写SQL注入的插件库Hotcoal的使用
保护手写SQL免受注入攻击
许多Golang应用不使用ORM,而是更喜欢使用原始SQL进行数据库操作。虽然编写原始SQL有时比使用ORM更灵活、高效和简洁,但它可能使您容易受到SQL注入攻击。
虽然大多数数据库技术(PostgreSQL、MySQL、Sqlite等)和Golang SQL库(database/sql
、sqlx
等)允许您使用预编译语句来接收参数并对其进行清理,但存在一些限制:
- 您可以使用参数作为值,但不能用于列名或表名
- 对于更复杂的操作,一个好的ORM可以动态生成SQL并安全地执行;但您没有使用ORM,所以开始手工编写SQL…
这就是Hotcoal的用武之地。
Hotcoal工作原理
Hotcoal提供了一个最小化的API,帮助您保护手工编写的SQL免受SQL注入攻击。
- 使用Hotcoal而不是纯字符串手工编写SQL。这样所有参数都会根据您提供的允许列表进行验证。
- 将结果转换为纯字符串并与您的SQL库一起使用。
您可以将Hotcoal与任何您喜欢的SQL库一起使用。Hotcoal不替代带有参数的预编译查询,而是对其进行补充。
示例
我们使用以下示例表:
CREATE TABLE "users" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
"first_name" TEXT NOT NULL,
"middle_name" TEXT NOT NULL,
"last_name" TEXT NOT NULL,
"nickname" TEXT,
"email" TEXT NOT NULL
);
验证列名
我们使用Hotcoal验证列名并创建SQL查询字符串。字符串常量可以直接使用Wrap
转换为hotcoalString,无需验证。
但是字符串变量不能直接转换为hotcoalString。这有助于防止SQL注入。相反,您必须使用Allowlist
和Validate
对字符串变量进行验证。如果尝试使用Wrap
将字符串变量转换为hotcoalString而不进行验证,它将无法编译。
import (
"database/sql"
"github.com/motrboat/hotcoal"
)
func queryCount(db *sql.DB, columnName string, value string) *sql.Row {
// 验证columnName变量是否在允许列表中
// 返回一个hotcoalString
validatedColumnName, err := hotcoal.
Allowlist("first_name", "middle_name", "last_name").
Validate(columnName)
if err != nil {
return nil, err
}
// 使用hotcoalStrings手工编写SQL
query := hotcoal.Wrap("SELECT COUNT(*) FROM users WHERE ") +
validatedColumnName +
hotcoal.Wrap(" = ?;")
// 如果尝试使用未经验证的常规字符串变量,
// 它容易受到SQL注入攻击,因此无法编译:
// query := hotcoal.Wrap("SELECT COUNT(*) FROM users WHERE ") +
// columnName +
// hotcoal.Wrap(" = ?;")
// 仅在传递给数据库库时将hotcoalString转换回常规字符串
// 使用带有参数的预编译查询来清理值
row := db.QueryRow(query.String(), value)
return row
}
验证手工编写的SQL
要手工编写更复杂的SQL,您还可以使用strings
函数的hotcoal等效函数Join
、Replace
和ReplaceAll
。这些可以使用hotcoalStrings或字符串常量调用。但不能使用字符串变量-必须先验证这些变量。
import (
"database/sql"
"github.com/motrboat/hotcoal"
)
type Filter struct {
ColumnName string
Value string
}
func queryCount(db *sql.DB, tableName string, filters []Filter) (*sql.Row, error) {
validatedTableName, err := hotcoal.
Allowlist("users", "customers").
Validate(tableName)
if err != nil {
return nil, err
}
allowlist := hotcoal.Allowlist("first_name", "middle_name", "last_name", "nickname")
sqlArr := hotcoal.Slice{}
values := []string{}
for _, filter := range filters {
validatedColumnName, err := allowlist.Validate(filter.ColumnName)
if err != nil {
return nil, err
}
sqlArr = append(sqlArr, validatedColumnName + hotcoal.Wrap(" = ?"))
values = append(values, filter.Value)
}
query := hotcoal.Wrap("SELECT COUNT(*) FROM {{TABLE}} WHERE {{FILTERS}};").
ReplaceAll(
"{{TABLE}}",
validatedTableName,
).
ReplaceAll(
"{{FILTERS}}",
hotcoal.Join(sqlArr, " OR "),
)
row := db.QueryRow(query.String(), values...)
return row
}
字符串构建器
Hotcoal还提供了使用hotcoalStrings
的strings.Builder
版本。它最小化了内存复制,效率更高。
import (
"database/sql"
"github.com/motrboat/hotcoal"
)
type Filter struct {
ColumnName string
Value string
}
func queryCount(db *sql.DB, filters []Filter) *sql.Row {
allowlist := hotcoal.Allowlist("first_name", "middle_name", "last_name", "nickname")
builder := hotcoal.Builder{}
values := []string{}
builder.Write("SELECT COUNT(*) FROM users WHERE ")
for i, filter := range filters {
if i != 0 {
builder.Write(" OR ")
}
validatedColumnName, err := allowlist.Validate(filter.ColumnName)
if err != nil {
return nil, err
}
builder.Write(validatedColumnName + hotcoal.Wrap(" = ?"))
values = append(values, filter.Value)
}
builder.Write(";")
row := db.QueryRow(builder.String(), values...)
return row
}
免责声明
Hotcoal不提供任何保证。
更多关于golang安全防护手写SQL注入的插件库Hotcoal的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang安全防护手写SQL注入的插件库Hotcoal的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang SQL注入防护:Hotcoal库使用指南
Hotcoal是一个轻量级的Golang库,专门用于防止SQL注入攻击。它通过将字符串"烧焦"(hot coal)来安全地处理SQL查询中的参数,确保用户输入不会被解释为SQL代码。
Hotcoal核心功能
- 自动转义特殊字符
- 提供类型安全的SQL参数处理
- 简化安全SQL查询的构建
安装Hotcoal
go get github.com/stephenafamo/hotcoal
基本使用方法
1. 简单参数转义
package main
import (
"fmt"
"github.com/stephenafamo/hotcoal"
)
func main() {
userInput := "admin'; DROP TABLE users;--"
safeInput := hotcoal.S(userInput)
query := fmt.Sprintf("SELECT * FROM users WHERE username = %s", safeInput)
fmt.Println(query)
// 输出: SELECT * FROM users WHERE username = 'admin''; DROP TABLE users;--'
}
2. 构建完整SQL查询
package main
import (
"database/sql"
"fmt"
"github.com/stephenafamo/hotcoal"
)
func main() {
db, err := sql.Open("mysql", "user:password@/dbname")
if err != nil {
panic(err)
}
defer db.Close()
username := hotcoal.S("admin")
password := hotcoal.S("password123")
query := hotcoal.Join([]hotcoal.String{
hotcoal.S("SELECT * FROM users WHERE username = "), username,
hotcoal.S(" AND password = "), password,
})
rows, err := db.Query(string(query))
if err != nil {
panic(err)
}
defer rows.Close()
// 处理查询结果...
}
3. 使用预编译语句
package main
import (
"database/sql"
"github.com/stephenafamo/hotcoal"
)
func getUser(db *sql.DB, userID int) (*User, error) {
query := hotcoal.S("SELECT id, name, email FROM users WHERE id = ?")
stmt, err := db.Prepare(string(query))
if err != nil {
return nil, err
}
defer stmt.Close()
var user User
err = stmt.QueryRow(userID).Scan(&user.ID, &user.Name, &user.Email)
if err != nil {
return nil, err
}
return &user, nil
}
高级用法
1. 批量处理参数
package main
import (
"fmt"
"github.com/stephenafamo/hotcoal"
)
func main() {
ids := []int{1, 2, 3, 4, 5}
safeIDs := make([]hotcoal.String, len(ids))
for i, id := range ids {
safeIDs[i] = hotcoal.S(fmt.Sprintf("%d", id))
}
query := hotcoal.S("SELECT * FROM products WHERE id IN (") +
hotcoal.JoinWith(safeIDs, ", ") +
hotcoal.S(")")
fmt.Println(query)
}
2. 自定义安全验证
package main
import (
"errors"
"github.com/stephenafamo/hotcoal"
)
func safeUsername(input string) (hotcoal.String, error) {
if len(input) > 20 {
return "", errors.New("username too long")
}
// 添加额外的验证逻辑
if input == "admin" {
return "", errors.New("reserved username")
}
return hotcoal.S(input), nil
}
func main() {
username, err := safeUsername("newuser")
if err != nil {
panic(err)
}
// 使用安全的username构建查询...
}
最佳实践
- 始终使用Hotcoal处理用户输入:即使是内部系统,也应遵循这一原则
- 结合预编译语句使用:Hotcoal + 预编译语句提供双重保护
- 验证输入长度和格式:在转换为hotcoal.String之前进行验证
- 限制数据库权限:应用使用的数据库账号应只有必要的最小权限
- 记录可疑查询:监控和记录包含特殊字符的查询
性能考虑
Hotcoal的设计考虑了性能因素,但在高并发场景下仍需注意:
- 重用hotcoal.String对象
- 使用预编译语句减少解析开销
- 批量处理参数时预分配切片
Hotcoal为Golang开发者提供了一种简单有效的方式来防止SQL注入攻击,结合良好的编程实践,可以显著提高应用程序的安全性。