新建一个 testform2.gtpl 文件,内容如下:

<!doctype html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport"content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>修改资料</title>
</head>
<body>
<form action="/info" method="post" enctype="multipart/form-data">头像:<input type="file" name="userheader"><br>用户名:<input type="text" name="username"><br>密码:<input type="password" name="password"><br>年龄:<input type="text" name="age"><br>邮箱:<input type="text" name="email"><br>手机号码:<input type="text" name="mobile"><br>身份证号码:<input type="text" name="usercard"><br>测试xss:<input type="text" name="xss"><br>性别:<select name="sex" ><option value="0">无</option><option value="1">男</option><option value="2">女</option></select><br>兴趣:<br><input type="checkbox" name="interest" value="no">无<input type="checkbox" name="interest" value="football">足球<input type="checkbox" name="interest" value="basketball">篮球<input type="checkbox" name="interest" value="tennis">网球<br><input type="hidden" name="token" value="{{.}}"><input type="submit" value="提交">
</form>
</body>
</html>

新建一个 testform2.go 文件,内容如下:

package mainimport ("fmt""crypto/md5""html/template"texttemplate "text/template""io""os""log""time""net/http""strconv""regexp""unicode"
)//判断是否在切片中
func In_slice(val string, slice []string) bool {for _, v := range slice {if v == val {return true}}return false
}
//判断两个切片的差异
//返回差异的数组
func Slice_diff(slice1, slice2 []string) (diffslice []string) {for _, v := range slice1 {if !In_slice(v, slice2) {diffslice = append(diffslice, v)}}return
}func sayhelloName(w http.ResponseWriter,r *http.Request)  {//下面这个写入到w 的是输出到客户端的fmt.Fprintf(w,"hello testform2.go")
}//验证表单输入
func info(w http.ResponseWriter,r *http.Request)  {fmt.Println("method:",r.Method) //获取请求的方法if r.Method == "GET"{curtime := time.Now().Unix()h := md5.New()io.WriteString(h,strconv.FormatInt(curtime,10))token := fmt.Sprintf("%x",h.Sum(nil)) //生成token//设置cookieexpiration := time.Now()expiration = expiration.AddDate(1, 0, 0)cookie := http.Cookie{Name: "username", Value: "go-cookie", Expires: expiration}http.SetCookie(w, &cookie)t,_ := template.ParseFiles("testform2.gtpl")t.Execute(w,token) //把token 写入到模板中}else{//读取cookiecookie, _ := r.Cookie("username")fmt.Println("cookie:",cookie)//防止多次重复提交表单//解决方案是在表单中添加一个带有唯一值的隐藏字段。// 在验证表单时,先检查带有该唯一值的表单是否已经递交过了。// 如果是,拒绝再次递交;如果不是,则处理表单进行逻辑处理。res1 := verifyToken(w,r)if !res1 {return}//表单验证res2 := formValidate(w,r)if !res2 {return}//预防跨站脚本res3 := xss(w,r)if !res3 {return}//获取上传文件res4 := uploadHandler(w,r)if !res4{return}}}
//防止多次重复提交表单
func verifyToken(w http.ResponseWriter,r *http.Request) bool{//r.ParseForm() //普通表单r.ParseMultipartForm(32<<20) //加入了 enctype="multipart/form-data" 的表单token := r.Form.Get("token")fmt.Println("token:",token)if token != ""{// 验证 token 的合法性if len(token) <10{fmt.Fprintf(w,"token验证失败")return false}fmt.Fprintf(w,"token验证通过")}else{//不存在token 报错fmt.Fprintf(w,"token验证失败")return false}fmt.Fprintf(w,"\n")return true
}//表单验证
func formValidate(w http.ResponseWriter,r *http.Request) bool{//r.ParseForm()       //解析url传递的参数,对于POST则解析响应包的主体(request body)r.ParseMultipartForm(32<<20) //加入了 enctype="multipart/form-data" 的表单//请求的是登录数据,name执行登录的逻辑判断fmt.Println("username:",r.Form["username"])fmt.Println("password:",r.Form["password"])fmt.Println("age:",r.Form["age"])fmt.Println("email:",r.Form["email"])fmt.Println("mobile:",r.Form["mobile"])fmt.Println("sex:",r.Form["sex"])fmt.Println("interest:",r.Form["interest"])fmt.Println("usercard:",r.Form["usercard"])//验证表单数据--------------------------------------------------------//必填字段if len(r.Form["username"][0]) == 0{//返回到客户端fmt.Fprintf(w,"用户名不能为空")return false}//unicode判断中文for _, val := range r.Form.Get("username"){if unicode.Is(unicode.Scripts["Han"], val) {//有中文fmt.Fprintf(w,"unicode姓名不能有中文\n")}}//正则判断中文chiReg := regexp.MustCompile("[\u4e00-\u9fa5]+")for _, val := range r.Form.Get("username") {if chiReg.MatchString(string(val)){//有中文fmt.Fprintf(w,"regexp姓名不能有中文\n")return false}}//判断英文match2,_ := regexp.MatchString("^[a-zA-Z]+$",r.Form.Get("username"))if !match2{fmt.Fprintf(w,"姓名只能是英文字母")return false}//使用转化判断数字getint,err := strconv.Atoi(r.Form.Get("age"))if err != nil{//数字转化出错了,那么可能就不是数字了fmt.Fprintf(w,"strconv年龄只能是数字\n")}//使用正则判断数字 ,应该尽量避免使用正则表达式,因为使用正则表达式的速度会比较慢m,_ := regexp.MatchString("^[0-9]+$",r.Form.Get("age"));if !m {fmt.Fprintf(w,"regexp年龄只能是数字\n")return false}//判断数字的大小范围if getint > 200{fmt.Fprintf(w,"年龄不能大于200")return false}//判断电子邮件match3,_ := regexp.MatchString(`^([\w\.\_]{2,})@(\w{1,})\.([a-z]{2,4})$`,r.Form.Get("email"))if !match3{fmt.Fprintf(w,"电子邮箱格式不正确")return false}//判断手机号码match4,_ := regexp.MatchString(`^1[0-9][0-9]\d{8}$`,r.Form.Get("mobile"))if !match4{fmt.Fprintf(w,"手机号码不正确")return false}//判断身份证号码//15位 或18位usercard := r.Form.Get("usercard")match5,_ := regexp.MatchString(`^(\d{15})$`,usercard)match6,_ := regexp.MatchString(`^(\d{17})([0-9]|X)$`,usercard)fmt.Println(usercard)fmt.Println(len(usercard))fmt.Println(!match6)if len(usercard) <= 15 && !match5{fmt.Fprintf(w,"身份证不正确")return false}else if len(usercard) > 15 && !match6{fmt.Fprintf(w,"身份证不正确")return false}//判断下拉菜单的值是否符合预设值sex_slice := []string{"1","2"}sex_value := r.Form.Get("sex")is_set := 0 //是否符合预设值 ,1 是,0否for _,val := range sex_slice{if sex_value == val{is_set = 1}}if is_set == 0{fmt.Fprintf(w,"性别不正确")return false}//判断复选框interest_slice := []string{"football","basketball","tennis"}interest := r.Form["interest"]array := Slice_diff(interest,interest_slice)fmt.Println("interest:",array)if array != nil{//有差异fmt.Fprintf(w,"兴趣选择不正确")return false}return true
}//预防跨站脚本
func xss(w http.ResponseWriter,r *http.Request) bool{//template.HTMLEscape(w io.Writer, b []byte) //把b进行转义之后写到w//template.HTMLEscapeString(s string) string //转义s之后返回结果字符串//template.HTMLEscaper(args ...interface{}) string //支持多个参数一起转义,返回结果字符串//输出到服务器端fmt.Println("xss:", template.HTMLEscapeString(r.Form.Get("xss")))//转义后输出到客户端template.HTMLEscape(w, []byte(r.Form.Get("xss")))fmt.Fprintf(w, "\n") //换行//转义后输出到客户端t,err := template.New("foo").Parse(`{{define "T"}}hello,{{.}}!{{end}}`)err = t.ExecuteTemplate(w,"T","<script>alert('you have been pwned')</script>")if err != nil{fmt.Println(err)}fmt.Fprintf(w, "\n") //换行//使用 text/template 完全输出到客户端t1,err1 := texttemplate.New("foo").Parse(`{{define "T"}}hello,{{.}}!{{end}}`)err1 = t1.ExecuteTemplate(w,"T","<script>alert('you have been pwned')</script>")if err1 != nil{fmt.Println(err1)}fmt.Fprintf(w, "\n") //换行//使用 html/template template.HTML 完全输出到客户端t2, err2 := template.New("foo").Parse(`{{define "T"}}hello,{{.}}!{{end}}`)err2 = t2.ExecuteTemplate(w,"T",template.HTML("<script>alert('you have been HTML')</script>"))if err2 != nil{fmt.Println(err2)}return true
}//获取上传文件
func uploadHandler(w http.ResponseWriter,r *http.Request) bool{//通过上面的代码可以看到,处理文件上传我们需要调用r.ParseMultipartForm,// 里面的参数表示maxMemory,调用ParseMultipartForm之后,// 上传的文件存储在maxMemory大小的内存里面,// 如果文件大小超过了maxMemory,那么剩下的部分将存储在系统的临时文件中。// 我们可以通过r.FormFile获取上面的文件句柄,然后实例中使用了io.Copy来存储文件。r.ParseMultipartForm(32<<20)file,handler,err := r.FormFile("userheader")//文件的handler 是multipart.FileHeader ,里面存储了如下结构信息/*type FileHeader struct{Filename stringHeader textproto.MIMEHeader//contains filtered or unexported fields}*/if err != nil{fmt.Println(err)return false}defer file.Close()fmt.Fprintf(w,"%v",handler.Header)f,err := os.OpenFile("./"+handler.Filename,os.O_WRONLY|os.O_CREATE,0777)if err != nil{fmt.Println(err)return false}defer f.Close()io.Copy(f,file)return true
}func main() {http.HandleFunc("/",sayhelloName) //设置路由http.HandleFunc("/info",info) //设置路由err := http.ListenAndServe(":6665",nil) //设置监听的端口if err != nil{log.Fatal("ListenAndServe:",err)}
}

运行 testform2.go ,启动服务器 :

[root@izj6c4jirdug8kh3uo6rdez goweb]# go run testform2.go

浏览器运行 http://域名:6665/info  ,输入数据后提交,客户端显示:

token验证通过
&lt;script&gt;alert(123);&lt;/script&gt;
hello,&lt;script&gt;alert('you have been pwned')&lt;/script&gt;!
hello,<script>alert('you have been pwned')</script>!
hello,<script>alert('you have been HTML')</script>!map[Content-Disposition:[form-data; name="userheader"; filename="a435c26724359a53730a52d919f106a4.png"] Content-Type:[image/png]]

服务器端即可看到表单参数:

method: POST
token: 11112bd3ffe4ba8ddaea713ef49f9806
username: [awef]
password: []
age: [3]
email: [123@qq.com]
mobile: [12312345678]
sex: [1]
interest: [football]
usercard: [123456789123456123]
123456789123456123
18
false
interest: []
xss: &lt;script&gt;alert(123);&lt;/script&gt;

参考:https://www.golang123.com/book/9?chapterID=158

go实践二十 web开发--表单唯一token 表单验证 防止xss攻击 上传文件 cookie处理相关推荐

  1. Web自动化成长之路:selenium中鼠标、键盘、上传文件操作、使用js脚本

    前言:UI自动化操作时,鼠标操作.键盘操作.文件上传都是使用普遍且重要的操作,接下来我们就一起来学习下吧 一.文件上传 a)send_keys:一定是要是input元素 input 里的type=&q ...

  2. iOS开发:xcode无法选择设备和corner stone如何过滤上传文件

    今天开发遇到一个问题,丛svn checkout的项目,xcode竟然把它识别成Mac工程了,target在Xcode上的device选项竟然只有My Mac,无法选择iphone. 用电脑打开其他工 ...

  3. form表单上传文件_SpringBoot中如何使用SpringMVC上传文件?

    今天我们要说的这个话题很简单,不要问为啥,因为SpringBoot,哈哈.现在SpringBoot可以说人人都会用了,它的好处是显而易见的,大大的简化了配置,一起来看看吧. 我们分以下3种情况来谈这个 ...

  4. javaweb开发之处理表单上传文件和文件下载

    2019独角兽企业重金招聘Python工程师标准>>> 一.基于表单的上传文件 1. enctype属性 当表单需要上传文件时,需指定表单 enctype 的值为 multipart ...

  5. 文件上传表单 上传文件的细节 文件上传下载和数据库结合

    1 文件上传表单    1)上传文件的本质是文本复制的过程    2)技术层面,在Java中一定会用到IO操作,主要以二进制方式读写    3)传统方式下,对于上传文件字段不同的浏览器有着不同的解析方 ...

  6. JAVAWEB开发之SpringMVC详解(二)——高级开发、数据回显、参数绑定集合、图片上传、json交互、validation校验、异常处理、RESTful支持、拦截器

    知识回顾 springmvc框架 用户请求url到DispatcherServlet前端控制器,相当于中央调度器,降低系统各组件之间的耦合度. DispatcherServlet前端控制器通过Hand ...

  7. 利用mysql实现上传和下载_文件上传表单 上传文件的细节 文件上传下载和数据库结合...

    1 文件上传表单 1)上传文件的本质是文本复制的过程 2)技术层面,在Java中一定会用到IO操作,主要以二进制方式读写 3)传统方式下,对于上传文件字段不同的浏览器有着不同的解析方式,例如: IE6 ...

  8. java form 上传文件_java通过表单进行文件上传的几种方法

    上传文件的分类: 无论什么方式上传文件,都要用post提交 方式一: 前端:表单方式上传文件 后端: 使用上传技术是apache中的Commons-fileupload.jar commons-io. ...

  9. ajax上传文件表单,图片、文件无刷新上传,jquery.form.js的使用

    我们在进行一些web开发时,有时会需要上传文件,图片等等的功能.这篇文章记录一下我实现用ajax实现无刷新上传图片的方法. 我们先要了解一下ajax,在前后端分离的开发环境中ajax被广泛的用原来前后 ...

最新文章

  1. [原创]SQL 表值函数:获取从今天计算起往前自定义天数
  2. Blockchain:《Blockchain applications in insurance》Deloitte—德勤区块链技术研究报告正文版—听课记录
  3. 【bzoj4025】二分图 LCT
  4. final 最终 java 1614876717
  5. kafka分区停留在UnderReplicated状态
  6. Linux (x86) Exploit 开发系列教程之八 绕过 ASLR -- 第三部分
  7. “+=”和append的区别
  8. c语言程序填空z=7,x=4,《C语言程序设计》复习题有答案
  9. CompletableFuture异步任务的简单使用
  10. 点石成金_Index
  11. 专升本C语言习题知识点笔记
  12. Win10首次开机设置
  13. cpu倍频模式怎么调_BIOS:增加倍频比率调整选项
  14. 友达8寸高分辨率工业屏G080UAN02.2-8寸MIPI屏
  15. 大数据技术_ 基础理论 之 大数据概念与应用
  16. mysql的首字母大写_修改MySQL字段为首字母大写
  17. 这家为AI for Science而生的新研究院,要让科研进入“安卓模式”
  18. 软考和高项哪个更好考?
  19. 西工大机考《 现代设计方法》大作业网考
  20. 云天励飞人脸识别技术助力央视春晚会场安保

热门文章

  1. optix资料(基于optix7.0)——错误
  2. 戴尔 DELL 游戏笔记本电脑 - Windows 10 关闭触摸板
  3. 使用Typora设置图片自动上传至gitee仓库
  4. 如何提高游戏后台数据查找效率
  5. Wine Mono 环境安装并运行.Net WPF
  6. 阿里云发布首款云电脑“无影”,价格仅传统电脑的一半
  7. ERROR dispatch for GET /error?thingName=lxyrequestId=123, parameters={masked}
  8. 局域网arp攻击_网络安全工程师教Kali Linux:ARP欺骗概述
  9. pstack无法使用的问题
  10. 退役感言 [Away From OI]