Тема посвящается https://lolz.live/threads/7061773/ Вступление Всем привет. Начну с небольшой предыстории. На момент жалобы я был на посту проверяющего в разделе программирования. Мне было поручено проверять выполненные тестовые задания, без которых нельзя получить префикс. При проверке учитывается несколько факторов, такие как: структура, умение пользоваться фичами языка и базовые знания работы с бд (ну и другие факторы) . За время работы мне удалось выделить несколько "красных флагов", благодаря которым можно очень быстро выдавать префикс, не продолжая проверку. Одним из них является форматирование sql запросов без экранирования символов или валидации данных. К сожалению, находились люди, которые начинали спорить, говоря, что всегда так делали и ничего плохого не случилось. Да, я соглашусь, кто в здравом уме будет искать скули в боте телеграм) Сегодня решил почистить папку с клонированными репками от ненужного. Во время удаления я наткнулся на папочку с проверенными работами. В дирках я обычно создавал файлик result.md, куда писал итог тестирования. Удаляя и читая результаты(ну как такое не почитать, воспоминания же), наткнулся на свой хештег #sqli . Вдруг, мне стало интересно: а не зря ли я так душил молодых. Запустив код мои сомнения развеялись. Сам проект Ниже я реализовал базовый функционал, который поможет в демонстрации. В тз был пункт про поиск вещей по части их названия. Очень простой способ поиска, который мне все демонстрировали: select * from table_name where column_name like '%to_search%' SQL select * from table_name where column_name like '%to_search%' Написал простенького бота с одним хендлером. (Код накидан мельком для демонстрации) @dp.message_handler() async def test_handler(msg: Message): with db.connection: db.cursor.execute(f"SELECT * FROM users WHERE data like'%{msg.text}%' ") result = db.cursor.fetchall() if not result: return await msg.answer("Ничего не найдено:( ") res_text = "" for res in result: res_text += f"\nАйди: {res[0]} Значение: {res[1]}" return await msg.answer(f"Найдено: {res_text} \n ") Python @dp.message_handler() async def test_handler(msg: Message): with db.connection: db.cursor.execute(f"SELECT * FROM users WHERE data like'%{msg.text}%' ") result = db.cursor.fetchall() if not result: return await msg.answer("Ничего не найдено:( ") res_text = "" for res in result: res_text += f"\nАйди: {res[0]} Значение: {res[1]}" return await msg.answer(f"Найдено: {res_text} \n ") Sqliter я пока раскрывать не буду, сохраним интригу Начинаем знакомиться Перед лицом у нас тот самый поиск по подстроке: Ввожу данные - получаю результат. Предлагаю попробовать что-нибудь сломать) Попробуем одинарные и двойные кавычки При двойных поиск отработал штатно, но одинарная что-то натворила. Давайте попробуем починить) В sql можно комментировать код при помощи `--` Предлагаю жестко закрыть кавычку и проигнорировать то, что правее нашей точки форматирования Урааа, мы смогли починить! Бежим требовать зп у админа бота. Думаем что делать дальше. Я не гуру в sql-injection и всё, что описано здесь, было создано с использованием личных знаний sql и гуглёшки встроенных функций sqlite. В sql есть прекрасная вещь, как union Она позволяет объединять таблички на выводе. inner outer lift right и все дела. Я хочу получить список всех табличек в бд. Для этого можно использовать встроенный прикол select sql from sqlite_master SQL select sql from sqlite_master Но как это сделать? Union! Единственное, что нам требуется - узнать кол-во возвращаемых в запросе колонок. логично, что у нас больше одной колонки) оп, что-то вышло вкидываем наш прикол Вот какие таблички у нас есть (1=0 добавил, чтобы из самой таблички значения не брались): Оп, у нас есть табличка admin_rights, там что-то интересное, смотрим кол-во записей в ней одна запись, как приятно. Давайте прочитаем что там. Название колонок мы знаем. Немного быдлокодим на sql и вауля Сам в ахуе А если мы будем возвращать не звёздочку? Так еще и sqlite3.Row используем! Теперь select выглядит так: db.cursor.execute(f"SELECT id, data FROM users WHERE data like'%{msg.text}%' ") Python db.cursor.execute(f"SELECT id, data FROM users WHERE data like'%{msg.text}%' ") А вывод так: res_text += f"\nАйди: {res['id']} Значение: {res['data']}" Python res_text += f"\nАйди: {res['id']} Значение: {res['data']}" Норм, да?) Вывод очень прост - так не делайте) Оп оп (id не чекалось, прямой пользовательский ввод) тут апдейтик, в тз селекта не было К сожалению, это все скрины, которые получилось откопать.
хахаха, сяп. спасибо за новичка, понял что торопится не надо даже в несложных проектах начал использовать ORM. но бля новый проверяющий стал уже не проверяющим и все блять, заново делать тз так то тебе , просто время было чуть-чуть сложное и разозлился. p.s. если можно, могу у тебя спросить кое что в тг?)
LIMP, экранирование символов или валидацию данных делай и будет тебе спокойный сон и никто не узнает что хранит твоя бд бота
Vulgar, ну вот глянь, вот пример как я использую sqlite, тут есть проблемы? cursor.execute("CREATE TABLE IF NOT EXISTS accounts (id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER, currency TEXT, card INTEGER, username TEXT)") ## если что это разные участки кода cursor.execute("INSERT INTO accounts (user_id, currency, card, username) VALUES (?, 'byn', 0, ?)", (callback.from_user.id, callback.from_user.username)) cursor.execute("SELECT * FROM accounts WHERE user_id = ?", (callback.from_user.id,)) Python cursor.execute("CREATE TABLE IF NOT EXISTS accounts (id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER, currency TEXT, card INTEGER, username TEXT)") ## если что это разные участки кода cursor.execute("INSERT INTO accounts (user_id, currency, card, username) VALUES (?, 'byn', 0, ?)", (callback.from_user.id, callback.from_user.username)) cursor.execute("SELECT * FROM accounts WHERE user_id = ?", (callback.from_user.id,))
Прошлым летом писал в лс всем ботам, если находил какого-то бота, который не здоровался - сразу понимал, что бот не защищен от инъекций У меня было следующее имя в телеграме: '-- Code '--
squids, хуевая защита так-то, бот-то не работает в конечном итоге. Нужно отражение спец символов юзать, что давно уже есть во всех орм
в sqlite есть stmt (prepare если гуглить), которая все сразу фиксит cursor.execute("INSERT INTO users (name, age) VALUES (?, ?)", ('Charlie', 35)) Python cursor.execute("INSERT INTO users (name, age) VALUES (?, ?)", ('Charlie', 35))
База про sql, джуниоры с форума не хотят учить нормальные ОРМ и из-за этого страдают. Помню даже в гарант боте был баг с sqli The post was merged to previous Jun 20, 2024 А, ну и sqlite3, которая не поддерживает ассинхронность используется в ассинхронном контексте, classique
Morn1ngStar, майкрософт вошел в чат. https://learn.microsoft.com/en-us/dotnet/standard/data/sqlite/async
AIexa, я прочел статью и могу сказать, что джангоОРМ решила почти все проблемы о которых говорит автор. Для проектов которые у нас на форуме да и 95% проектов айти в целом ОРМ достаточно, она проще, и код писать банально быстрее.