sql注入:
所謂sql注入,就是經過把sql命令插入到表單中或頁面請求的查詢字符串中,最終達到欺騙服務器執行惡意的sql命令。具體來講,它是利用現有的應用程序,將(惡意的)sql命令注入到後臺數據庫引擎執行的能力,它也能夠經過在Web表單中輸入(惡意)SQL語句獲得一個存在安全漏洞的網站上的數據庫,而不是按照設計者的意圖去執行sql語句。好比先前的不少影視網站泄露VIP會員密碼大多數就是經過Web表單遞交查詢字符串爆出的。
(1)如今咱們有一個sql_user表,表結構以下:
from django.db import models
from django.core import validators
class User(models.Model):
username = models.CharField(max_length=20)
password = models.CharField(max_length=24)
telephone = models.CharField(max_length=11, validators=[validators.RegexValidator(r"1[345678]\d{9}")])
class Meta:
db_table = 'sql_user'
(2)而後咱們使用原生sql語句實現如下需求:
(1)實現一個根據用戶id獲取用戶詳情的視圖,示例代碼以下:
from django.http import HttpResponse
from django.db import connection
from django.shortcuts import render
def index(request):
cursor = connection.cursor()
user_id = request.GET.get('id')
context = {}
if user_id:
cursor.execute("select id,username from sql_user where id=%s"%user_id)
users = cursor.fetchall()
for user in users:
print(user)
context['users'] = users
return render(request, 'sql.html', context=context)
else:
return HttpResponse('該用戶不存在!!!')
(2)正常狀況,用戶可使用查詢字符串的形式訪問該網頁,而且查詢用戶的詳情,能夠輸入:http://127.0.0.1:8000/sql/?id=2, 這樣的話,就會返回給用戶數據庫中id爲2的用戶詳情。但是,若是用戶在這個時候,進行sql注入,好比,輸入:http://127.0.0.1:8000/sql/?id=2 or 1=1,很顯然,1=1這樣的條件是永遠爲True的,這樣的話,就會返回給用戶數據庫中存在的全部用戶的數據,就會形成用戶信息的泄露。
(3)根據用戶名提取用戶相關的信息,示例代碼以下:
from django.http import HttpResponse
from django.db import connection
from django.shortcuts import render
def index(request):
cursor = connection.cursor()
username = request.GET.get('username')
context = {}
if username:
cursor.execute("select id, username from sql_user where username='%s'"%username)
users = cursor.fetchall()
for user in users:
print(user)
context['users'] = users
return render(request, 'sql.html', context=context)
else:
context['users'] = '您輸入的用戶不存在!'
return render(request, 'sql.html', context=context)
注意,若是在執行sql語句的時候沒有在%s兩邊用單引號包裹,那麼在輸入url的時候必定要將username對應的值加上單引號http://127.0.0.1:8001/sql/?username='孤煙逐雲',否者的話,會報錯:「OperationalError at /sql/(1054, "Unknown column '孤煙逐雲' in 'where clause'")」。可是,若是咱們在執行sql語句的時候,在%s兩邊加上單引號,那麼在url中輸入查詢字符串的時候,就不用加單引號了。
正常狀況下,咱們應該輸入:http://127.0.0.1:8001/sql/?username=孤煙逐雲 ,網頁就會返回給咱們查詢到的用戶的詳情。可是,若是咱們不遵循設計者的意願,輸入http://127.0.0.1:8001/sql/?username=孤煙逐雲' or '1=1很顯然,這個結果永遠爲True 。那麼,就會給用戶返回數據庫中全部的用戶信息,而且此時無論你輸入的username是否存在數據庫中,也無論你後面輸入的是1=4仍是1=3都會返回數據庫中全部的信息。其實此時已經破壞了網頁的結構。
sql注入防護:
經過傳遞一些惡意代碼來破壞原有的sql語句以便達到本身的目的。那麼咱們該如何防護sql注入呢? 歸類起來主要有如下幾點:
(1)永遠不要信任用戶的輸入。對用戶的輸入進行校驗,能夠經過正則表達式,或限制長度,對單引號和雙引號進行轉換等。
(2)永遠不要使用動態拼接sql,可使用參數化的sql或者直接使用存儲過程進行數據查詢存取,好比:
sql = "select id, username from sql_user where username=%s"
cursor.execute(sql, (username,))
<!--參數化的形式execute(sql語句,(參數,)),其中參數後面的逗號表示execute()傳入的是一個元組。-->
(3)永遠不要使用管理員權限的數據庫鏈接,爲每一個應用使用單獨的權限有限的數據庫鏈接。
(4)不要把機密信息直接存放,加密或者hash掉密碼和敏感的信息。
(5)應用的異常信息應該給出儘量少的提示,最好使用自定義的錯誤信息對原始信息進行包裝。
在Django中如何防護sql注入:
(1)使用ORM來作數據的增刪改查,由於ORM使用的是參數化的形式執行sql語句。
(2)若是要執行原生sql語句,那麼建議不要使用拼接的sql,而是使用參數化的形式。