一个网站的基本构成
- 前端:JavaScript/Vue/React
- 网关:Nginx
- 后端:Java/Go/Node.js/Python
- 前后端交互:HTTP/Websocket
一些我们经常听到的安全事件
- 数据泄露
- 服务瘫痪
- 因果失窃
- 系统劫持
网站攻击者
漏洞的分类
SQL注入
SQL注入(SQL Injection)是一种常见的网络安全漏洞,攻击者通过在应用程序的输入字段中插入恶意的SQL(结构化查询语言)代码来执行未经授权的数据库操作。这可能会导致对数据库的未授权访问、数据泄露、数据篡改以及其他安全问题。
而造成 SQL 注入的原因是因为程序没有有效过滤用户的输入,使攻击者成功的向服务器提交恶意的 SQL 查询代码,程序在接收后错误的将攻击者的输入作为查询语句的一部分执行,导致原始的查询逻辑被改变,额外的执行了攻击者精心构造的恶意代码。
下面是一个简单的例子
假设用户输入的用户名和密码是通过构建SQL查询进行验证的:
query := "SELECT * FROM users WHERE username='" + username + "' AND password='" + password + "'"
如果攻击者在用户名字段中输入 ' OR '1'='1,并且不输入密码,那么构建的查询将会是:
SELECT * FROM users WHERE username='' OR '1'='1' AND password=''
由于 '1'='1' 总是成立,查询将返回所有用户的记录,攻击者可以绕过身份验证。
如何解决?
使用参数化查询 参数化查询是一种防止SQL注入的有效方法。它的原理是将用户提供的数据作为参数传递给数据库,而不是将其直接嵌入到SQL查询字符串中。这样,数据库会自动处理参数的转义,从而防止恶意输入影响查询。
在Go中,可以使用数据库驱动程序的预处理语句来实现参数化查询。以下是修复SQL注入问题的示例代码:参数化查询是一种防止SQL注入的有效方法。它的原理是将用户提供的数据作为参数传递给数据库,而不是将其直接嵌入到SQL查询字符串中。这样,数据库会自动处理参数的转义,从而防止恶意输入影响查询。
func loginPage(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodPost {
username := r.FormValue("username")
password := r.FormValue("password")
db, err := sql.Open("mysql", "username:password@tcp(localhost:3306)/mydb")
if err != nil {
http.Error(w, "Database error", http.StatusInternalServerError)
return
}
defer db.Close()
query := "SELECT * FROM users WHERE username=? AND password=?"
rows, err := db.Query(query, username, password)
if err != nil {
http.Error(w, "Query error", http.StatusInternalServerError)
return
}
defer rows.Close()
if rows.Next() {
fmt.Fprintf(w, "Welcome, %s!", username)
} else {
fmt.Fprintln(w, "Invalid credentials")
}
} else {
//..........
}
}
在这个修复后的示例中,我们使用了参数 username 和 password 来替代原来的字符串插值。这样,数据库驱动会自动处理这些参数,确保它们被正确转义,防止SQL注入。