这是我参与「第五届青训营 」伴学笔记创作活动的第 10 天
SQL注入
SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。
解决方法
- 过滤输入内容,校验字符串:数据提交到数据库之前,对其中的不合法字符进行剔除。也可以验证输入数据的类型是否符合要求。
- 参数化查询:目前被认为是最有效的预防sql注入方法。需要填入数据的地方,使用参数(Parameter)来给值 先把参数用?代替 ,再编译后再填入参数具体值。就算有破坏指令,也不会被执行
- 安全测试、安全审计:开发中对代码进行审查,测试环节进行测试,上线后定期扫描安全漏洞
规范
- 避免使用动态sql 最好使用准备好的语句和参数化查询 避免将用户输入的数据直接放入sql
- 不要将敏感数据保留在纯文本中 加密数据库中的敏感数据 以防攻击者排出敏感数据
- 限制数据库访问权限和特权
- 避免直接向用户显示数据库报错 攻击者可能使用这些错误消息来获取数据库信息
下面使用的解决方法是参数化查询(推荐)。
代码
package dao
import (
"go_douyin/database"
"go_douyin/model")
//(以下代码可以防止SQL注入)
// FollowMapper 自定义FollowMapper的类型,于follow实体类对应即可
type FollowMapper struct{}
func NewFollowMapper() *FollowMapper {
return &FollowMapper{}
}
// 显示关注列表
func (FollowMapper) FollowFindList(userId uint64) []model.User {
var followedUsers []model.User
//查询数据(联表查询)
database.SqlDB.Table("tb_follow_list").Select("tb_users.*").Joins("JOIN tb_users ON tb_follow_list.follow_user_id = tb_users.user_id").Where("tb_follow_list.user_id = ?", userId).Scan(&followedUsers)
return followedUsers
}
XSS攻击
XSS攻击通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是JavaScript。
解决方法
处理的过程是在服务端配置富文本标签和属性的白名单,不允许出现其他标签或属性(例如script、iframe、form等),即”XSS Filter“。然后在存储之前进行过滤。
配置
go get -u github.com/dvwright/xss-mw
代码
(直接使用第三方库) 关键
var xssMdlwr xss.XssMw
router.Use(xssMdlwr.RemoveXss())
完整代码 router/router.go
package router
import (
"github.com/dvwright/xss-mw"
"github.com/gin-gonic/gin" "go_douyin/controller" "go_douyin/utils/cors")
func SetupRouter() *gin.Engine {
router := gin.Default()
var xssMdlwr xss.XssMw
router.Use(xssMdlwr.RemoveXss())
userController := controller.NewUserController()
v1 := router.Group("/douyin/user")
{
v1.POST("register", userController.Register)
v1.POST("login", userController.Login)
v1.GET("/", userController.GetInfo)
}
//允许跨域
router.Use(cors.Next())
return router
}
使用MD5加密密码
MD5的全称是md5信息摘要算法(英文:MD5 Message-Digest Algorithm ),一种被广泛使用的密码散列函数,可以产生一个128位(16字节,1字节8位)的散列值(常见的是用32位的16进制表示,比如:0caa3b23b8da53f9e4e041d95dc8fa2c),用于确保信息传输的完整一致。MD5由MD4、MD3、MD2改进而来,主要增强算法复杂度和不可逆性。MD5算法因其普遍、稳定、快速的特点,仍广泛应用于普通数据的加密保护领域。
代码
utils/md5_encrypt/md5_encrypt.go
package md5_encrypt
import (
"crypto/md5"
"encoding/base64"
"encoding/hex")
func MD5(params string) string {
md5Ctx := md5.New()
md5Ctx.Write([]byte(params))
return hex.EncodeToString(md5Ctx.Sum(nil))
}
//先base64,然后MD5
func Base64Md5(params string) string {
return MD5(base64.StdEncoding.EncodeToString([]byte(params)))
}
service/user/curd/userService.go(关键代码)
func (h *UserService) Register(user model.User) bool {
user.CreateTime = time.Now()
// 预先处理密码MD5加密
user.Password = md5_encrypt.Base64Md5(user.Password)
row := h.userMapper.Add(user)
if row > 0 {
return true
} else {
return false
}
}
func (h *UserService) Login(username string, password string) (bool, model.User, string) {
var user model.User = h.userMapper.Login(username, md5_encrypt.Base64Md5(password))
// 比较结构体是否为空
if reflect.DeepEqual(user, model.User{}) { //判断是否为空值
//fmt.Println("user is empty")
return false, user, ""
} else {
// 生成JWT
userTokenFactory := JWT.CreateUserFactory()
if userToken, err := userTokenFactory.GenerateToken(user.UserID, user.Username, 28800); err == nil {
return true, user, userToken
} else {
return false, user, ""
}
}
}