失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 视图 触发器 函数 流程控制 存储过程 SQL注入问题

视图 触发器 函数 流程控制 存储过程 SQL注入问题

时间:2022-08-27 02:05:12

相关推荐

视图 触发器 函数 流程控制 存储过程 SQL注入问题

视图

视图就是通过查询得到一张虚拟表(非真实存在),然后保存下来,下次可以直接使用,用户使用时直接使用【视图表名】即可获取结果集。

视图有明显地效率问题,并且视图是存放在数据库中的,如果我们程序中使用的sql过分依赖数据库中的视图,即强耦合,那就意味着扩展sql极为不便,因此并不推荐使用。

使用视图的注意点:

1.创建视图在硬盘上只会有表结构,没有表数据,数据并没有存在硬盘(数据还是来自之前的表)

2.视图一般只用来查询,里面的数据不要进行修改,可能会影响真正的表

创建视图语法

create view 表名 as 虚拟表的查询语句

# 创建一张数据表

select * from employee;

+----+--------+--------+-----+------------+--------------+--------------+----------+--------+-----------+

| id | name | sex | age | hire_date | post| post_comment | salary | office | depart_id |

+----+--------+--------+-----+------------+--------------+--------------+----------+--------+-----------+

| 1 | sun | male | 18 | -03-01 | 猥琐欲为 | NULL| 1000.22 | 401 |1 |

| 2 | haha | male | 78 | -03-02 | teacher | NULL| 10000.31 | 401 |1 |

| 3 | xixi | male | 81 | -03-05 | teacher | NULL| 8300.31 | 401 |1 |

| 4 | dudu | male | 72 | -03-12 | teacher | NULL| 3100.00 | 401 |1 |

| 5 | biubiu | male | 28 | -03-18 | teacher | NULL| 5000.00 | 401 |1 |

| 6 | lala | female | 58 | -03-23 | teacher | NULL| 1020.00 | 401 |1 |

| 7 | bubu | male | 38 | -05-20 | teacher | NULL| 1501.00 | 401 |1 |

| 8 | bobo | male | 55 | -03-10 | teacher | NULL| 8222.00 | 401 |1 |

| 9 | 哈哈 | male | 48 | -03-21 | sale| NULL| 3333.00 | 402 |2 |

| 10 | 呵呵 | male | 55 | -06-20 | sale| NULL| 1050.00 | 402 |2 |

| 11 | 西西 | male | 38 | -07-20 | sale| NULL| 1200.31 | 402 |2 |

| 12 | 嘟嘟 | male | 18 | -12-01 | sale| NULL| 10011.00 | 402 |2 |

| 13 | 萌萌 | male | 38 | -05-02 | sale| NULL| 10020.00 | 402 |2 |

| 14 | 拉拉 | male | 58 | -03-25 | sale| NULL| 6250.00 | 402 |2 |

| 15 | 娜娜 | male | 18 | -03-19 | operation | NULL| 20000.00 | 403 |3 |

| 16 | 宝宝 | female | 18 | -04-05 | operation | NULL| 20000.00 | 403 |3 |

| 17 | 辣辣 | male | 18 | -03-15 | operation | NULL| 18220.00 | 403 |3 |

| 18 | 蟹蟹 | male | 18 | -03-20 | operation | NULL| 50000.00 | 403 |3 |

+----+--------+--------+-----+------------+--------------+--------------+----------+--------+-----------+

# 查看salary大于10000的虚拟表

select name,age,post from employee where salary > 10000;

+--------+-----+-----------+

| name | age | post |

+--------+-----+-----------+

| haha | 78 | teacher |

| 嘟嘟 | 18 | sale |

| 萌萌 | 38 | sale |

| 娜娜 | 18 | operation |

| 宝宝 | 18 | operation |

| 辣辣 | 18 | operation |

| 蟹蟹 | 18 | operation |

+--------+-----+-----------+

# 创建视图,将虚拟表的结果产生的表结构保存了,并没有表数据

# 每次我们使用视图的表数据,都是直接触发as后面的sql语句运行,通过查询得到的表数据

create view new_employee as select name,age,post from employee where salary > 10000;

# 查看视图数据

select * from new_employee;

+--------+-----+-----------+

| name | age | post |

+--------+-----+-----------+

| haha | 78 | teacher |

| 嘟嘟 | 18 | sale |

| 萌萌 | 38 | sale |

| 娜娜 | 18 | operation |

| 宝宝 | 18 | operation |

| 辣辣 | 18 | operation |

| 蟹蟹 | 18 | operation |

+--------+-----+-----------+

# 查看数据库指定目录下的视图数据,只有表结构

ls /service/mysql/data/db01

# new_employee.frm

# 修改视图表(本质就是修改视图as后面的sql语句规则)

alter view new_employee as select name,age from employee where id < 3;

select * from new_employee;

+------+-----+

| name | age |

+------+-----+

| sun | 18 |

| haha | 78 |

+------+-----+

# 删除视图

drop view new_employee;

触发器

使用触发器可以定制用户对表进行【增、删、改】操作时前后的行为,注意:没有查询!!!

使用触发器可以帮助我们实现监控,日志,自动处理异常等等...触发器可以在6种情况下自动触发 增前增后 删前删后 改前改后

创建触发器基本语法结构

create trigger 触发器的名字 before/after insert/update/delete 表名for each rowbegin sql语句end

触发器无法由用户直接调用,而知由于对表的【增/删/改】操作被动引发的!!!

当cmd表中的记录success字段是no那么就触发触发器去执行errlog表中插入的数据

# 创建表字段

create table cmd(

id int primary key auto_increment,

user char(32),

priv char(10),

cmd char(64),

sub_time datetime,# 提交时间

success enum("yes","no") # no代表执行失败

);

create table errlog(

id int primary key auto_increment,

err_cmd char(64),

err_time datetime

);

# 创建触发器

delimiter $$ # delimiter 声明sql语句的结束符号

# create trigger 触发器名 after insert 表名,插入表数据后被动引发触发器执行

create trigger tri_after_insert_cmd after insert on cmd

for each row

begin

if new.success = "no" then # new 指代的就是cmd表中的一条条数据对象(new.success ==> cmd.success)

insert into errlog(err_cmd,err_time) values(new.cmd,new.sub_time); # 必须加分号

end if; # 必须加分号

end $$

delimiter ; # 重新声明sql语句符号为;

# 往表cmd中插入记录,触发触发器,根据if的条件决定是否插入错误日志

insert into cmd(user,priv,cmd,sub_time,success)

values("nana","0755","is -1 /etc",now(),"yes"),

("nana","0755","cat /etc/password",now(),"no"),

("nana","0755","useradd xxx",now(),"no");

select * from cmd;

+----+------+------+-------------------+---------------------+---------+

| id | user | priv | cmd | sub_time| success |

+----+------+------+-------------------+---------------------+---------+

| 1 | nana | 0755 | is -l /etc | -07-05 22:18:01 | yes |

| 2 | nana | 0755 | cat /ect/password | -07-05 22:18:01 | no |

| 3 | nana | 0755 | useradd xxx | -07-05 22:18:01 | no |

+----+------+------+-------------------+---------------------+---------+

# 查询错误日志,发现有两条数据

select * from errlog;

+----+-------------------+---------------------+

| id | err_cmd| err_time|

+----+-------------------+---------------------+

| 1 | cat /ect/password | -07-05 22:18:01 |

| 2 | useradd xxx | -07-05 22:18:01 |

+----+-------------------+---------------------+

# 删除触发器

drop trigger tri_after_insert_cmd;

函数

函数只能在sql语句中使用,不能独立调用!!!

若要想在begin…end…中写sql,请用存储过程!!!

内置函数

- 常见的内置函数

# 查看当前登陆的用户

select user();

+----------------+

| user()|

+----------------+

| root@localhost |

+----------------+

# 查看当前时间

select now();

+---------------------+

| now() |

+---------------------+

| -07-05 22:45:03 |

+---------------------+

# 随机生成一个小数

select rand();

+--------------------+

| rand() |

+--------------------+

| 0.6458554832691843 |

+--------------------+

# 四舍五入取值,保留两位小数

select round(6.666,2);

+----------------+

| round(6.666,2) |

+----------------+

|6.67 |

+----------------+

- date_format内置函数,日期格式的拼接

# 创建表格

create table blog(

id int primary key auto_increment,

name char(32),

sub_time datetime

);

# 插入数据

insert into blog(name,sub_time) values

('1','-03-01 11:31:21'),

('2','-03-11 16:31:21'),

('3','-07-01 10:21:31'),

('4','-07-22 09:23:21'),

('5','-07-23 10:11:11'),

('6','-07-25 11:21:31'),

('7','-03-01 15:33:21'),

('8','-03-01 17:32:21'),

('9','-03-01 18:31:21');

# 查看表的数据

select * from blog;

+----+------+---------------------+

| id | name | sub_time|

+----+------+---------------------+

| 1 | 1 | -03-01 11:31:21 |

| 2 | 2 | -03-11 16:31:21 |

| 3 | 3 | -07-01 10:21:31 |

| 4 | 4 | -07-22 09:23:21 |

| 5 | 5 | -07-23 10:11:11 |

| 6 | 6 | -07-25 11:21:31 |

| 7 | 7 | -03-01 15:33:21 |

| 8 | 8 | -03-01 17:32:21 |

| 9 | 9 | -03-01 18:31:21 |

+----+------+---------------------+

# 提取sub_time的字段数据,格式按照"年月"来进行分组

select date_format(sub_time,"%Y-%m") "时间(年-月)",count(id) from blog group by date_format(sformat(sub_time,"%Y-%m");

+-----------------+-----------+

| 时间(年-月) | count(id) |

+-----------------+-----------+

| -03|2 |

| -07|4 |

| -03|3 |

+-----------------+-----------+

自定义函数

函数中不要写sql语句(否则会报错),函数仅仅只是一个功能,是一个在sql中被应用的功能

# delimiter 声明sql语句的结束符号

delimiter $$

# 定义一个函数f1

create function f1(

a int,

b int)

returns int

begin

declare num int;

set num = a+b;

return(num);

end$$

delimiter ;

# 调用函数

select f1(2,3);

+---------+

| f1(2,3) |

+---------+

| 5 |

+---------+

# 创建一个表

create table t1(id int);

# 调用函数在表中插入数据

mysql> insert t1 values(f1(2,3));

# 查看表数据

select * from t1;

+------+

| id |

+------+

| 5 |

+------+

# 删除自定义函数

drop function f1;

流程控制

if判断

# 定义一个if判断的存储过程

delimiter //

create procedure proc_if ()

begin

declare i int default 0;

if i = 1 then

select 1;

elseif i = 2 then

select 2;

else

select 7;

end if;

end //

delimiter ;

# 调用存储过程

call proc_if();

+---+

| 7 |

+---+

| 7 |

+---+

# 删除存储过程

drop procedure proc_if;

while循环

# 定义一个while循环的存储过程

delimiter //

create procedure proc_while ()

begin

declare num int ;

set num = 0 ;

while num < 3 do # 如果num小于3,do表示进入循环

select

num ;

set num = num + 1 ;

end while ;

end //

delimiter ;

# 调用存储过程

call proc_while();

+------+

| num |

+------+

| 0 |

+------+

+------+

| num |

+------+

| 1 |

+------+

+------+

| num |

+------+

| 2 |

+------+

# 删除存储过程

drop procedure proc_while;

存储过程

存储过程常见的三种开发模型

第一种

应用程序:程序员编写代码开发,调用存储过程

mysql:DBA提前编写好存储过程,供程序员调用

优点:开发效率提升了,执行效率也提升了 缺点:考虑到人为因素,跨部门沟通问题,后续的存储国过程扩展性差

第二种

应用程序:程序员编写开发代码,涉及到数据库操作也是自己编写sql语句

优点:扩展性很高 缺点:开发效率低,编写sql语句太过繁琐,后续还需要考虑sql优化的问题

第三种

应用程序:只写程序代码,不写sql语句,基于别人写好的框架(ORM框架)直接调用sql语句即可

优点:开发效率比上面两种情况都要高 缺点:语句扩展性差,可能会出现效率低下问题

通常情况下,我们都是用第三种开发模型,程序运行出现效率低下的问题,再手动写sql语句。

创建无参存储过程

# 定义存储过程

delimiter //

create procedure p1()

begin

select * from blog;

insert into blog(name,sub_time) values("nana",now());

end //

delimiter ;

# 在mysql中调用存储过程

call p1();

# 删除存储过程

drop procedure p1;

# 在python中基于pymysql调用

cursor.callproc('p1')

print(cursor.fetchall())

创建有参存储过程

对于存储过程,可以接收参数,其参数有三类:

in仅用于传入参数用out 仅用于返回值用inout既可以传参又可以当作返回值

in 仅用于传参

# 定义存储过程

delimiter //

create procedure p2(

in n1 int,

in n2 int

)

begin

select * from blog where id > n1;

end //

delimiter ;

# 在mysql中调用

call p2(3,2);

# 删除存储过程

drop procedure p2;

# 在python中基于pymysql调用

cursor.callproc('p2',(3,2))

print(cursor.fetchall())

out 仅用于返回值用

# 定义存储过程

delimiter //

create procedure p3(

in n1 int,

out res int

)

begin

select * from blog where id > n1;

set res = 1;

end //

delimiter ;

# 在mysql中调用存储过程

set @res=0; # 0代表假(执行失败),1代表真(执行成功)

call p3(3,@res);

select @res;

# 删除存储过程

drop procedure p3;

# 在python中基于pymysql调用

cursor.callproc('p3',(3,0)) # 0相当于set @res=0

print(cursor.fetchall()) # 查询select的查询结果

cursor.execute('select @_p3_0,@_p3_1;') # @p3_0代表第一个参数,@p3_1代表第二个参数,即返回值

print(cursor.fetchall())

inout 既可以传参又可以当作返回值

# 定义存储过程

delimiter //

create procedure p4(

inout n1 int

)

begin

select * from blog where id > n1;

set n1 = 1;

end //

delimiter ;

# 在mysql中调用存储过程

set @x=3;

call p4(@x);

select @x;

# 删除存储过程

drop procedure p4;

# 在python中基于pymysql调用

cursor.callproc('p4',(3,))

print(cursor.fetchall()) # 查询select的查询结果

cursor.execute('select @_p4_0;')

print(cursor.fetchall())

SQL注入问题

模拟sql注入问题

sql注入问题,我们可以通过特殊的符号改变sql语句的语法规则

如下所示,我们编写一个登陆功能,需要连接数据库,校验数据库的表数据,可以使用特殊的符号改变sql语句的语法规则所以市场上有一些软件,在用户注册的时候,会限制用户设置密码禁止使用一些特殊字符

1. 创建远程登陆用户,并插入用户数据

# 登陆数据库

mysql -uroot -p123

# 创建mysql用户

grant all on *.* to "nana"@"%" identified by "123";

# 刷新用户表

flush privileges;

# 创建本地用户成功之后使用ip登陆做一次测试

mysql -unana -p123 -h192.168.15.51

# 创建表格

create database db01;

use db01;

create table user(id int,name varchar(16),password varchar(32));

# 插入数据

insert user values(1,"nana","123");

insert user values(2,"haha","456");

# 查看用户表数据

mysql> select * from user;

+------+------+----------+

| id | name | password |

+------+------+----------+

| 1 | nana | 123 |

| 2 | haha | 456 |

+------+------+----------+

2. 模拟sql注入问题

# 使用pymysql模块连接登陆数据库

import pymysql

# 连接数据库

conn = pymysql.connect(

host="195.168.15.51",

port=3306,

user="nana",

password="123",

database="db01",

charset="utf8"

)

# 游标:相当于mysql> ,给mysql提供sql语句

cursor = conn.cursor()

inp_name = input("username>>>:").strip()

inp_passwd = input("password>>>:").strip()

sql = "select * from user where name ='%s' and password = '%s'" % (inp_name, inp_passwd)

print(sql)

# 将命令提交给mysql数据库进行校验

rows = cursor.execute(sql)

if rows:

print("登陆成功")

else:

print("用户名密码错误")

cursor.close() # 关闭游标

conn.close() # 断开连接

=================================================运行代码===========================================================

# sql语句-- 表示注释

username>>>:kkkk' or True -- '

password>>>:

select * from user where name ='kkkk' or True -- '' and password = '';

登陆成功

sql注入问题解决方案

方法一: 日常生活中很多软件在注册的时候禁止使用特殊符号方法二: 使用python的execute内置函数帮忙拼接,execute默认会把特殊符号自动过滤掉,如下所示

import pymysql

# 连接数据库

conn = pymysql.connect(

host="192.168.15.51",

port=3306,

user="nana",

password="123",

database="db01",

charset="utf8"

)

# 游标:相当于mysql> ,给mysql提供sql语句

cursor = conn.cursor()

inp_name = input("username>>>:").strip()

inp_passwd = input("password>>>:").strip()

# 不要手动拼接数,先用%s占位,之后将需要拼接的数据直接交给execute方法即可

sql = "select * from user where name =%s and password = %s"

print(sql)

# 将命令提交给mysql数据库进行校验

# execute:自动识别sql里面的%s然后用后面元组里面的数据替换,并且会帮你把特殊符号自动过滤掉

rows = cursor.execute(sql,(inp_name,inp_passwd))

if rows:

print("登陆成功")

else:

print("用户名或密码错误")

cursor.close() # 关闭游标

conn.close() # 断开连接

==================================================运行代码==============================================================

username>>>:kkk' or True -- '

password>>>:

select * from user where name =%s and password = %s

用户名或密码错误

如果觉得《视图 触发器 函数 流程控制 存储过程 SQL注入问题》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。