总结一下我见过的web安全漏洞和相关安全防护

sql 注入

开启慢SQL日志

  • 开启慢日志需要注意三个关键点
    1.多久算慢?
    2.慢日志存放哪?
    3.可以不可以关闭慢日志

  • 抱着上面的问题我们来查找一下 多久算慢?show variables like 'long_query_time%';

    在这里插入图片描述

    系统默认的是10s 我们来改一下,改成2s行不行set global long_query_time=2;
    在这里插入图片描述

  • 我们再看慢日志的开启状态和文件存放 show variables like 'slow_query_log%';

    在这里插入图片描述

    默认是关闭的,我们打开set global slow_query_log=1;

在这里插入图片描述
  • 测试一下
    打开一个新的窗口【或者重新启动MySQL也可以】,执行SQL select sleep(3);
    查看慢日志
    在这里插入图片描述
  • 但是这种做法是临时生效,我们可以在配置文件里面配置,在/etc/my.cnf中追加以下内容,这种做法是永久生效的
slow_query_log=1
slow_query_log_file=/usr/local/mysql/data/zhangguofudeMacBook-Pro-slow.log
long_query_time=2
  • 增加一个用户
use mysql;
create user 'acurd'@'%' identified by 'acurd';
grant all privileges  on *.*  to "acurd"@'%';

golang sql 注入

注入SQL函数

创建表

CREATE TABLE `user` (
  `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT '管理员ID',
  `name` varchar(20) NOT NULL COMMENT '管理员名称',
  `password` varchar(32) NOT NULL DEFAULT '' COMMENT '管理员密码',
  PRIMARY KEY (`id`),
  KEY `member_id` (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COMMENT='管理员表';

INSERT INTO `user` VALUES (1,'haha','123456'),(3,'123','sfdsaf');

  • 相关代码
package main

import (
    "database/sql"
    "fmt"
    _ "github.com/go-sql-driver/mysql"
    "html/template"
    "log"
    "net/http"
    "strings"
)

func login(w http.ResponseWriter, r *http.Request) {
    fmt.Println("method:", r.Method) //获取请求的方法
    if r.Method == "GET" {
        t, _ := template.ParseFiles("sql-inject/login.html")
        t.Execute(w, nil)
        return
    }

    if r.Method == "POST" {
        r.ParseForm()
        fmt.Println("name:", r.Form["name"])
        var name = strings.Join(r.Form["name"], "")
        var password = strings.Join(r.Form["password"], "")
        var id int
        db, err := sql.Open("mysql", "acurd:acurd@tcp(127.0.0.1:3306)/test")
        if err != nil {
            log.Fatal(err)
        }
        sql:="SELECT id FROM user WHERE name = '" + name + "' AND password =" + password + ""
        log.Println(sql)
        err = db.QueryRow(sql).Scan(&id)

        if err != nil {
            w.Write([]byte("登录失败!"))
            return
        }

        if id != 0 {
            w.Write([]byte("登录成功!"))
            return
        } else {
            w.Write([]byte("登录失败!"))
            return
        }
        return
    }
}

func main() {
    http.HandleFunc("/login", login)       //设置访问的路由     //设置访问的路由
    err := http.ListenAndServe(":80", nil) //设置监听的端口
    if err != nil {
        log.Fatal("ListenAndServe: ", err)
    }
}
  • 我们现在通过页面访问一下,竟然用了10s


    在这里插入图片描述
  • 我们来看一下慢日志Query_time: 10.015358 Lock_time: 0.007526 Rows_sent: 0
zhangguofu@zhangguofudeMacBook-Pro mysql $ cat /usr/local/mysql/data/zhangguofudeMacBook-Pro-slow.log

# Time: 2022-03-08T02:13:50.546820Z
# User@Host: acurd[acurd] @ localhost [127.0.0.1]  Id:    63
# Query_time: 10.015358  Lock_time: 0.007526 Rows_sent: 0  Rows_examined: 38
SET timestamp=1646705620;
SELECT id FROM user WHERE name = 'haha' AND password =ELT(1,SLEEP(10));
  • ELT(1,SLEEP(10))的意思是说如果 如果第一个值是1 ,那么就执行第一个函数,其实就是每次请求都会sleep10秒

SQL 追加条件

  • 我们再来看一个 我用户名写的是haha 密码是3 or 1=1 ,数据库里面肯定没有的,但是我登录成功了


    在这里插入图片描述
  • 查看一下sql 是这样的SELECT id FROM user WHERE name = 'haha' AND password =3 or 1=1 这条SQL把库里所有的数据都查出来了

利用SQL分隔符或者注释符对SQL截取

  • 比如我数据库里有这样一条数据


    在这里插入图片描述
  • 我把SQL改成这样sqlStr:="SELECT id FROM user WHERE name = " + name + " AND password =" + password + ""
  • 现在我发起请求,竟然也登录成功了


    在这里插入图片描述
  • 看一下执行的SQL name后面被#给截取了
SELECT id FROM user WHERE name = 123 # AND password =some word

总结

  • 这个时候可能有人有疑问,我接收password用的是string类型,怎么到执行SQL的时候就变成了函数呢?虽然你接收的是string类型,你组装MySQL也是组装成string,但是MySQL执行的时候就是原样执行,比如你这样组装var sqln string; sqln="select sleep(10)",你说你声明的是字符串,但是MySQL执行的是字符串里面的内容。
  • 如果你想在SQL语句中 用字符串,需要将参数用''包括起来,比如这样SELECT id FROM user WHERE name = 'haha' AND password ='ELT(1,SLEEP(10))'
  • 在组装SQL的时候可以这样sql:="SELECT id FROM user WHERE name = '" + name + "' AND password = '" + password + "'"
  • 或者我们可以使用MySQL的预编译
sql:="SELECT id FROM user WHERE name = ? AND password = ?"
        log.Println(sql)
        err = db.QueryRow(sql,name,password).Scan(&id)

xss攻击

  • 代码和模板
package main

import (
    "fmt"
    _ "github.com/go-sql-driver/mysql"
    "html/template"
    "log"
    "net/http"
)

func article(w http.ResponseWriter, r *http.Request) {
    fmt.Println("method:", r.Method) //获取请求的方法
    if r.Method == "GET" {
        r.ParseForm()
        title := r.FormValue("title")
        log.Println(title)
        titleHtml:=template.HTML(title)//template默认是转义了,我们使用template.HTML 表示不转义
        t, _ := template.ParseFiles("xss/article.html")
        t.Execute(w, titleHtml)
        return
    }

}

func main() {
    http.HandleFunc("/article", article)       //设置访问的路由     //设置访问的路由
    err := http.ListenAndServe(":80", nil) //设置监听的端口
    if err != nil {
        log.Fatal("ListenAndServe: ", err)
    }
}

  • html模板
<html>
<head>
    <meta charset="utf-8" />
    <title>sql注入</title>
    <style>
        form{
            width: 30vw;
            height: 30vh;
            min-height: 300px;
            margin: 10vh auto;
            border: 1px solid;
            border-radius: 4px;
        }
        form .username,.password{
            display: block;
            float: right;
        }
        div {
            width: 300px;
            height: 80px;
            margin: 30px auto 0;
        }
        input label {
            float: left;
            display: inline-block;
        }
        input {
            height: 30px;
        }
        .button {
            width: 100px;
            margin: auto;
            clear: both;
            display: block;
        }
    </style>
</head>
<body>
<form action="/article" method="get">
    <div>
        <label>标题: </label>
        <input class="username" type="text" name="title">
    </div>
    <input class="button" type="submit" value="查询">
    <p>搜索结果:{{.}}</p>
</form>
</body>
</html>

  • 反射型,比如在标题搜索里面我们输入<script>alert("反射型 XSS 攻击")</script>
    在这里插入图片描述
  • 存储型
    我们创建一个文章表
CREATE TABLE `an_article` (
                         `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT '文章id',
                         `title` varchar(100) NOT NULL COMMENT '标题',
                         `detail` varchar(1000) DEFAULT NULL COMMENT '内容',
                         PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COMMENT='文章表';

<!doctype html>
<html lang="en" content="wwwww">
<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">

</head>
<body>
<h4>{{.Title}}</h4>
<p>{{.Detail}}</p>
</body>
</html>
  • go代码
package main

import (
    "database/sql"
    "fmt"
    _ "github.com/go-sql-driver/mysql"
    "html/template"
    "log"
    "net/http"
    "strings"
)

type Article struct {
    Title template.HTML
    Detail template.HTML
}

func article(w http.ResponseWriter, r *http.Request) {
    fmt.Println("method:", r.Method) //获取请求的方法
    db, err := sql.Open("mysql", "acurd:acurd@tcp(127.0.0.1:3306)/test")
    if r.Method == "GET" {
        sqlStr:="SELECT title,detail FROM an_article WHERE id=13"//13是带xss提交生成的id
        var article Article
        var title string
        var detail string
        err = db.QueryRow(sqlStr).Scan(&title,&detail)
        article.Title=template.HTML(title)
        article.Detail=template.HTML(detail)
        log.Println(article)
        t, err := template.ParseFiles("xss/article.html")
        if err != nil{
            log.Fatal(err)
        }
        err = t.Execute(w, article)
        if err != nil{
            log.Fatal(err)
        }
        return
    }

    if r.Method=="POST"{
        if err != nil {
            log.Fatal(err)
        }
        defer db.Close()
        sqlStr := "INSERT INTO an_article (title,detail) VALUES (?,?)"

        r.ParseForm()
        fmt.Println("title:", r.Form["title"])
        fmt.Println("detail:", r.Form["detail"])
        var title = strings.Join(r.Form["title"], "")
        var detail = strings.Join(r.Form["detail"], "")
        res, _ := db.Exec(sqlStr, title, detail)
        id,_:=res.LastInsertId()
        fmt.Println(id)
    }

}

func main() {
    http.HandleFunc("/article", article)       //设置访问的路由     //设置访问的路由
    err := http.ListenAndServe(":80", nil) //设置监听的端口
    if err != nil {
        log.Fatal("ListenAndServe: ", err)
    }
}
  • post提交创建文章,id是13


    在这里插入图片描述
  • 访问页面


    在这里插入图片描述
  • 更有甚至可以把xss模拟成为图片,比如我们发送了这样一个数据
 <img src="pic.gif" onerror="alert('请点击图片查看')" alt="点击可查看" title="点击可查看" onclick="alert('叫点就点,你也是有蛮乖的!')">
在这里插入图片描述
在这里插入图片描述
  • 有的甚至截断你的标签比如</p><h4>xxxxxxx</h4> 截断了你的p标签,换行了一个h4

解决方式

  • 过滤输入,表单提交或者url参数传递前,对需要的参数进行过滤和类型转换 比如上面那个图片。我们存数据的时候 转义之后是这样的
&lt;img src=&quot;pic.gif&quot; onerror=&quot;alert(&#39;请点击图片查看&#39;)&quot; alt=&quot;点击可查看&quot; title=&quot;点击可查看&quot; onclick=&quot;alert(&#39;叫点就点,你也是有蛮乖的!&#39;)&quot;&gt;
  • 控制输出,使用转义函数、标签过滤函数等 比如转义后的在html 并不是医html实体 ,而是字符串的形式出现的,当然不会被执行


    在这里插入图片描述

    在这里插入图片描述
  • 对于一些富文本,我们可以采用白名单或者黑名单的方式,过滤非法字符串

csrf攻击

  • 简单理解就是你访问了a网站并登录成功,你办完事后并没有退出登录,这个时候你访问了b网站,b网站给你提供了一个a网站的链接(转账 发邮件等链接),并引导你点击。你点击了之后,发现钱没了。。。这就是csrf攻击
  • 比如你是公司的财务,你通过公司网站提交了一个支付请求,这个时候你这个支付请求被第三方截获。第三方也模拟了一个同样的请求。这样公司就要支付两笔钱


    在这里插入图片描述

解决csrf攻击的方法

  • 验证 HTTP Referer 字段,比如只有admin.aaa.com的请求才允许访问,但是refer是可以伪造的
  • 一次性token,每次用户提交的时候都带着一个由服务端颁发的token(一次性的),用户提交完毕即销毁token,token可以加入body中发送给服务端,也可以放在header中发送给服务端
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,306评论 4 370
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,657评论 2 307
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,928评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,688评论 0 220
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,105评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,024评论 1 225
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,159评论 2 318
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,937评论 0 212
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,689评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,851评论 2 254
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,325评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,651评论 3 263
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,364评论 3 244
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,192评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,985评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,154评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,955评论 2 279

推荐阅读更多精彩内容