Как избежать SQL-инъекций, если я вставляю данные из CSV-файла с переменными в Python3, Pymsql? - PullRequest
0 голосов
/ 26 апреля 2018

Мой ENV:

MySQL (mariadb) - версия БД 5.5.56

Python3 версия составляет 3,6

Положение:

У меня есть файл CSV телефонной статистики, который будет генерироваться каждый день, и мне нужно вставить эти данные в мою БД MYSQL.

Type: Extension Statistic Report,,,,,,,,
From 2018/4/17 上午 12:00:00 To 2018/4/18 上午 12:00:00
Agent Extension: Any number
,,,,,,,,
Agent Extension,,Inbound,,Outbound,,Total,,Total Talking time
,,  Answered,Unanswered,Answered,Unanswered,Answered,Unanswered,
100 MeetingRoom,,0,0,0,0,0,0,00:00:00
101 Build,,0,0,0,0,0,0,00:00:00
102 Lead,,0,0,2.00,1.00,2.00,1.00,01:36:09
103 Discover,,0,0,0,0,0,0,00:00:00
105 Fatto,,1.00,0,28.00,9.00,29.00,9.00,01:07:27
106 Meditare,,0,0,0,0,0,0,00:00:00
Total:,,122.00,41.00,152.00,49.00,274.00,90.00,10h 43m 17s

Это мой код:

import csv, sys, os
import pymysql
from datetime import datetime, timedelta

# DB Config
dbconn = pymysql.connect(host='192.168.X.X',
                     port=3306,
                     user='root',
                     passwd='********',
                     db='test',
                     charset='utf8')
cursor = dbconn.cursor()

# Get today's date.
def get_date(d):
    toDay = timedelta(days=d)
    yesDay = datetime.now() + toDay

    return yesDay.strftime("%Y%m%d")

# Get today's str value.
yesterday = get_date(-1)
beforeyesterday = get_date(-2)

with open("/Users/fiona/Downloads/statistics_1704_v1nNHbvGjnIQ2mVwsMLr.csv") as file:
readCSV = csv.reader(file)

extensionCodes = []  # Store extension Number
usersName = []  # Store User Name
inboundsAnswered = []  # Store Inbound Answered
inboundsUnanswered = []  # Store Inbound Unanswered
outboundsAnswered = []  # Store Outbound Answered
outboundsUnanswered = []  # Store Outbound Unanswered
totalsAnswered = []  # Store Total Answered
totalsUnanswered = []  # Store Total Unanswered
totalsTalkingTime = []  # Store Total Talking time

for index, rows in enumerate(readCSV):
    if index not in range(0, 7) and rows[0] != "":
        if str(rows[0])[:3] != "Tot":
            extensionCode = str(rows[0])[:3] # Store every rows extension number
        elif str(rows[0])[:5] == "Total":
            break

        userName = rows[0] # Store every rows name
        inboundAnswered = float(rows[2])
        inboundUnanswered = float(rows[3])
        outboundAnswered = float(rows[4])
        outboundUnanswered = float(rows[5])
        totalAnswered = float(rows[6])
        totalUnanswered = float(rows[7])
        totalTalkingTime = rows[8]

        sql = """
            INSERT INTO 
                test (extension_number, username, inbound_answered, inbound_unanswered, 
                outbound_answered, outbound_unanswered, total_answered, total_unanswered, 
                total_talking_time, createtime)
            VALUES
                (%d, %s, %d, %d, %d, %d, %d, %d, %s, %s); 
        """ % (int(extensionCode), "'"+userName+"'", int(inboundAnswered), int(inboundUnanswered),
               int(outboundAnswered), int(outboundUnanswered), int(totalAnswered),
               int(totalUnanswered), "'"+totalTalkingTime+"'", yesterday)

        print(sql) # Testing SQL Syntax
        cursor.execute(sql)


dbconn.commit()
cursor.close()
dbconn.close()

Используя приведенный выше код, я могу вставить свои данные в БД, но я также хочу сохранить проблему внедрения SQL Поэтому я провел некоторые исследования и изменил свой код, но все равно не смог.

  1. Лучшие и надежные методы Python для подключения к MySQL и выполнения запросов
  2. Как я могу избежать ввода в базу данных MySQL в Python3?
  3. Как использовать переменные в SQL-выражении в Python?
  4. Python MySQL Параметризованные запросы

Теперь я знаю, что если я хочу избежать внедрения SQL, я не могу использовать % для получения значений моей переменной, я должен использовать , для получения значений. Но я обнаружил, что при использовании , кажется, что значения станут str , что приведет к сбою моего% d.

Мой дизайн БД выглядит так: Изображение

Есть кто-нибудь, кто может дать мне какой-нибудь совет или направление? Спасибо за вашу помощь!

Обновление 1:

если я использую ссылку 4.

sql = """
    INSERT INTO test (extension_number, username, inbound_answered, inbound_unanswered, outbound_answered, outbound_unanswered, total_answered, total_unanswered, 
                total_talking_time, createtime)
            VALUES (%d, %s, %d, %d, %d, %d, %d, %d, %s, %s)
        """, (int(extensionCode), userName, int(inboundAnswered), int(inboundUnanswered), int(outboundAnswered), int(outboundUnanswered),
              int(totalAnswered), int(totalUnanswered), totalTalkingTime, yesterday)

будет показано:

packet = prelude + sql[:packet_size-1]
TypeError: can't concat tuple to bytes
('\n                INSERT INTO test (extension_number, username, inbound_answered, inbound_unanswered, \n                    outbound_answered, outbound_unanswered, total_answered, total_unanswered, \n                    total_talking_time, createtime)\n                VALUES (%d, %s, %d, %d, %d, %d, %d, %d, %s, %s)\n            ', (100, 'MeetingRoom', 0, 0, 0, 0, 0, 0, '00:00:00', '20180423'))

Process finished with exit code 1

Обновление 2:

Я пробовал другой способ,

sql = "INSERT INTO test (extension_number, username, inbound_answered, inbound_unanswered, " \
"outbound_answered, outbound_unanswered, total_answered, total_unanswered, total_talking_time, " \
"createtime) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)", \
     (int(extensionCode), userName, int(inboundAnswered), int(inboundUnanswered),
      int(outboundAnswered), int(outboundUnanswered), int(totalAnswered),
      int(totalUnanswered), totalTalkingTime, yesterday)

cursor.execute(sql)

но все еще не работает

   packet = prelude + sql[:packet_size-1]
   TypeError: can't concat tuple to bytes

Обновление 3:

Наконец, я выясняю путь,

sql = "INSERT INTO test (extension_number, username, inbound_answered, " \
              "inbound_unanswered, outbound_answered, outbound_unanswered, " \
              "total_answered, total_unanswered, total_talking_time, createtime) " \
              "VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"
data = (extensionCode, userName, inboundAnswered, inboundUnanswered,
                outboundAnswered, outboundUnanswered, totalAnswered,
                totalUnanswered, totalTalkingTime, yesterday)

cursor.execute(sql, data)

Итак, похоже, что если я хочу использовать переменную в cursor.execute (), мне нужно разделить синтаксис и значение sql.

Если я хочу использовать синтаксис и значение sql в одной строке, я должен использовать cursor.execute (синтаксис и значение sql) напрямую, и двойные кавычки или тройные кавычки одинаково хороши.

, таких как:

cursor.execute("""INSERT INTO test (extension_number, username, inbound_answered, inbound_unanswered, 
            outbound_answered, outbound_unanswered, total_answered, total_unanswered, total_talking_time, 
            createtime) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""",
                  (extensionCode, userName, inboundAnswered, inboundUnanswered, outboundAnswered, outboundUnanswered, totalAnswered, totalUnanswered, totalTalkingTime, yesterday))

разделяет синтаксис и значения sql или просто помещает их все вместе в cursor.execute, какой из них более безопасен?

Спасибо за ваш совет, позвольте мне найти правильное направление!

...