CSRF
CSRF 原理
CSRF(Cross-Site Request Forgery)跨站请求伪造,可以伪装为受害者的身份,向服务器发送各种请求。原理如下:
- 受害者登录受信任网站 A,并在本地生成 Cookie。
- 在不退出 A 的情况下,访问危险网站 B。此时访问 B 时会发送请求给受信任网站 A 并且会附上 Cookie 信息。
CSRF 防御
在服务器端防御 CSRF,主要有两个方面:
- 正确使用 GET、POST 请求。
- 在非 GET 请求中增验证。
正确使用 GET POST 请求
使用 REST 方式可以限制请求的类型:
GET 常用在查看,列举,展示等不需要改变资源属性的时候。
POST 常用在改变一个资源的属性或者状态。
增加验证
在非 GET 请求中增加验证,可以有三个思路:
为每个用户生成一个唯一的 token,所有表单都包含同一个伪随机值。这种方法最简单,因为攻击者(理论上)不能获取到第三方的 Cookie,所以表单中的数据也就构造失败,但是 XSS 可以窃取到第三方 Cookie,所以这个方案在没有 XSS 时是安全的。
为每一个请求使用验证码,用户体验很差。
每个用户生成的 token 随时更新,实现如下:
- 生成随机 token:
1
2
3
4
5
6
7h := md5.New()
io.WriteString(h, strconv.FormatInt(crutime, 10))
io.WriteString(h, "salt")
token := fmt.Sprintf("%x", h.Sum(nil))
t, _ := template.ParseFiles("xxx.gtpl")
t.Execute(w, token)- 表单中的 token:
1
<input type="hidden" name="token" value="{{.}}">
- 验证 token:
1
2
3
4
5
6
7r.ParseForm()
token := r.Form.Get("token")
if token != "" {
// 验证 token 的合法性
} else {
// 不存在 token 报错
}
XSS
XSS 原理
XSS(Cross-Site Scripting)跨站脚本攻击,原理是一段恶意的 JavaScript 代码在用户客户端上被执行,导致信息泄露( Cookie 泄露)。XSS 主要用于攻击用户端的。
主要分为两类:
- 存储型 XSS:恶意 XSS 代码被服务器存储到了服务器中,应用程序从数据库中查询出来并在客户端中显示,造成 XSS 攻击。
- 反射型 XSS:将恶意 XSS 代码加入到 URL 的请求参数中,请求参数在页面上直接输出。
XSS 防御
XSS防御可以有如下方式:
- 过滤特殊字符:text/template 包下面的 HTMLEscapeString、JSEscapeString 等函数可以对敏感字符进行转义。
- 输入内容长度控制:对于不受信任的输入,都应该限定一个合理的长度,这样可以增加攻击难度。
- HTTP-Only:禁止从客户端脚本中读取 Cookie 信息,使得攻击者无法窃取 Cookie。
- 等一系列防御手段。。。
SQL 注入
SQL 注入原理
SQL 注入的原理就是因为用户输入的数据被当作 SQL 语句执行。
SQL 注入防御
SQL 注入可以有如下防御方式:
限制 Web 应用数据库的操作权限,给予用户最低的操作权限。
检查输入的数据,对进入数据库的字符进行转义、过滤。html/template 包的 HTMLEscapeString 函数可以对字符串进行转义处理。
所有的查询语句建议使用数据库提供的参数化查询接口,避免直接拼接 SQL 语句。
存储密码
普通方案:哈希
目前利用最多的方案就是对明文密码进行哈希之后,进行存储。常用的单向哈希算法包括 SHA-256, SHA-1, MD5 等。
缺点:考虑到多数人所使用的密码为常见的组合,攻击者可以将所有密码的常见组合进行单向哈希,得到一个摘要组合(彩虹表),然后与数据库中的摘要进行比对即可获得对应的密码。
进阶方案:哈希+盐
可以采用加盐的方式来存储密码,常用的方式:
- 对用户的明文密码进行一次哈希运算。
- 将得到的摘要加上随机串(盐),这个随机串中可以包括某些固定的串,也可以包括用户名(用来保证每个用户加密使用的密钥都不一样)。
- 再进行一次哈希运算后,放入数据库中存储起来。
1 | // 假设用户名 abc,密码 123456 |
专家方案:Scrypt
故意增加密码计算所需耗费的资源和时间,使得任何人都不可获得足够的资源建立所需的 rainbow table
。
Scrypt 算法使得并行计算多个摘要异常困难,因此利用rainbow table(彩虹表)进行暴力攻击的难度增加。
在 Go 的 golang.org/x/crypto/scrypt 包中支持 scrypt:
1 | package main |
加密和解密数据
Go 语言中 crypto 及其子包提供了多种加密算法。