159.SQL注入的實現和防護措施

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,而是使用參數化的形式。
相關文章
相關標籤/搜索