From d924866727e4cdc00d82f9d70e3a4cbff67700ff Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Tue, 14 Jul 2026 00:58:19 +0000 Subject: [PATCH] Fix SQL injection in python/Quiz_4.py Replaced string formatting with parameterized queries in insertPC, updatePrinter, and deleteLaptop to prevent SQL injection vulnerabilities. Added a test script using an in-memory SQLite database to verify the database operations. Co-authored-by: tsainez <13399044+tsainez@users.noreply.github.com> --- .gitignore | 2 + python/Quiz_4.py | 16 +++--- python/test_quiz_4.py | 120 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 130 insertions(+), 8 deletions(-) create mode 100644 python/test_quiz_4.py diff --git a/.gitignore b/.gitignore index 4ecb8a2..1d0706a 100644 --- a/.gitignore +++ b/.gitignore @@ -52,3 +52,5 @@ c/.idea/c.iml /dataSources/ /dataSources.local.xml /httpRequests/ +__pycache__/ +*.pyc diff --git a/python/Quiz_4.py b/python/Quiz_4.py index 454f0b6..1cc14de 100644 --- a/python/Quiz_4.py +++ b/python/Quiz_4.py @@ -149,16 +149,16 @@ def insertPC(_conn, _maker, _model, _speed, _ram, _hd, _price): print(l) cursor = _conn.cursor() - cursor.execute('DELETE FROM pc WHERE model = {};'.format(_model)) + cursor.execute('DELETE FROM pc WHERE model = ?;', (_model,)) - cursor.execute('DELETE FROM product WHERE model = {};'.format(_model)) + cursor.execute('DELETE FROM product WHERE model = ?;', (_model,)) cursor.execute( - 'INSERT INTO pc(model, speed, ram, hd, price) VALUES(\'{}\', {}, {}, {}, {});'.format( - _model, _speed, _ram, _hd, _price)) + 'INSERT INTO pc(model, speed, ram, hd, price) VALUES(?, ?, ?, ?, ?);', + (_model, _speed, _ram, _hd, _price)) - cursor.execute('INSERT INTO product(maker, model, TYPE) VALUES(\'{}\', {}, \'{}\');'.format( - _maker, _model, 'PC')) + cursor.execute('INSERT INTO product(maker, model, TYPE) VALUES(?, ?, ?);', + (_maker, _model, 'PC')) _conn.commit() print("++++++++++++++++++++++++++++++++++") @@ -179,7 +179,7 @@ def updatePrinter(_conn, _model, _price): cursor = _conn.cursor() # Fixed typo from original code: exucte -> execute cursor.execute( - 'UPDATE printer SET price = {} WHERE model = {};'.format(_price, _model)) + 'UPDATE printer SET price = ? WHERE model = ?;', (_price, _model)) _conn.commit() print("++++++++++++++++++++++++++++++++++") @@ -198,7 +198,7 @@ def deleteLaptop(_conn, _model): print(l) cursor = _conn.cursor() - cursor.execute('DELETE FROM laptop WHERE model = {}'.format(_model)) + cursor.execute('DELETE FROM laptop WHERE model = ?', (_model,)) _conn.commit() print("++++++++++++++++++++++++++++++++++") diff --git a/python/test_quiz_4.py b/python/test_quiz_4.py new file mode 100644 index 0000000..104fd98 --- /dev/null +++ b/python/test_quiz_4.py @@ -0,0 +1,120 @@ +import unittest +import sqlite3 +from Quiz_4 import insertPC, updatePrinter, deleteLaptop + +class TestQuiz4(unittest.TestCase): + def setUp(self): + # Create an in-memory SQLite database + self.conn = sqlite3.connect(':memory:') + self.cursor = self.conn.cursor() + + # Create required tables for testing + self.cursor.execute(''' + CREATE TABLE IF NOT EXISTS product ( + maker VARCHAR(10), + model INT PRIMARY KEY, + TYPE VARCHAR(20) + ) + ''') + self.cursor.execute(''' + CREATE TABLE IF NOT EXISTS pc ( + model INT PRIMARY KEY, + speed FLOAT, + ram INT, + hd INT, + price INT + ) + ''') + self.cursor.execute(''' + CREATE TABLE IF NOT EXISTS printer ( + model INT PRIMARY KEY, + price INT + ) + ''') + self.cursor.execute(''' + CREATE TABLE IF NOT EXISTS laptop ( + model INT PRIMARY KEY, + speed FLOAT, + ram INT, + hd INT, + price INT + ) + ''') + + # Insert some initial data + self.cursor.execute("INSERT INTO product(maker, model, TYPE) VALUES('A', 1001, 'PC')") + self.cursor.execute("INSERT INTO pc(model, speed, ram, hd, price) VALUES(1001, 2.66, 1024, 250, 2114)") + + self.cursor.execute("INSERT INTO printer(model, price) VALUES(3001, 120)") + + self.cursor.execute("INSERT INTO laptop(model, speed, ram, hd, price) VALUES(2001, 2.00, 2048, 250, 3150)") + self.conn.commit() + + def tearDown(self): + self.conn.close() + + def test_insertPC(self): + # Test inserting a new PC + insertPC(self.conn, 'B', 1002, 3.0, 2048, 500, 1000) + + self.cursor.execute("SELECT * FROM pc WHERE model = 1002") + result = self.cursor.fetchone() + self.assertIsNotNone(result) + self.assertEqual(result, (1002, 3.0, 2048, 500, 1000)) + + self.cursor.execute("SELECT * FROM product WHERE model = 1002") + result = self.cursor.fetchone() + self.assertIsNotNone(result) + self.assertEqual(result, ('B', 1002, 'PC')) + + # Test updating (replacing) an existing PC + insertPC(self.conn, 'B', 1002, 3.2, 4096, 1000, 1500) + self.cursor.execute("SELECT * FROM pc WHERE model = 1002") + result = self.cursor.fetchone() + self.assertIsNotNone(result) + self.assertEqual(result, (1002, 3.2, 4096, 1000, 1500)) + + # Test preventing SQL injection in insertPC (e.g. maker with quotes) + # Assuming maker name "Inject'; DROP TABLE pc; --" + malicious_maker = "Inject'; DROP TABLE pc; --" + insertPC(self.conn, malicious_maker, 1003, 2.0, 1024, 250, 500) + + # Verify table pc still exists by fetching + self.cursor.execute("SELECT * FROM pc WHERE model = 1003") + result = self.cursor.fetchone() + self.assertIsNotNone(result) + + self.cursor.execute("SELECT maker FROM product WHERE model = 1003") + maker_result = self.cursor.fetchone() + self.assertEqual(maker_result[0], malicious_maker) + + def test_updatePrinter(self): + # Test updating an existing printer + updatePrinter(self.conn, 3001, 150) + self.cursor.execute("SELECT price FROM printer WHERE model = 3001") + result = self.cursor.fetchone() + self.assertEqual(result[0], 150) + + def test_deleteLaptop(self): + # Test deleting an existing laptop + deleteLaptop(self.conn, 2001) + self.cursor.execute("SELECT * FROM laptop WHERE model = 2001") + result = self.cursor.fetchone() + self.assertIsNone(result) + + # Test preventing SQL injection in deleteLaptop + self.cursor.execute("INSERT INTO laptop(model, speed, ram, hd, price) VALUES(2002, 2.00, 2048, 250, 3150)") + self.conn.commit() + + # Attempt injection to delete all or something + malicious_model = "2002 OR 1=1" + deleteLaptop(self.conn, malicious_model) + + # If parameterized properly, it shouldn't execute the injection. It will either fail to match or delete literally that string if somehow model allows string (which here it's INT but SQLite is flexible). + # We can check if 2002 still exists + self.cursor.execute("SELECT * FROM laptop WHERE model = 2002") + result = self.cursor.fetchone() + self.assertIsNotNone(result) + +if __name__ == '__main__': + unittest.main()