pymysql模塊使用介紹


pymysql

​ 我們要學的pymysql就是用來在python程序中如何操作mysql,本質上就是一個套接字客戶端,只不過這個套接字客戶端是在python程序中用的,既然是客戶端套接字,應該怎么用,是不是要連接服務端,並且和服務端進行通信啊,讓我們來學習一下pymysql這個模塊

安裝

pip3 install pymysql

使用

我們通過一個登陸認證,也就是驗證用戶名和密碼是否在用戶表中存在來使用一下pymysql

首先我們創建一個用戶表,名為userinfo表,其中有用戶名(name)和密碼字段(password),然后在表中存放一些數據。

然后在我們的python腳本中寫上以下內容,就可以完成我們的登陸認證了

import pymysql
user=input('用戶名: ').strip()
pwd=input('密碼: ').strip()

#鏈接,指定ip地址和端口,本機上測試時ip地址可以寫localhost或者自己的ip地址或者127.0.0.1,然后你操作數據庫的時候的用戶名,密碼,要指定你操作的是哪個數據庫,指定庫名,還要指定字符集。不然會出現亂碼
conn=pymysql.connect(host='localhost',port=3306,user='root',password='123',database='student',charset='utf8') 

cursor=conn.cursor() #這就想到於mysql自帶的那個客戶端的游標mysql> 在這后面輸入指令,回車執行

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

res=cursor.execute(sql) #執行sql語句,返回sql查詢成功的記錄數目,是個數字,是受sql語句影響到的記錄行數
#all_data=cursor.fetchall()  #獲取返回的所有數據,注意凡是取數據,取過的數據就沒有了,結果都是元祖格式的
#many_data=cursor.fetchmany(3) #一下取出3條數據,
#one_data=cursor.fetchone()  #按照數據的順序,一次只拿一個數據,下次再去就從第二個取了,因為第一個被取出去了,取一次就沒有了,結果也都是元祖格式的
if res:
    print('登錄成功')
else:
    print('登錄失敗')

cursor.close() #關閉游標
conn.close()   #關閉連接

sql注入

所謂sql注入,就是通過將一些特殊符號寫入到我們的sql語句中,使我們的sql語句失去了原有的作用。比如繞開我們的認證機制,在不知道用戶名和密碼的情況下完成登錄。

基於上一節的示例,我們看一下sql注入怎么搞事情的。

以下還是上述示例的代碼

import pymysql

conn = pymysql.connect(
    host='127.0.0.1',
    port=3306,
    user='root',
    password='666',
    database='crm',
    charset='utf8'
)

cursor = conn.cursor(pymysql.cursors.DictCursor)
uname = input('請輸入用戶名:')
pword = input('請輸入密碼:')

sql = "select * from userinfo where username='%s' and password='%s';"%(uname,pword)

res = cursor.execute(sql) #res我們說是得到的行數,如果這個行數不為零,說明用戶輸入的用戶名和密碼存在,如果為0說名存在,你想想對不

print(res) #如果輸入的用戶名和密碼錯誤,這個結果為0,如果正確,這個結果為1
if res:
    print('登陸成功')
else:
    print('用戶名和密碼錯誤!')

但是我們來看下面的操作,如果將在輸入用戶名的地方輸入一個 chao'空格然后--空格然后加上任意的字符串,就能夠登陸成功,也就是只知道用戶名的情況下,他就能登陸成功的情況:

uname = input('請輸入用戶名:')
pword = input('請輸入密碼:')

sql = "select * from userinfo where username='%s' and password='%s';"%(uname,pword)
print(sql)
res = cursor.execute(sql) #res我們說是得到的行數,如果這個行數不為零,說明用戶輸入的用戶名和密碼存在,如果為0說名存在,你想想對不

print(res) #如果輸入的用戶名和密碼錯誤,這個結果為0,如果正確,這個結果為1
if res:
    print('登陸成功')
else:
    print('用戶名和密碼錯誤!')
#運行看結果:居然登陸成功
請輸入用戶名:chao' -- xxx
請輸入密碼:
select * from userinfo where username='chao' -- xxx' and password='';
1
登陸成功

我們來分析一下:

此時uname這個變量等於什么,等於chao' -- xxx,然后我們來看我們的sql語句被這個字符串替換之后是個什么樣子:
	select * from userinfo where username='chao' -- xxx' and password=''; 其中chao后面的這個',在進行字符串替換的時候,我們輸入的是chao',這個引號和前面的引號組成了一對,然后后面--在sql語句里面是注釋的意思,也就是說--后面的sql語句被注釋掉了。也就是說,拿到的sql語句是select * from userinfo where username='chao';然后就去自己的數據庫里面去執行了,發現能夠找到對應的記錄,因為有用戶名為chao的記錄,然后他就登陸成功了,但是其實他連密碼都不知道,只知道個用戶名。。。,他完美的跳過了你的認證環節。

然后我們再來看一個例子,直接連用戶名和密碼都不知道,但是依然能夠登陸成功的情況:

請輸入用戶名:xxx' or 1=1 -- xxxxxx
請輸入密碼:
select * from userinfo where username='xxx' or 1=1 -- xxxxxx' and password='';
3
登陸成功

我們只輸入了一個xxx' 加or 加 1=1 加 -- 加任意字符串
看上面被執行的sql語句你就發現了,or 后面跟了一個永遠為真的條件,那么即便是username對不上,但是or后面的條件是成立的,也能夠登陸成功。

出現這樣的問題,我們怎么解決的?通過pymysql給我們提供的execute方法可以解決,看示例:

之前我們的sql語句是這樣寫的:
sql = "select * from userinfo where username='%s' and password='%s';"%(uname,pword)

以后再寫的時候,sql語句里面的%s左右的引號去掉,並且語句后面的%(uname,pword)這些內容也不要自己寫了,按照下面的方式寫
sql = "select * from userinfo where username=%s and password=%s;"
難道我們不傳值了嗎,不是的,我們通過下面的形式,在excute里面寫參數:
#cursor.execute(sql,[uname,pword]) ,其實它本質也是幫你進行了字符串的替換,只不過它會將uname和pword里面的特殊字符給過濾掉。

看下面的例子:
uname = input('請輸入用戶名:') #輸入的內容是:chao' -- xxx或者xxx' or 1=1 -- xxxxx
pword = input('請輸入密碼:')

sql = "select * from userinfo where username=%s and password=%s;"
print(sql)
res = cursor.execute(sql,[uname,pword]) #res我們說是得到的行數,如果這個行數不為零,說明用戶輸入的用戶名和密碼存在,如果為0說名存在,你想想對不

print(res) #如果輸入的用戶名和密碼錯誤,這個結果為0,如果正確,這個結果為1
if res:
    print('登陸成功')
else:
    print('用戶名和密碼錯誤!')
#看結果:
請輸入用戶名:xxx' or 1=1 -- xxxxx
請輸入密碼:
select * from userinfo where username=%s and password=%s;
0
用戶名和密碼錯誤!

commit方法

當我們通過pymysql來執行增刪改動作的時候,需要commit以下才能生效。

sql='insert into userinfo(name,password) values(%s,%s);'
res=cursor.executemany(sql,[("root","123456"),("lhf","12356"),("eee","156")]) #執行sql語句,返回sql影響成功的行數,一次插多條記錄
print(res)
#上面的幾步,雖然都有返回結果,也就是那個受影響的函數res,但是你去數據庫里面一看,並沒有保存到數據庫里面,
conn.commit() #必須執行conn.commit,注意是conn,不是cursor,執行這句提交后才發現表中插入記錄成功,沒有這句,上面的這幾步操作其實都沒有成功保存。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM