网络安全篇(数据表单的创建 SQL命令拾遗 数据的SQL注入的防护)

SQL注入五孔不入,尽管是老技术了,但是依然是重点防护的手段,更多的需要我们数据库开发者细心!!
数据表的演练

1 创建数据表

create database jing_dong charset=utf8;
-- 使用 jing_dong数据库
use jing_dong;
create table goods(
    id int unsigned primary key auto_increment not null,
    name varchar(150) not null,
    cate_name varchar(40) not null,
    brand_name varchar(40) not null,
    price decimal(10,3) not null default 0,
    is_show bit not null default 1,
    is_saleoff bit not null default 0
);
-- 展示数据库
show tables;
-- 插入数据
INSERT INTO `goods` VALUES (1, '联想(Lenovo)天逸510S 个人商务台式机电脑整机(i3-10100 8G 512G', '笔记本', '华硕', 2324.000, b'0', b'0');
INSERT INTO `goods` VALUES (2, '戴尔dell成就3690 商用办公台式机电脑主机(11代i5-11400 16G', '笔记本', '联想', 4234.000, b'0', b'0');
INSERT INTO `goods` VALUES (3, '联想(Lenovo)天逸510S 个人商务台式机电脑整机(i5-10400 16G 1T+256G SSD', '游戏本', '索尼', 2342.000, b'0', b'0');
INSERT INTO `goods` VALUES (4, '武极天机 i5 10400F/GTX1050Ti/游戏台式办公电脑主', '超极本', '苹果', 4655.000, b'0', b'0');
INSERT INTO `goods` VALUES (5, '荣耀笔记本 MagicBook X 14 2021 14英寸全面屏轻薄笔记本电脑 (i3 10110U 8GB', '笔记本', '苹果', 1233.000, b'0', b'0');
INSERT INTO `goods` VALUES (6, '戴尔Dell成就3000 办公商用家用台式机电脑英特尔十代处理器学习财务', '平板电脑', '戴尔', 3434.000, b'0', b'0');
INSERT INTO `goods` VALUES (7, '戴尔笔记本电脑dell灵越15-3501 15.6英寸高性能轻薄商务笔记本电脑(11代英特', '台式机', '华硕', 2344.000, b'0', b'0');
INSERT INTO `goods` VALUES (8, '联想(Lenovo)扬天M4000q英特尔酷睿i3 商用台式机电脑整机(i3-10100', '平板电脑', '联想', 4543.000, b'0', b'0');
INSERT INTO `goods` VALUES (9, '联想ThinkPad E15 2021款 酷睿版 英特尔酷睿i5/i7 轻薄笔记本电脑 人', '台式机', '苹果', 3455.000, b'0', b'0');
INSERT INTO `goods` VALUES (10, '硕扬 i5 10400F/八核/GTX1050TI 4G/32G内存游戏台式吃鸡', '台式机', '索尼', 2455.000, b'0', b'0');
INSERT INTO `goods` VALUES (11, '惠普(HP)小欧高清一体机电脑21.5英寸(J4025 4G 256SSD UMA 无线', '笔记本', '华硕', 7899.000, b'0', b'0');

-- 查询为超极本的商品
select *from goods where cate_name="超极本";

-- 但是我只想看商品品名称和价格
select name,price from goods where cate_name="超极本";

-- 但是我不认识英文怎么办,设置一个中文的对话框
select name as 名字,price as 价格 from goods where cate_name="超极本";

-- 显示商品种类
select name,cate_name from goods;

-- 我想看所有的电脑的分类,全部类别用distinct进行实现
select distinct cate_name from goods;

-- 我想看所有的电脑的分类,用分组来进行实现
select cate_name from goods group by cate_name;

-- 我想看电脑的分类并且要加上名字,用分组来进行实现
select cate_name,group_concat(name) from goods group by cate_name;

-- 求所有电脑产品的平均价格
select avg(price) from goods;

-- 求所有电脑产品的平均价格,并保留两位小数
select round(avg (price),2) from goods;

-- 显示每种类别商品的平均价格
select cate_name ,avg(price) from goods group by cate_name;

-- 查询每种类型的商品中最贵的,最便宜的,平均价,数量
select cate_name, max(price) ,min(price) ,avg(price),count(*) from goods group by cate_name;

-- 查询所有价格大于平均价格的商品,并且按价格降序排序
select id,name,price from goods where price> (select round (avg(price),2) as avg_price from goods) order by price desc;

-- 查询每种商品中最贵的电脑信息
select * from goods 
inner join(
    select
	cate_name,
	max(price) as max_price,
    min(price) as min_price,
	avg(price) as avg_price,
	count(*) from goods group by cate_name 
    )
    as goods_new_info
on goods.cate_name=goods_new_info.cate_name and goods.price=goods_new_info.max_price;
-- 思路,把第一次上面的查询语句看作一个表,用下面的检索条件进行适配,名字相等 价格相等,那么就直接输出出来,相当于两张表合并查询
-- 或者也可以有这种写法(表级的查询)
select *from
	(select cate_name,max(price) as max_price from goods group by cate_name	)
	as g_new
left join goods as g
on g_new.cate_name =g.cate_name and g_new.max_price =g.price;

最后一个的输出结果为:

+----+----------------------------------------------------------------------+-----------+------------+----------+---------+------------+-----------+-----------+-----------+--------------+----------+
| id | name                                                                 | cate_name | brand_name | price    | is_show | is_saleoff | cate_name | max_price | min_price | avg_price    | count(*) |
+----+----------------------------------------------------------------------+-----------+------------+----------+---------+------------+-----------+-----------+-----------+--------------+----------+
|  3 | 联想(Lenovo)天逸510S 个人商务台式机电脑整机(i5-10400 16G 1T+256G SSD | 游戏本    | 索尼       | 2342.000 |         |            | 游戏本    |  2342.000 |  2342.000 | 2342.0000000 |        1 |
|  4 | 武极天机 i5 10400F/GTX1050Ti/游戏台式办公电脑主                      | 超极本    | 苹果       | 4655.000 |         |            | 超极本    |  4655.000 |  4655.000 | 4655.0000000 |        1 |
|  8 | 联想(Lenovo)扬天M4000q英特尔酷睿i3 商用台式机电脑整机(i3-10100       | 平板电脑  | 联想       | 4543.000 |         |            | 平板电脑  |  4543.000 |  3434.000 | 3988.5000000 |        2 |
|  9 | 联想ThinkPad E15 2021款 酷睿版 英特尔酷睿i5/i7 轻薄笔记本电脑 人     | 台式机    | 苹果       | 3455.000 |         |            | 台式机    |  3455.000 |  2344.000 | 2751.3333333 |        3 |
| 11 | 惠普(HP)小欧高清一体机电脑21.5英寸(J4025 4G 256SSD UMA 无线         | 笔记本    | 华硕       | 7899.000 |         |            | 笔记本    |  7899.000 |  1233.000 | 3922.5000000 |        4 |
+----+----------------------------------------------------------------------+-----------+------------+----------+---------+------------+-----------+-----------+-----------+--------------+----------+

查询各个电脑种类的最大价格

select cate_name ,max(price) from goods group by cate_name;

数据库高级演练 拆分为多个表

-- 创建商品分类
create table if not exists goods_cates(
    id int unsigned primary key auto_increment,
    name varchar(48) not null
);

-- 查看之前的goods表单中的所有分类
select cate_name from goods group by cate_name;

--将分组结果写入goods_cates 数据表中

insert into goods_cate(name) select cate_name from goods group by cate_name;

-- 同步表数据 通过goods_cates 数据表来更新goods表  更新goods 中的cate_name用第二张表来进行更新 
update goods as g inner join goods_cates as c on g.cate_name=c.name set g.cate_name =c.id;

-- 我们发现主键的goods与goods_cates类型并不是一样的,这里我们就需要改变一下类型
alter table goods change cate_name cate_id int unsigned not null;

-- 插入关联,将cate_id 追加约束外键
alter table goods add foreign key(cate_id)  references goods_cates(id);

-- 如何取消外键
alter table goods drop foreign key 外键名称;

pymysql 连接的过程

开始 ==> 创建connection > 获取cursor (游标对象)> 执行查询 执行命令 获取数据 处理数据 ==> 关闭cursor ==> 关闭 connection ==> 结束

import pymysql
#创建connect链接数据库
connect = pymysql.connect(host="localhost",port=3306,user='root',password='200228',database='jing_dong',charset='utf8')
#获得游标对象 cursor
cs1= connect.cursor()
#执行SQL语句中的select 并返回受影响的行数,查找一条数据
count =cs1.execute('select id,name from goods where id>=4')
print(count)
for i in range(count):
    #获取查询结果
    result = cs1.fetchone()
    #打印查询的结果
    print(result)
#关闭cursor对象
cs1.close()
#关闭连接
connect.close()

当我们的游标可以取到商品后,我们也可以取一下数据 信息,

cs1.fetchone() 取一个 cs1.fetchmany() 去多个

cs1.fetchall() 取所有的数据

fetchone等函数因为链接的是游标,因此,再没关闭连接和游标对象时,是按照前面执行的那步接着往下执行的

我们也可以通过定义后再进行取值

line_content = cs1.fetchone()
for temp in line_content:
    print(temp)

#如果要是用fetchmany来进行查看的时候,就是元组套元组来进行显示
#这个的意思就是取五条数据
lines = cs1.fetchmany(5)
print(lines)

工程案例:

开发一款可以方便于京东商品查询的脚本,需使用面向对象开发;实现可查看数据库内所有商品 所有商品的分类 所有商品的品牌分类

from pymysql import connect
class JD(object):
    def __init__(self):
        # 初始化创建connection连接
        self.conn = connect(host="localhost", port=3306, user='root', password='200228', database='jing_dong',
                            charset='utf8')
        # 创建游标对象
        self.cs1 = self.conn.cursor()

    def __del__(self):
        self.cs1.close()
        self.conn.close()

    def execute_sql(self, sql):
        """
        :param sql: 传入sql数据,无需每次连接后断开
        """
        self.cs1.execute(sql)
        for temp in self.cs1.fetchall():
            print(temp)

    def show_all_intem(self):
        """显示所有的商品"""
        # 创建connection连接
        sql = "select *from goods;"
        self.execute_sql(sql)

    def show_cates(self):
        sql = "SELECT name FROM goods_cates"
        self.execute_sql(sql)

    def show_brand(self):
        sql = "SELECT name FROM goods_brands;"
        self.execute_sql(sql)

    @staticmethod
    def print_menu():
        """
        使用实例方法,全局调用
        :return: 返回的值传入下一个即将调用的函数中
        """
        print("----京东-----")
        print("1:所有的商品")
        print("2:所有的商品分类")
        print("3:所有的商品品牌分类")
        num = input("请输入功能对应的序号:")
        # 这里切记,一定要return返回值
        return num

    def run(self):
        while True:
            num = self.print_menu()
            if num == "1":
                # 查询所有商品
                self.show_all_intem()
            elif num == "2":
                # 查询分类
                self.show_cates()
            elif num == "3":
                # 查询品牌
                self.show_brand()
            else:
                print("输入有误,请重新输入....")


def main():
    # 1. 创建一个京东商城的对象
    jd = JD()
    # 2. 调用这个对象的run 方法,让其运行
    jd.run()


if __name__ == '__main__':
    main()

pymysql增删改查:实质上都是一样的,唯一不一样的就是最后一个需要提交 通过使用 commit 方法

插入数据:

from pymysql import connect

conn = connect(host="localhost", port=3306, user='root', password='200228', database='jing_dong',
               charset='utf8')
# 创建游标对象
cs1 = conn.cursor()
sql = "insert into goods_cates(name) VALUES ('硬盘_new')"
cs1.execute(sql)
#无论是更新还是删除,必须要commit提交一下数据库
conn.commit()
cs1.close()
conn.close()

实现数据的插入

from pymysql import connect


class JD(object):
    def __init__(self):
        # 初始化创建connection连接
        self.conn = connect(host="localhost", port=3306, user='root', password='200228', database='jing_dong',
                            charset='utf8')
        # 创建游标对象
        self.cs1 = self.conn.cursor()

    def __del__(self):
        self.cs1.close()
        self.conn.close()

    def execute_sql(self, sql):
        """
        :param sql: 传入sql数据,无需每次连接后断开
        """
        self.cs1.execute(sql)
        for temp in self.cs1.fetchall():
            print(temp)

    def show_all_intem(self):
        """显示所有的商品"""
        # 创建connection连接
        sql = "select *from goods;"
        self.execute_sql(sql)

    def show_cates(self):
        sql = "SELECT name FROM goods_cates"
        self.execute_sql(sql)

    def show_brand(self):
        sql = "SELECT name FROM goods_brand;"
        self.execute_sql(sql)

    def add_menu(self):
        item_name =input("请输入新商品分类名称")
        sql ="""insert into goods_brand(name) VALUES("%s") """ %item_name
        self.execute_sql(sql)
        #更新创建数据表单,实现数据的更新
        self.conn.commit()

    @staticmethod
    def print_menu():
        """
        使用实例方法,全局调用
        :return: 返回的值传入下一个即将调用的函数中
        """
        print("----京东-----")
        print("1:所有的商品")
        print("2:所有的商品分类")
        print("3:所有的商品品牌分类")
        print("4:插入商品品牌")
        num = input("请输入功能对应的序号:")
        # 这里切记,一定要return返回值
        return num

    def run(self):
        while True:
            num = self.print_menu()
            if num == "1":
                # 查询所有商品
                self.show_all_intem()
            elif num == "2":
                # 查询分类
                self.show_cates()
            elif num == "3":
                # 查询品牌
                self.show_brand()
            elif num == "4":
                # 插入数据
                self.add_menu()
            else:
                print("输入有误,请重新输入....")


def main():
    # 1. 创建一个京东商城的对象
    jd = JD()
    # 2. 调用这个对象的run 方法,让其运行
    jd.run()


if __name__ == '__main__':
    main()

SQL注入:

什么是SQL注入,在数据库没有超级管理员的权限时,我们通过一些奇怪的命令也可以获取到数据表单

-- 输入5之后 可以通过这条命令获取到全部的信息
-- select * from goods where name =''or 1=1 or'';
'or 1=1 or'

输出

----->select * from goods where name =''or 1=1 or'';ql<------
(1, '联想(Lenovo)天逸510S 个人商务台式机电脑整机(i3-10100 8G 512G', 4, '华硕', Decimal('2324.000'), b'\x00', b'\x00')
(2, '戴尔dell成就3690 商用办公台式机电脑主机(11代i5-11400 16G', 4, '联想', Decimal('4234.000'), b'\x00', b'\x00')
(3, '联想(Lenovo)天逸510S 个人商务台式机电脑整机(i5-10400 16G 1T+256G SSD', 3, '索尼', Decimal('2342.000'), b'\x00', b'\x00')
(4, '武极天机 i5 10400F/GTX1050Ti/游戏台式办公电脑主', 5, '苹果', Decimal('4655.000'), b'\x00', b'\x00')
(5, '荣耀笔记本 MagicBook X 14 2021 14英寸全面屏轻薄笔记本电脑 (i3 10110U 8GB', 4, '苹果', Decimal('1233.000'), b'\x00', b'\x00')
(6, '戴尔Dell成就3000 办公商用家用台式机电脑英特尔十代处理器学习财务', 2, '戴尔', Decimal('3434.000'), b'\x00', b'\x00')
(7, '戴尔笔记本电脑dell灵越15-3501 15.6英寸高性能轻薄商务笔记本电脑(11代英特', 1, '华硕', Decimal('2344.000'), b'\x00', b'\x00')
(8, '联想(Lenovo)扬天M4000q英特尔酷睿i3 商用台式机电脑整机(i3-10100', 2, '联想', Decimal('4543.000'), b'\x00', b'\x00')
(9, '联想ThinkPad E15 2021款 酷睿版 英特尔酷睿i5/i7 轻薄笔记本电脑 人', 1, '苹果', Decimal('3455.000'), b'\x00', b'\x00')
(10, '硕扬 i5 10400F/八核/GTX1050TI 4G/32G内存游戏台式吃鸡', 1, '索尼', Decimal('2455.000'), b'\x00', b'\x00')
(11, '惠普(HP)小欧高清一体机电脑21.5英寸(J4025 4G 256SSD UMA 无线', 4, '华硕', Decimal('7899.000'), b'\x00', b'\x00')

我们如何做到用更安全的方式防护SQL注入呢

#安全的方式
#构建参数列表
params =[find_name]
#执行select语句,并返回收影响的行数,查询所有数据
count =cs1.execute('select * from goods where name=%s',params)
#注意 如果有多个参数,需要进行参数化,那么params=[数值1,数值2....] ,此时sql语句中有多个%s即可
#打印受影响的行数
print(count)

防止SQL注入代码:

from pymysql import connect


class JD(object):
    def __init__(self):
        # 初始化创建connection连接
        self.conn = connect(host="localhost", port=3306, user='root', password='200228', database='jing_dong',
                            charset='utf8')
        # 创建游标对象
        self.cs1 = self.conn.cursor()

    def __del__(self):
        self.cs1.close()
        self.conn.close()

    def execute_sql(self, sql):
        """
        :param sql: 传入sql数据,无需每次连接后断开
        """
        self.cs1.execute(sql)
        for temp in self.cs1.fetchall():
            print(temp)

    def show_all_intem(self):
        """显示所有的商品"""
        # 创建connection连接
        sql = "select *from goods;"
        self.execute_sql(sql)

    def show_cates(self):
        sql = "SELECT name FROM goods_cates"
        self.execute_sql(sql)

    def show_brand(self):
        sql = "SELECT name FROM goods_brand;"
        self.execute_sql(sql)

    def add_menu(self):
        item_name =input("请输入新商品分类名称")
        sql ="""insert into goods_brand(name) VALUES("%s") """ %item_name
        self.execute_sql(sql)
        #更新创建数据表单,实现数据的更新
        self.conn.commit()
    def get_info_by_name(self):
        find_name = input("请输入要查询的商品名字:")
        sql = "select * from goods where name= %s"
        self.cs1.execute(sql,[find_name])
        print(self.cs1.fetchall())
    @staticmethod
    def print_menu():
        """
        使用实例方法,全局调用
        :return: 返回的值传入下一个即将调用的函数中
        """
        print("----京东-----")
        print("1:所有的商品")
        print("2:所有的商品分类")
        print("3:所有的商品品牌分类")
        print("4:插入商品品牌")
        print("5:根据名字查询一个商品")
        num = input("请输入功能对应的序号:")
        # 这里切记,一定要return返回值
        return num

    def run(self):
        while True:
            num = self.print_menu()
            if num == "1":
                # 查询所有商品
                self.show_all_intem()
            elif num == "2":
                # 查询分类
                self.show_cates()
            elif num == "3":
                # 查询品牌
                self.show_brand()
            elif num == "4":
                # 插入数据
                self.add_menu()
            elif num == "5":
                #根据名字查询商品
                self.get_info_by_name()
            else:
                print("输入有误,请重新输入....")


def main():
    # 1. 创建一个京东商城的对象
    jd = JD()
    # 2. 调用这个对象的run 方法,让其运行
    jd.run()


if __name__ == '__main__':
    main()

写在最后:
SQL注入的防治之一,只有唯一的方法,千万不要自己去拼接,而是我们需要用pymysql自带的函数来进行进一步拼接,这边的话我们要更多的使用 execute 来进行安全防护

我们设想一下,查询可以通过 'or 1=1'来进行查看的,我们仅仅是通过查看,走更危险的一步 如果要是 删除呢(手动滑稽) drop table message 哈哈哈这就有意思了,未来可能面临三餐管饭了,乌云网被封了,如果要是能看到更多安全渗透可以学到更多的安全防护知识。网络安全固然有意思,千万不要上头,SQL注入尽管已经很老了,但是有矛就一定有盾,天下没有不透风的墙,最笨的方法我们可以一点点去试,总会有更多的漏洞等着我们去发现,初学者千万不要以身试法,不要去试探底线!!! 通过非法途径获取50+用户的信息就可以管饭了。。。。希望大家的技术越来越强!!!!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学成七步

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值