Go语言SQL注入和防注入

一、SQL注入是什么

SQL注入是一种注入攻击手段,通过执行恶意SQL语句,进而将任意SQL代码插入数据库查询,从而使攻击者完全控制Web应用程序后台的数据库服务器。攻击者可以使用SQL注入漏洞绕过应用程序验证,比如绕过登录验证登录Web身份验证和授权页面;也可以绕过网页,直接检索数据库的所有内容;还可以恶意修改、删除和增加数据库内容。

二、防止SQl注入的思路和方法

  • 1.永远不要信任用户的输入。对用户的输入进行校验,可以通过正则表达式,或限制长度;对单引号和 双"-"进行转换等。
  • 2.永远不要使用动态拼装SQL,可以使用参数化的SQL或者直接使用存储过程进行数据查询存取。
  • 3.永远不要使用管理员权限的数据库连接,为每个应用使用单独的权限有限的数据库连接。
  • 4.不要把机密信息直接存放,加密或者hash掉密码和敏感的信息。
  • 5.应用的异常信息应该给出尽可能少的提示,最好使用自定义的错误信息对原始错误信息进行包装
  • 6.sql注入的检测方法一般采取辅助软件或网站平台来检测,软件一般采用sql注入检测工具jsky,网站平台就有亿思网站安全平台检测工具。MDCSOFT SCAN等。采用MDCSOFT-IPS可以有效的防御SQL注入,XSS攻击等。

三、Go语言防止SQL注入的方法

我们采取了第二条思路和方法,即不用动态拼接SQL语句的方法,而是使用参数化查询,即变量绑定。

下面给出SQL注入攻击安全漏洞代码——拼接SQL语句:

//数据库
/*
Navicat Premium Data Transfer Source Server : localhost_3306
Source Server Type : MySQL
Source Server Version : 50553
Source Host : localhost:3306
Source Schema : test Target Server Type : MySQL
Target Server Version : 50553
File Encoding : 65001 Date: 28/02/2020 10:48:06
*/ SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0; -- ----------------------------
-- Table structure for userinfo
-- ----------------------------
DROP TABLE IF EXISTS `userinfo`;
CREATE TABLE `userinfo` (
`uid` int(10) NOT NULL AUTO_INCREMENT,
`username` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`password` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`uid`) USING BTREE
) ENGINE = MyISAM AUTO_INCREMENT = 14 CHARACTER SET = latin1 COLLATE = latin1_swedish_ci ROW_FORMAT = Dynamic; -- ----------------------------
-- Records of userinfo
-- ----------------------------
INSERT INTO `userinfo` VALUES (2, 'aaa', 'hh');
INSERT INTO `userinfo` VALUES (4, 'ast', 'dddd'); SET FOREIGN_KEY_CHECKS = 1;
//test.go
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("D:/Golang/GoItem/go_ex/goSql/test.html")
t.Execute(w, nil)
} else {
//请求的是查询数据,那么执行查询的逻辑判断
r.ParseForm()
fmt.Println("username:", r.Form["username"])
var sename = strings.Join(r.Form["username"], "")
var partname = strings.Join(r.Form["password"], "")
db, err := sql.Open("mysql", "root:123456@/test?charset=utf8")
infoErr(err)
if sename != "" && partname != "" {
var uid int
var username string
var password string
//字符串拼接查询
err := db.QueryRow("SELECT * FROM userinfo WHERE username ='"+sename+"'AND password ='"+partname+"'").
Scan(&uid, &username, &password)
infoErr(err)
//判断返回的数据是否为空
if err == sql.ErrNoRows {
fmt.Fprintf(w, "无该用户数据")
} else {
if (sename == username) && (partname == password) {
fmt.Println(uid)
fmt.Println(username)
fmt.Println(password)
t, _ := template.ParseFiles("D:/Golang/GoItem/go_ex/goSql/success.html")
t.Execute(w, nil)
}
}
} else if sename == "" || partname == "" {
fmt.Fprintf(w, "错误,输入不能为空!")
} } } func infoErr(err error) {
if err != nil {
panic(err)
}
} func main() {
http.HandleFunc("/login",login) //设置访问的路由 //设置访问的路由
err := http.ListenAndServe(":9092", nil) //设置监听的端口
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}
//login.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="/login" method="post">
<div>
<label>username: </label>
<input class="username" type="text" name="username">
</div>
<div>
<label>password:</label>
<input class="password" type="text" name="password">
</div>
<input class="button" type="submit" value="查询">
</form>
</body>
</html>

解决防SQL注入方案——参数化查询:

//test.go
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("D:/Golang/GoItem/go_ex/goSql/login.html")
t.Execute(w, nil)
} else {
//请求的是查询数据,那么执行查询的逻辑判断
r.ParseForm()
fmt.Println("username:", r.Form["username"])
var sename = strings.Join(r.Form["username"], "")
var partname = strings.Join(r.Form["password"], "")
db, err := sql.Open("mysql", "root:123456@/test?charset=utf8")
checkErr(err)
if sename != "" && partname != "" {
var uid int
var username string
var password string
//参数查询在一定程度上防止sql注入,参数化查询主要做了两件事:
//1.参数过滤;2.执行计划重用
//因为执行计划被重用,所以可以防止SQL注入。
err := db.QueryRow("SELECT * FROM userinfo WHERE username = ? AND password = ?", sename, partname).
Scan(&uid, &username, &password)
//判断返回的数据是否为空
if err == sql.ErrNoRows {
fmt.Fprintf(w, "无该用户数据")
} else {
if (sename == username) && (partname == password) {
fmt.Println(uid)
fmt.Println(username)
fmt.Println(password)
t, _ := template.ParseFiles("D:/Golang/GoItem/go_ex/goSQL/success.html")
t.Execute(w, nil)
}
}
} else if sename == "" || partname == "" {
fmt.Fprintf(w, "错误,输入不能为空!")
} } } func checkErr(err error) {
if err != nil {
panic(err)
}
} func main() {
http.HandleFunc("/login", login) //设置访问的路由
err := http.ListenAndServe(":9090", nil) //设置监听的端口
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}

四、SQL注入判断

执行登录查询的数据库语句:"SELECT * FROM userinfo WHERE username ='"+sename+"'AND password ='"+partname+"'"

当查询到数据表中存在同时满足 username 和 password 字段时,会返回用户信息。 尝试在用户名中输入 123' or 1=1 #, 密码同样输入 123' or 1=1 # ,实际执行的SQL语句是select * from users where username='123' or '1'='1' and password='123' or '1'='1

则会出现一个空白页面,其实此时SQl注入已经绕过验证进入到需要身份验证的页面。

而如果执行"SELECT * FROM userinfo WHERE username = ? AND password = ?", sename, partname

再次输入123' or 1=1 #,则会被拦截下来,显示无该用户数据

五、为什么参数化查询会防止SQL注入

我们需要知道参数化查询都做了些什么事:

1.参数过滤

2.执行计划重用

它的原理是采用了预编译的方法,先将SQL语句中可被客户端控制的参数集进行编译,生成对应的临时变量集,再使用对应的设置方法,为临时变量集里面的元素进行赋值,而QueryRow()方法会对传入参数进行强制类性检查和安全检查,所以就避免了SQL注入的产生。

QueryRow("SELECT * FROM userinfo WHERE username = ? AND password = ?", sename, partname).
Scan(&uid, &username, &password)

Go语言SQL注入和防注入的更多相关文章

  1. 万能写入sql语句,并且防注入

    通过perpare()方法和检查字段防sql注入. $pdo=new PDO('mysql:host=localhost;dbname=scms', 'root' ); $_POST=array('t ...

  2. SQL防注入程序

    1.在Global.asax.cs中写入: protected void Application_BeginRequest(Object sender,EventArgs e){      SqlIn ...

  3. SQL防注入程序 v1.0

    /// ***************C#版SQL防注入程序 v1.0************ /// *使用方法: /// 一.整站防注入(推荐) /// 在Global.asax.cs中查找App ...

  4. PHP之SQL防注入代码集合(建站常用)

    SQL防注入代码一 <?php if (!function_exists (quote)) { function quote($var) { if (strlen($var)) { $var=! ...

  5. mybatis 的sql语句及使用mybatis的动态sql mybatis防注入

    由于看到写的比较详细的文档这里将之前的删掉了,只留下一些我认为能帮助理解的和关于动态sql及防注入的一些理解.文档链接  :mybatis官方文档介绍 <!-- 根据条件查询用户 --> ...

  6. sql 防注入 维基百科

    http://zh.wikipedia.org/wiki/SQL%E8%B3%87%E6%96%99%E9%9A%B1%E7%A2%BC%E6%94%BB%E6%93%8A SQL攻击(SQL inj ...

  7. 特殊字符的过滤方法,防sql防注入代码的过滤方法

    特殊字符的过滤方法 function strFilter($str){ //特殊字符的过滤方法 $str = str_replace('`', '', $str); $str = str_replac ...

  8. PHP SQL防注入

    过年前后在做一个抽奖的东西,需要用户填写中奖信息,为了防止非法用户对数据库进行入侵神马的,于是写下基本的防注入语句,需要用的可以自己封装成一个function. $str = str_replace( ...

  9. 简单实用的PHP防注入类实例

    这篇文章主要介绍了简单实用的PHP防注入类实例,以两个简单的防注入类为例介绍了PHP防注入的原理与技巧,对网站安全建设来说非常具有实用价值,需要的朋友可以参考下   本文实例讲述了简单实用的PHP防注 ...

随机推荐

  1. CodeSign error: no provisioning profile at path '/Users/zhht-2015/Library/MobileDevice/Provisioning Profiles/79693141-f98b-4ac4-8bb4-476c9475f265.mobileprovision'

    解决方法: 1.关闭Xcode,找到项目中的**.xcodeproj文件,点击右键,show package contents(打开包内容). 2.打开后找到project.pbxproj文件,用文本 ...

  2. 你在使用什么 Redis 客户端工具?

    今天发现一个不错的 Redis 客户端工具:AnotherRedisDesktopManager. 兼容 Windows Mac Linux,号称又快又稳定,加载大量 keys 时也不会崩溃. Git ...

  3. Java入门 - 语言基础 - 13.Character类

    原文地址:http://www.work100.net/training/java-character.html 更多教程:光束云 - 免费课程 Character类 序号 文内章节 视频 1 概述 ...

  4. colab上基于tensorflow2.0的BERT中文多分类

    bert模型在tensorflow1.x版本时,也是先发布的命令行版本,随后又发布了bert-tensorflow包,本质上就是把相关bert实现封装起来了. tensorflow2.0刚刚在2019 ...

  5. C入门题目

    37. 反转一个3位整数 反转一个只有3位数的整数. 样例 样例 1: 输入: number = 123 输出: 321 样例 2: 输入: number = 900 输出: 9 注意事项 你可以假设 ...

  6. 深入浅出WPF笔记

    数据层(Database,Oracle等) 业务逻辑层(Service,Data Access Layer,WCF) 表示层(WPF,Win Form,ASP.net,Silverlight) [WP ...

  7. 异想家Golang学习笔记

    1. 简介 官网:https://golang.google.cn/ 2. 编译器.工具链 编译 go build .\demo.go 编译和执行指令合二为一 go run demo.go 3. 注释 ...

  8. Mondriaan's Dream 轮廓线DP 状压

    Mondriaan's Dream 题目链接 Problem Description Squares and rectangles fascinated the famous Dutch painte ...

  9. PMP——项目管理的价值观与方法论

    关于项目管理的十个成语: 未雨绸缪(计划.风险):识别风险.做出计划.并指定负责人: 防微杜渐(监控.纠正):持续的实时的监控计划,监控和发现偏差,并进行纠正: 资源集成(整合.采购):把最专业的资源 ...

  10. SpringCloud与微服务Ⅲ --- SpringCloud入门概述

    一. 什么是SpringCloud SpringCloud基于SpringBoot提供了一套微服务解决方案,包括服务注册与发现,配置中心,全链路监控,服务网关,负载均衡,熔断器等组件,除了基于NetF ...