{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Sqlite database\n",
"\n",
"\n",
"- https://www.sqlite.org/\n",
"- C-based, one of the most used embedded database (zero configuration)\n",
"\n",
"## SQL basics\n",
"- Structured Query Language\n",
"- case insensitive language; usually written in uppercase\n",
"- let's you or program use SQL-based databases such as SQLite, MySQL, MSSQL, PostgreSQL, etc.\n",
"- most important basic statents to learn: CRUD\n",
"- C: create (database, table, create and insert records)\n",
"- R: retrieve/read data\n",
"- U: update data\n",
"- D: delete data\n",
"- http://www.w3schools.com/sql/default.asp\n",
"\n",
"## sqlite browser\n",
"- GUI-based sqlite db explorer\n",
"- makes it easy to see data and learn SQL\n",
"- http://sqlitebrowser.org/"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## sqlite3 module\n",
"- python3 provides sqlite3 library to work with sqlite database\n",
"- https://docs.python.org/3/library/sqlite3.html\n",
"- SQLite natively supports the following types: NULL, INTEGER, REAL, TEXT, BLOB \n",
"\n",
"|SQLite type|Python type|\n",
"| ---|---|\n",
"| NULL | None |\n",
"| INTEGER | int |\n",
"| REAL | float |\n",
"| TEXT | str |\n",
"| BLOB | bytes |\n",
"\n",
"## in memory db example"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
""
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import sqlite3\n",
"# connect to the memory database\n",
"con = sqlite3.connect(\":memory:\")\n",
"\n",
"# create a table\n",
"con.execute(\"create table person(fname, lname)\")"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
""
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# fill the table with data\n",
"persons = [('Hugo', 'Boss'), ('Calvin', 'Klien')]\n",
"con.executemany(\"insert into person(fname, lname) values (?, ?)\", \n",
" persons)"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"(1, 'Hugo', 'Boss')\n",
"(2, 'Calvin', 'Klien')\n"
]
}
],
"source": [
"# print the table contents\n",
"for row in con.execute(\"select rowid, fname, lname from person\"):\n",
" print(row)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"I just deleted 1 rows\n"
]
}
],
"source": [
"print(\"I just deleted\", con.execute(\"delete from person where rowid=1\").rowcount, \n",
" \"rows\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## db file example\n",
"### create database, create table and insert data into table"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
""
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import sqlite3\n",
"# create connection\n",
"conn = sqlite3.connect('example.db')\n",
"# create cursor object\n",
"cur = conn.cursor()\n",
"\n",
"cur.execute(\"\"\"CREATE TABLE IF NOT EXISTS students (\n",
" firstName text, \n",
" lastName text, \n",
" test1 real, \n",
" test2 real,\n",
" average real,\n",
" grade text\n",
" )\n",
" \"\"\")"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
""
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"query = \"\"\" INSERT INTO students (firstName, lastName, \n",
" test1, test2) values (?, ?, ?, ?)\n",
" \"\"\"\n",
"cur.execute(query, ('John', 'Smith', 99, 95.5))"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
""
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"cur.execute(query, ('Michael', 'Jordan', 50, 65))"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"# save/commit the changes to the db\n",
"conn.commit()\n",
"# close the database if done\n",
"conn.close()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### open database, read and update table"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"import sqlite3\n",
"conn = sqlite3.connect('example.db')\n",
"cur = conn.cursor()"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"('John', 'Smith', 99.0, 95.5, None, None)\n"
]
}
],
"source": [
"cur.execute('SELECT * FROM students where rowid = 1')\n",
"row = cur.fetchone() # returns one row as tuple if rowid with value 1 exists\n",
"print(row)"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"John\n",
"Smith\n",
"99.0\n",
"95.5\n",
"None\n",
"None\n"
]
}
],
"source": [
"for col in row:\n",
" print(col)"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n"
]
}
],
"source": [
"cur.execute('SELECT rowid, * FROM students')\n",
"rows = cur.fetchall()\n",
"print(type(rows))"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"(1, 'John', 'Smith', 99.0, 95.5, None, None)\n",
"(2, 'Michael', 'Jordan', 50.0, 65.0, None, None)\n"
]
}
],
"source": [
"for row in rows:\n",
" print(row)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"update table"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [],
"source": [
"for row in rows:\n",
" avg = (row[3] + row[4])/2\n",
" # grade = ?\n",
" cur.execute('update students set average=? where rowid=?', (avg, row[0]))"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[('John', 'Smith', 99.0, 95.5, 97.25, None), ('Michael', 'Jordan', 50.0, 65.0, 57.5, None)]\n"
]
}
],
"source": [
"cur.execute('select * from students')\n",
"print(cur.fetchall())"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [],
"source": [
"# commit changes and close connection\n",
"conn.commit()\n",
"conn.close()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## SQL Injection Vulnerability\n",
"- how not to write sql query in programs"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
""
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import sqlite3\n",
"conn = sqlite3.connect('example.db')\n",
"cur = conn.cursor()\n",
"\n",
"cur.execute(\"\"\"CREATE TABLE IF NOT EXISTS users (\n",
" username text unique, \n",
" password text \n",
" )\n",
" \"\"\")"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Enter your username: john\n",
"Pick a password: password\n"
]
}
],
"source": [
"# Prompt user to create account\n",
"username = input('Enter your username: ')\n",
"password = input('Pick a password: ')"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"insert into users (username, password) values ('john', 'password')\n"
]
},
{
"data": {
"text/plain": [
""
]
},
"execution_count": 23,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# bad passwords\n",
"# insecure way to create sql statements\n",
"sqlinsert = \"insert into users (username, password) values ('{0}', '{1}')\".format(username, password)\n",
"print(sqlinsert)\n",
"cur.execute(sqlinsert)\n"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"('john', 'password')\n"
]
}
],
"source": [
"# check database\n",
"conn.commit()\n",
"for row in cur.execute('select * from users'):\n",
" print(row)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### what is wrong with the above codes?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### authenticate users and SQL injection attack"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [],
"source": [
"# Prompt user to create account\n",
"def insecureAuthentication():\n",
" username = input('Enter your username: ')\n",
" password = input('Pick a password: ')\n",
" sqlSelect = \"select * from users where username = '{0}' \\\n",
" and password = '{1}'\".format(username, password)\n",
" cur.execute(sqlSelect)\n",
" row = cur.fetchone()\n",
" if row:\n",
" print('Welcome {}, this is your kingdom!'.format(row[0]))\n",
" else:\n",
" print('Wrong credentials. Try Again!')\n",
" "
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Enter your username: john\n",
"Pick a password: password\n",
"Welcome john, this is your kingdom!\n"
]
}
],
"source": [
"insecureAuthentication()"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Enter your username: john' or '1'='1\n",
"Pick a password: adfadsfdsf\n",
"Welcome john, this is your kingdom!\n"
]
}
],
"source": [
"# sql injection; authenticate without using password\n",
"insecureAuthentication()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## secure way to store password\n",
"- https://docs.python.org/3/library/hashlib.html\n"
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {},
"outputs": [],
"source": [
"import uuid\n",
"import hashlib, binascii\n",
"\n",
"def createSecurePassword(password, salt=None, round=100000):\n",
" if not salt:\n",
" salt = uuid.uuid4().hex\n",
" \n",
" \"\"\"\n",
" for i in range(round):\n",
" password = password+salt\n",
" password = hashlib.sha256(password.encode('utf-8')).hexdigest()\n",
" \"\"\"\n",
" # hashlib.pbkdf2_hmac(hash_name, password, salt, iterations, dklen=None)\n",
" dk = hashlib.pbkdf2_hmac('sha256', password.encode('utf-8'), \n",
" salt.encode('utf-8'), round)\n",
" password = binascii.hexlify(dk)\n",
" return \"%s:%s\"%(password, salt)"
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {},
"outputs": [],
"source": [
"def secureRegistration():\n",
" # Prompt user to create account\n",
" username = input('Enter your username: ')\n",
" password = input('Enter your password: ')\n",
" secPass = createSecurePassword(password)\n",
" insert = 'insert into users (username, password) values (?, ?)'\n",
" cur.execute(insert, (username, secPass))\n",
" "
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Enter your username: jake\n",
"Enter your password: password1\n"
]
}
],
"source": [
"# register a user\n",
"secureRegistration()"
]
},
{
"cell_type": "code",
"execution_count": 35,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"('john', 'password')\n",
"('jake', \"b'c318988672d05094deaffce0148a49b1b43dfc89f3b8b75d251de60446dcecc5':5340a4af29574554997b0fe7a1ac670b\")\n"
]
}
],
"source": [
"# check data\n",
"for row in cur.execute('select * from users'):\n",
" print(row)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"conn.commit()"
]
},
{
"cell_type": "code",
"execution_count": 36,
"metadata": {},
"outputs": [],
"source": [
"def secureAuthentication():\n",
" username = input('Enter your username: ')\n",
" password = input('Enter your password: ') \n",
" # use parameterized query\n",
" sqlSelect = 'select password from users where username = ?'\n",
" cur.execute(sqlSelect, (username,))\n",
" row = cur.fetchone()\n",
" if row:\n",
" # username exists\n",
" # check password hashes\n",
" hashpass = row[0]\n",
" hashedPass = hashpass[:hashpass.find(':')]\n",
" salt = hashpass[hashpass.find(':')+1:]\n",
" secPass = createSecurePassword(password, salt)\n",
" if hashpass == secPass:\n",
" print('Welcome to your kingdom, {}'.format(username))\n",
" else:\n",
" print('Wrong credentials. Try Again!')\n",
" else:\n",
" print('Wrong credentials. Try Again!')"
]
},
{
"cell_type": "code",
"execution_count": 37,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Enter your username: jake\n",
"Enter your password: password1\n",
"Welcome to your kingdom, jake\n"
]
}
],
"source": [
"secureAuthentication()"
]
},
{
"cell_type": "code",
"execution_count": 39,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Enter your username: jake' or '1' = '1\n",
"Enter your password: adsfadsf\n",
"Wrong credentials. Try Again!\n"
]
}
],
"source": [
"# try the same SQL injection\n",
"secureAuthentication()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"conn.commit()\n",
"conn.close()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.3"
}
},
"nbformat": 4,
"nbformat_minor": 2
}