This presentation aims to teach the concept of SQL Injection and illustrate in practical examples how such an attack can damage a system.
Examples in Python
Esta apresentação objetiva ensinar o conceito de SQL Injection, bem como ilustrar em exemplos práticos como um ataque desse tipo pode danificar um sistema.
Exemplos em Python.
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
Neutralizing SQL Injection in PostgreSQL
1. Juliano Atanazio
Neutralizando SQL Injection no PostgreSQLNeutralizando SQL Injection no PostgreSQL
Neutralizing SQL Injection in PostgreSQLNeutralizing SQL Injection in PostgreSQL
2. 2/59
About me
Juliano Atanazio
● Graduated in Computer Science for Business Management (Informática para Gestão de
Negócios), FATEC Zona Sul, São Paulo – SP;
● PostgreSQL DBA;
● Linux admin;
● Instructor (PostgreSQL);
● LPIC-1, LPIC-2 Certified;
● Linux user since 2000;
● Free Software enthusiast;
● Favorite technologies: PostgreSQL, Linux, Python, Shell Script, FreeBSD, etc...;
● Headbanger :) m/
3. 3/59
SQL Injection
Definition
SQL Injection is a method to introducing malicious SQL code to
get unauthorized access or even damage a system.
Definição
SQL Injection é um método para introduzir código SQL maligno
para obter acesso indevido ou mesmo danificar um sistema.
4. 4/59
SQL Injection: Practice
$DBHOST enviroment variable to database server address:
Variável de ambiente $DBHOST para o endereço do servidor de
banco de dados:
$ read -p 'Type the database host address: ' DBHOST
Type the database host address:
Type the server address.
Digite o endereço do servidor.
5. 5/59
SQL Injection: Practice
Database user with encrypted stored password, login permission,
no superuser:
Usuário de banco de dados com senha armazenada
criptografada, permissão de login, não superuser:
$ psql -U postgres -h ${DBHOST} -c
"CREATE ROLE u_sql_injection
ENCRYPTED PASSWORD 'secret' LOGIN NOSUPERUSER;"
6. 6/59
SQL Injection: Practice
Database creation "db_sql_injection" with user "u_sql_injection"
as owner:
Criação de banco de dados "db_sql_injection" com o usuário
"u_sql_injection" como proprietário:
$ psql -U postgres -h ${DBHOST} -c
"CREATE DATABASE db_sql_injection OWNER u_sql_injection;"
7. 7/59
SQL Injection: Practice
Accessing the database via psql:
Acessando a base de dados via psql:
$ psql -U u_sql_injection db_sql_injection -h ${DBHOST}
8. 8/59
SQL Injection: Practice
User table creation for the application (without hashing):
Criação de tabela de usuários para a aplicação (sem hashing):
> CREATE TABLE tb_user(
username varchar(50) PRIMARY KEY, -- natural primary key
password VARCHAR(72) NOT NULL);
Inserting a application user in the table:
Inserindo um usuário do aplicativo na tabela:
> INSERT INTO tb_user (username, password)
VALUES ('foo', 'mypassword');
9. 9/59
SQL Injection: Practice
Script (1):
__________ sql_injection_1.py ___________________________
#_*_ encoding: utf-8 _*_
import getpass
user = input('User: ')
password = getpass.getpass('Password: ')
sql = """
SELECT TRUE FROM tb_user
WHERE username = '{}'
AND password = '{}';
""".format(user, password)
print('n{}'.format(sql))
____________________________________________________
10. 10/59
SQL Injection: Practice
A simple test:
Um teste simples:
$ python3 sql_injection_1.py
User: foo
Password:
SELECT TRUE FROM tb_user
WHERE username = 'foo'
AND password = 'mypassword';
11. 11/59
SQL Injection: About the Script
The script is pretty simple, does not yet have any interaction with
the database, but it serves to illustrate.
O script é bem simples, ainda não possui qualquer interação com
o banco de dados, mas serve para ilustrar.
12. 12/59
SQL Injection: Practice
Script (2):
__________ sql_injection_2.py ___________________________
# _*_ encoding: utf-8 _*_
import getpass
import psycopg2
import sys
# DB server as first argument
dbhost = sys.argv[1]
# Connection string
conn_string = """
host='{}'
dbname='db_sql_injection'
user='u_sql_injection'
password='secret'
port='5432'
""".format(dbhost)
→
14. 14/59
SQL Injection: Practice
Script (2):
__________ sql_injection_2.py ___________________________
# SQL string
sql = """
SELECT TRUE FROM tb_user
WHERE username = '{}'
AND password = '{}';
""".format(user, password)
# Print the sql string after user and password input
print('{}n'.format(sql))
# Execute the SQL string in database
cursor.execute(sql)
# The result of the string SQL execution
res = cursor.fetchone()
→
15. 15/59
SQL Injection: Practice
Script (2):
__________ sql_injection_2.py ___________________________
# User login validation
if res:
print('nAcessed!')
else:
print('nError: Invalid user and password combination!')
sys.exit(1)
except psycopg2.Error as e:
print('nAn error has occurred!n{}'.format(e))
# Close the database connection
conn.close()
____________________________________________________
16. 16/59
SQL Injection: Practice
A simple test access with correct password:
Um teste simples de acesso com senha correta:
$ python3 sql_injection_2.py ${DBHOST}
User: foo
Password:
SELECT TRUE FROM tb_user
WHERE username = 'foo'
AND password = 'mypassword';
Acessed!
17. 17/59
SQL Injection: Practice
A simple test access with wrong password:
Um teste simples de acesso com senha errada:
$ python3 sql_injection_2.py ${DBHOST}
User: foo
Password:
SELECT TRUE FROM tb_user
WHERE username = 'foo'
AND password = '123';
Error: Invalid user and password combination!
18. 18/59
SQL Injection: Practice
Malicious code at user login input:
Código malicioso na entrada de login de usuário:
$ python3 sql_injection_2.py ${DBHOST}
User: ' OR 1 = 1; DROP TABLE tb_user; --
Password:
SELECT TRUE FROM tb_user
WHERE username = '' OR 1 = 1; DROP TABLE tb_user; –-'
AND password = '';
An error has occurred!
no results to fetch
Does the table has been deleted?
Será que a tabela foi apagada?
19. 19/59
SQL Injection: Practice
Checking the table in the database:
Verificando a tabela na base de dados:
> SELECT TRUE FROM tb_user;
bool
------
t
Everithing is OK... for a while...
No commit...
Está tudo OK... por enquanto...
Sem efetivação...
20. 20/59
SQL Injection: Practice
Malicious code at user login input (with COMMIT):
Código malicioso na entrada de login de usuário (com COMMIT):
$ python3 sql_injection.py
User: ' OR 1 = 1; DROP TABLE tb_user; COMMIT; --
Password:
SELECT TRUE FROM tb_user
WHERE username = '' OR 1 = 1; DROP TABLE tb_user; COMMIT; –-'
AND password = '';
An error has occurred!
no results to fetch
21. 21/59
SQL Injection: Practice
Checking the table in the database:
Verificando a tabela na base de dados:
> SELECT TRUE FROM tb_user;
ERROR: relation "tb_user" does not exist
LINE 1: SELECT id FROM tb_user;
^
The table was dropped and must be created with the data again.
A tabela foi apagada e terá que ser criada com os dados
novamente.
:(
22. 22/59
Dollar Quoting
It consists of a dollar sign ($), an optional “tag” of zero or more
characters, another dollar sign, an arbitrary sequence of
characters that makes up the string content, a dollar sign, the
same tag that began this dollar quote, and a dollar sign. For
example, here are two different ways to specify the string
“Dianne's horse” using dollar quoting:
Consiste de um caractere de dólar, uma “tag” opcional de zero ou
mais caracteres, outro caractere de dólar, uma sequência
arbitrária de caracteres que é o conteúdo da string, um caractere
de dólar, a mesma tag que começou o dollar quoting e um
caractere de dólar. Por exemplo, há duas maneiras diferentes de
especificar a string “Dianne's horse” usando dollar quoting:
$$Dianne's horse$$
$SomeTag$Dianne's horse$SomeTag$
23. 23/59
Dollar Quoting
Dollar quoting is also a very nice feature to avoid SQL injection,
particularly when the application generates a random tag.
This tag must start with either a letter or with an underscore, the
rest can have underscore, letters or numbers.
Dollar quoting também é um recurso muito interessante para se
evitar SQL injection, principalmente quando a aplicação gera uma
tag aleatória.
Essa tag deve começar ou com uma letra ou com underscore, o
resto pode ter underscore, letras ou números.
24. 24/59
Dollar Quoting: Practice
Script (3):
__________ sql_injection_3.py ___________________________
# _*_ encoding: utf-8 _*_
import getpass
import psycopg2
import sys
# DB server as first argument
dbhost = sys.argv[1]
# Connection string
conn_string = """
host='{}'
dbname='db_sql_injection'
user='u_sql_injection'
password='secret'
port='5432'
""".format(dbhost)
→
25. 25/59
Dollar Quoting: Practice
Script (3):
__________ sql_injection_3.py ___________________________
try:
# Connection
conn = psycopg2.connect(conn_string)
# Cursor creation to execute SQL commands
cursor = conn.cursor()
# User input
user = input('User: ')
# Password input
password = getpass.getpass('Password: ')
→
26. 26/59
Dollar Quoting: Practice
Script (3):
__________ sql_injection_3.py ___________________________
# SQL string
sql = """
SELECT TRUE FROM tb_user
WHERE username = $${}$$
AND password = $${}$$;
""".format(user, password)
# Print the sql string after user and password input
print('{}n'.format(sql))
# Execute the SQL string in database
cursor.execute(sql)
# The result of the string SQL execution
res = cursor.fetchone()
→
27. 27/59
Dollar Quoting: Practice
Script (3):
__________ sql_injection_3.py ___________________________
# User login validation
if res:
print('nAcessed!n')
else:
print('nError: Invalid user and password combination!n')
sys.exit(1)
except psycopg2.Error as e:
print('nAn error has occurred!n{}'.format(e))
# Close the database connection
conn.close()
____________________________________________________
28. 28/59
Dollar Quoting: Practice
Normal access:
Acesso normal:
$ python3 sql_injection_3.py ${DBHOST}
User: foo
Password:
SELECT TRUE FROM tb_user
WHERE username = $$foo$$
AND password = $$mypassword$$;
Acessed!
29. 29/59
Dollar Quoting: Practice
Attempted malicious code (with apostrophe):
Tentativa de código malicioso (com apóstrofo):
$ python3 sql_injection_3.py ${DBHOST}
User: ' OR 1 = 1; DROP TABLE tb_user; COMMIT; --
Password:
SELECT TRUE FROM tb_user
WHERE username = $$' OR 1 = 1; DROP TABLE tb_user; COMMIT; --$$
AND password = $$$$;
Error: Invalid user and password combination!
Neutralized malicious code.
Código malicioso neutralizado.
30. 30/59
Dollar Quoting: Practice
Attempted malicious code (with double dollar sign):
Tentativa de código malicioso (com dólar duplo):
$ python3 sql_injection_3.py ${DBHOST}
User: $$ OR 1 = 1; DROP TABLE tb_user; COMMIT; --
Password:
SELECT TRUE FROM tb_user
WHERE username = $$$$ OR 1 = 1; DROP TABLE tb_user; COMMIT; --$$
AND password = $$$$;
An error has occurred!
no results to fetch
31. 31/59
Dollar Quoting: Practice
Checking the table in the database:
Verificando a tabela na base de dados:
> SELECT TRUE FROM tb_user;
ERROR: relation "tb_user" does not exist
LINE 1: SELECT id FROM tb_user;
^
The table was dropped and must be created with the data again.
A tabela foi apagada e terá que ser criada com os dados
novamente.
:(
32. 32/59
Dollar Quoting: Practice
Script (4):
__________ sql_injection_4.py ___________________________
# _*_ encoding: utf-8 _*_
import getpass
import psycopg2
import sys
import string
import random
# DB server as first argument
dbhost = sys.argv[1]
→
34. 34/59
Dollar Quoting: Practice
Script (4):
__________ sql_injection_4.py ___________________________
# Function: tag generator
def tag_gen(size):
first_char = '{}_'.format(string.ascii_letters)
last_chars = '{}{}'.format(string.digits, first_char)
tag = random.choice(first_char)
for i in range(size - 1):
tag = '{}{}'.format(tag, random.choice(last_chars))
return tag
# Tag for dollar quoting
tag = tag_gen(7)
→
35. 35/59
Dollar Quoting: Practice
Script (4):
__________ sql_injection_4.py ___________________________
try:
# Connection
conn = psycopg2.connect(conn_string)
# Cursor creation to execute SQL commands
cursor = conn.cursor()
# User input
user = input('User: ')
# Password input
password = getpass.getpass('Password: ')
→
36. 36/59
Dollar Quoting: Practice
Script (4):
__________ sql_injection_4.py ___________________________
# SQL string
sql = """
SELECT TRUE FROM tb_user
WHERE username = ${}${}${}$
AND password = ${}${}${}$;
""".format(tag, user, tag, tag, password, tag)
# Print the sql string after user and password input
print('{}n'.format(sql))
# Execute the SQL string in database
cursor.execute(sql)
# The result of the string SQL execution
res = cursor.fetchone()
→
37. 37/59
Dollar Quoting: Practice
Script (4):
__________ sql_injection_4.py ___________________________
# User login validation
if res:
print('nAcessed!n')
else:
print('nError: Invalid user and password combination!n')
sys.exit(1)
except psycopg2.Error as e:
print('nAn error has occurred!n{}'.format(e))
# Close the database connection
conn.close()
____________________________________________________
38. 38/59
Dollar Quoting: Practice
A simple test access with correct password:
Um teste simples de acesso com senha correta:
$ python3 sql_injection_4.py ${DBHOST}
User: foo
Password:
SELECT TRUE FROM tb_user
WHERE username = $PJPWqvS$foo$PJPWqvS$
AND password = $PJPWqvS$mypassword$PJPWqvS$;
Acessed!
39. 39/59
Dollar Quoting: Practice
Attempted malicious code (with apostrophe):
Tentativa de código malicioso (com apóstrofo):
$ python3 sql_injection_4.py ${DBHOST}
User: ' OR 1 = 1; DROP TABLE tb_user; COMMIT; --
Password:
SELECT TRUE FROM tb_user
WHERE username = $EbVRSoG$' OR 1 = 1; DROP TABLE tb_user; COMMIT; --
$EbVRSoG$
AND password = $EbVRSoG$$EbVRSoG$;
Error: Invalid user and password combination!
Neutralized malicious code.
Código malicioso neutralizado.
40. 40/59
Dollar Quoting: Practice
Attempted malicious code (with double dollar sign):
Tentativa de código malicioso (com dólar duplo):
$ python3 sql_injection_4.py ${DBHOST}
User: $$ OR 1 = 1; DROP TABLE tb_user; COMMIT; --
Password:
SELECT TRUE FROM tb_user
WHERE username = $Re7Gqwb$$$ OR 1 = 1; DROP TABLE tb_user; COMMIT; --
$Re7Gqwb$
AND password = $Re7Gqwb$$Re7Gqwb$;
Error: Invalid user and password combination!
Neutralized malicious code.
Código malicioso neutralizado.
41. 41/59
Prepared Statement
A prepared statement is a server-side object that can be used to
optimize performance.
Um prepared statement (comando preparado) é um objeto do
lado do servidor que pode ser usado para otimizar performance.
When the PREPARE statement is executed, the statement is
analyzed, statistics collections are made (ANALYZE) and
rewritten.
Quando PREPARE statement é executado, o comando
(statement) é analisado, são feitas coletas de estatísticas
(ANALYZE) e reescrito.
42. 42/59
Prepared Statement
When given an EXECUTE statement, the statement is planned
and prepared executed.
Quando é dado um comando EXECUTE, o prepared statement é
planejado e executado.
This division of labor prevents repetitive tasks of collecting
statistics, while allowing the execution plan depend on specific
parameters that can be provided.
Essa divisão de trabalho evita repetitivos trabalhos de coleta de
estatística, enquanto permite ao plano de execução de depender
de parâmetros específicos que podem ser fornecidos.
44. 44/59
Prepared Statement: Practice
Create a prepared statement:
Criar um prepared statement:
> PREPARE q_user(text, text) AS
SELECT TRUE FROM tb_user
WHERE username = $1
AND password = $2;
48. 48/59
Prepared Statement: Practice
Script (5):
__________ sql_injection_5.py ___________________________
# SQL string
sql = """
PREPARE q_user (text, text) AS
SELECT TRUE FROM tb_user
WHERE username = $1
AND password = $2;
"""
# Print the sql string after user and password input
print('{}n'.format(sql))
# Execute the SQL string in database
cursor.execute(sql)
→
49. 49/59
Prepared Statement: Practice
Script (5):
__________ sql_injection_5.py ___________________________
# SQL string with EXECUTE
sql = "EXECUTE q_user('{}', '{}');".format(user, password)
# Print the SQL string
print('{}n'.format(sql))
# Execute the SQL string in database
cursor.execute(sql)
# The result of the string SQL execution
res = cursor.fetchone()
→
50. 50/59
Prepared Statement: Practice
Script (5):
__________ sql_injection_5.py ___________________________
# User login validation
if res:
print('nAcessed!')
else:
print('nError: Invalid user and password combination!')
sys.exit(1)
except psycopg2.Error as e:
print('nAn error has occurred!n{}'.format(e))
# Close the database connection
conn.close()
____________________________________________________
51. 51/59
Prepared Statement: Practice
A simple test access with correct password:
Um teste simples de acesso com senha correta:
$ python3 sql_injection_5.py ${DBHOST}
User: foo
Password:
PREPARE q_user (text, text) AS
SELECT TRUE FROM tb_user
WHERE username = $1
AND password = $2;
EXECUTE q_user('foo', 'mypassword');
Acessed!
52. 52/59
Prepared Statement: Practice
A simple test access with wrong password:
Um teste simples de acesso com senha errada:
$ python3 sql_injection_5.py ${DBHOST}
User: foo
Password:
PREPARE q_user (text, text) AS
SELECT TRUE FROM tb_user
WHERE username = $1
AND password = $2;
EXECUTE q_user('foo', '123');
Error: Invalid user and password combination!
53. 53/59
Prepared Statement: Practice
Attempted malicious code (with apostrophe):
Tentativa de código malicioso (com apóstrofo):
$ python3 sql_injection_5.py ${DBHOST}
User: ' OR 1 = 1; DROP TABLE tb_user; COMMIT; --
Password:
PREPARE q_user (text, text) AS
SELECT TRUE FROM tb_user
WHERE username = $1
AND password = $2;
EXECUTE q_user('' OR 1 = 1; DROP TABLE tb_user; COMMIT; --', '');
An error has occurred!
syntax error at or near ";"
LINE 1: EXECUTE q_user('' OR 1 = 1; DROP TABLE tb_user; COMMIT; --',...
^
Neutralized malicious code. / Código malicioso neutralizado
54. 54/59
Prepared Statement: Practice
Attempted malicious code (with double dollar sign):
Tentativa de código malicioso (com dólar duplo):
$ python3 sql_injection_5.py ${DBHOST}
User: $$ OR 1 = 1; DROP TABLE tb_user; COMMIT; --
Password:
PREPARE q_user (text, text) AS
SELECT TRUE FROM tb_user
WHERE username = $1
AND password = $2;
EXECUTE q_user('$$ OR 1 = 1; DROP TABLE tb_user; COMMIT; --', '');
Error: Invalid user and password combination!
Neutralized malicious code. / Código malicioso neutralizado.
55. 55/59
Conclusion / Conclusão
PostgreSQL has its own mechanisms against SQL injection which
makes it very independent of the application.
O PostgreSQL possui mecanismos próprios contra SQL injection
que o torna muito independente da aplicação.
56. 56/59
Conclusion / Conclusão
This makes it easier for the application
developer, may delegate such tasks to the
database, avoiding technical adjustments
in the application and finally provide a
robust solution independent of language.
Isso facilita para o desenvolvedor da
aplicação, podendo confiar tais tarefas ao
banco de dados, evitando adaptações
técnicas na aplicação e por fim prover
uma solução robusta independente da
linguagem.
57. 57/59
Donate!
The elephant needs you!
O Elefante precisa de você!
Contribute!
Contribua!
:)
http://www.postgresql.org/about/donate/
59. 59/59
See you soon!!!
Até a próxima!!!
Juliano Atanazio
juliano777@gmail.com
http://slideshare.net/spjuliano
https://speakerdeck.com/julianometalsp
https://juliano777.wordpress.com
:)