作为后端开发者我们要记住一句话:“永远不要相信用户的输入”,这里所说的用户可能是人,也可能是另一个应用程序。“永远不要相信用户的输入”是安全编码的准则,也就是说,任何输入的内容在验证无害之前都是有害的。很多应用程序的安全漏洞都和用户输入有关,比如SQL注入漏洞。

我们可以通过参数验证、sql语句过滤和参数化查询等方式对用户的输入进行处理来规避这种安全隐患。本文介绍第一种方法,并对基于gin的golang web开发:模型验证进行补充,了解更多的参数验证方法。

验证非必填的邮箱字段

需求是这样的:我们需要验证一个字段可以为空,同时字段的值为合法的电子邮箱。

  1. type MailRequest struct {
  2. Email string `json:"email" binding:"email"` // 邮箱地址
  3. }

代码的执行结果和我们想的不太一样,我们没有为字段设置required标签,但是传入空字符串时会提示Email必须是一个有效的邮箱,解决方法是加入omitempty验证规则。omitempty允许条件验证,在没有为字段设置值的情况下,跳过后面的验证规则。注意omitempty要放在其他规则前面。下面是修改后的代码:

  1. type MailRequest struct {
  2. Email string `json:"email" binding:"omitempty,email"` // 邮箱地址
  3. }

验证0值

先看代码

  1. type AddRoleRequest struct {
  2. Available int `json:"available" binding:"required"` // 是否可用 0 不可用 1 可用
  3. }

Available 字段为int类型,添加了required验证规则,0为一个有效的值。Available为0时不能通过Gin的参数验证。这里只需要把字段类型修改为*int即可。

  1. type AddRoleRequest struct {
  2. Available *int `json:"available" binding:"required"` // 是否可用 0 不可用 1 可用
  3. }

自定义错误消息

前文基于gin的golang web开发:模型验证结尾部分,我们没有把参数验证的错误消息完全翻译成中文,字段名还是英文的。显然还有更优雅的做法,给用户提示一个更友好的错误信息。

  1. {
  2. "error": "Username为必填字段;"
  3. }

返回值中的Username为字段名称,可以通过自定义标签的方式修改错误信息中的字段名。我们自定义一个display标签,然后使用标签的值替换掉验证器中的字段。

  1. func init() {
  2. translator := zh.New()
  3. uni = ut.New(translator, translator)
  4. trans, _ = uni.GetTranslator("zh")
  5. validate := binding.Validator.Engine().(*validator.Validate)
  6. // 注意这里
  7. validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
  8. return fld.Tag.Get("display")
  9. })
  10. _ = zh_translations.RegisterDefaultTranslations(validate, trans)
  11. }
  12. func Translate(err error) string {
  13. var result string
  14. errors := err.(validator.ValidationErrors)
  15. for _, err := range errors {
  16. errMessage := err.Translate(trans)
  17. result += errMessage + ";"
  18. }
  19. return result[:len(result)-1] // <--
  20. }
  21. type AddUserRequest struct {
  22. Username string `json:"username" binding:"required" display:"用户名"`
  23. Password string `json:"password" binding:"required" display:"密码"` // 登录密码
  24. Nickname string `json:"nickname" binding:"required" display:"昵称"` // 昵称
  25. }

注意代码中validate.RegisterTagNameFunc方法注册display标签,Translate方法也有一些改进,去掉了结果中最后一个分号。

举个栗子

  1. func checkUser(user string, password string) bool {
  2. db := GetDbContext()
  3. defer db.Close()
  4. dataSql := `
  5. select count(1) from sys_user
  6. where username = '` + user + `' and password = '` + password + `'`
  7. count := 0
  8. log.Println(dataSql)
  9. db.QueryRow(dataSql).Scan(&count)
  10. return count > 0
  11. }

这段代码用于判断账号密码是否正确,但是没有验证用户输入的user和password参数,恶意用户构造一个特殊的密码1' or '1'='1dataSql中拼接的sql语句变为

  1. select count(1) from sys_user
  2. where username = 'xxx' and password = '1' or '1'='1'

查询结果大于0,方法返回真。这就造成了sql注入。我们可以在password字段上增加规则alphanum验证字段内容只能为字母或数字。1' or '1'='1不能通过参数验证也就规避掉了SQL注入的问题。例子中拼接SQL语句是为了方便演示,正式项目中不推荐这种写法。完整代码如下:

  1. type UserAndPassword struct {
  2. User string `json:"user" binding:"required,alphanum"`
  3. Pwd string `json:"pwd" binding:"required,alphanum"`
  4. }
  5. func IsLoginIn(c *gin.Context) {
  6. var req = UserAndPassword{}
  7. if err := c.ShouldBindJSON(&req); err != nil {
  8. c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
  9. return
  10. }
  11. c.String(http.StatusOK, strconv.FormatBool(checkUser(req.User, req.Pwd)))
  12. }
  13. func checkUser(user string, password string) bool {
  14. db := GetDbContext()
  15. defer db.Close()
  16. dataSql := `
  17. select count(1) from sys_user
  18. where username = '` + user + `' and password = '` + password + `'`
  19. count := 0
  20. log.Println(dataSql)
  21. db.QueryRow(dataSql).Scan(&count)
  22. return count > 0
  23. }

文章出处:基于gin的golang web开发:永远不要相信用户的输入

基于gin的golang web开发:永远不要相信用户的输入的更多相关文章

  1. 基于gin的golang web开发:路由

    Gin是一个用Golang编写的HTTP网络框架.它的特点是类似于Martini的API,性能更好.在golang web开发领域是一个非常热门的web框架. 启动一个Gin web服务器 使用下面的 ...

  2. 基于gin的golang web开发:路由二

    在基于gin的golang web开发:路由中我们介绍了Gin的路由和一些获取链接中参数的方法,本文继续介绍其他获取参数的方法. 文件上传 在web开发中文件上传是一个很常见的需求,下面我们来看一下基 ...

  3. 基于gin的golang web开发:模型绑定

    在前两篇文章介绍路由的时候,我们了解到gin可用通过类似DefaultQuery或DefaultPostForm等方法获取到前端提交过来的参数.参数不多的情况下也很好用,但是想想看,如果接口有很多个参 ...

  4. 基于gin的golang web开发:模型验证

    Gin除了模型绑定还提供了模型验证功能.你可以给字段指定特定的规则标签,如果一个字段用binding:"required"标签修饰,在绑定时该字段的值为空,那么将返回一个错误.开发 ...

  5. 基于gin的golang web开发:访问mysql数据库

    web开发基本都离不开访问数据库,在Gin中使用mysql数据库需要依赖mysql的驱动.直接使用驱动提供的API就要写很多样板代码.你可以找到很多扩展包这里介绍的是jmoiron/sqlx.另外还有 ...

  6. 基于gin的golang web开发:使用数据库事务

    在前文介绍访问数据库时介绍了github.com/jmoiron/sqlx包,本文基于这个包使用数据库事务. defer 在使用数据库事务之前,首先需要了解go语言的defer关键字.defer是go ...

  7. 基于gin的golang web开发:mysql增删改查

    Go语言访问mysql数据库需要用到标准库database/sql和mysql的驱动.标准库的Api使用比较繁琐这里再引入另一个库github.com/jmoiron/sqlx. go get git ...

  8. 基于gin的golang web开发:中间件

    gin中间件(middleware)提供了类似于面向切面编程或路由拦截器的功能,可以在请求前和请求之后添加一些自定义逻辑.实际开发中有很多场景会用到中间件,例如:权限验证,缓存,错误处理,日志,事务等 ...

  9. 基于gin的golang web开发:集成swagger

    在前后端分离的项目维护一份完整且及时更新的api文档会极大的提高我们的工作效率,传统项目中接口文档都是由后端开发手写的,这种文档很难保证及时性,久而久之便失去了参考意义.swagger给我们提供了一种 ...

随机推荐

  1. 浅析Java Web框架技术

    一.Java Web框架技术的概念 所谓的Java框架,简单理解是一个可复用的设计构件,它规定了应用的体系结构,阐明了整个设计.协作构件之间的依赖关系.责任分配和控制流程,表现为一组抽象类以及其实例之 ...

  2. JavaScript 正则表达式:字符串中查找数字

    以下代码是在一段字符串中,用正则表达式找到数字,使用 replace() 方法,用找到的数字的两倍值替换原数字.replace() 方法的第二个参数为一个函数,返回找到数字的两倍值. <scri ...

  3. C语言知识点复习梳理

    C语言知识点复习梳理 C语言的知识点讲完了,接下来就是做一下整理与总结,然后就会进入其他知识的学习. 本文目录如下: 基础知识. 顺序程序设计. 数据类型. 标准输入输出. 进制转换. 选择结构. 循 ...

  4. MySQL图形界面客户端

    图形界面客户端 使用图形界面客户端操作数据库更直观.方便.下面三个客户端都能操作MySQL,各有各自的优点. 1.Navicat Premium 下载安装包下载 关注公众号[轻松学编程],然后回复[n ...

  5. ps怎么做发光字体效果 ps中最简单的发光字教程

    ps中最简单的发光字教程 我们先用[文字工具]输入文字(比如:发光效果),字体填充为白色,如图所示. 我们选中文字的图层,点击[FX]找到[外发光],如图所示. 接着,我们在外发光里面把颜色设置为紫色 ...

  6. Core WebApi项目快速入门(一):环境部署

    1.WebApi新建与部署 1.1 新建Core WebApi工程 1.2 部署 1.2.1 IIS部署 首先以文件方式发布应用程序,然后下载依赖.net core运行时及host安装包 在iis中看 ...

  7. CSS3:overflow属性详解

    1.Overflow overflow为溢出(容器),当内容超出容器时只需添加overflow属性值为hidden, 就可以把超出容器的部分隐藏起来: 如果内容超出容器却又不想其隐藏时可以将其属性值设 ...

  8. MQ-gogogo

    1. RocketMQ https://github.com/alibaba/RocketMQ/wiki/quick-start 2. RabbitMQ https://www.rabbitmq.co ...

  9. fashion数据集训练

    下载数据集 fashion数据集总共有7万张28*28像素点的灰度图片和标签,涵盖十个分类:T恤.裤子.套头衫.连衣裙.外套.凉鞋.衬衫.运动鞋.包.靴子. 其中6万张用于训练,1万张用于测试. im ...

  10. animation关键帧动画语法

    基本声明和用法 @-webkit-keyframes NAME-YOUR-ANIMATION { 0% { opacity: 0; } 100% { opacity: 1; } } @-moz-key ...