Upload
albaar-rubhasy
View
200
Download
1
Embed Size (px)
DESCRIPTION
Powerpoint pemrograman basis data & sql mg 12 fasilkom albaar rubhasy
Citation preview
Modul ke:
Fakultas
Program Studi
PL/SQL Dynamic SQLMelaksanakan perintah SQL menggunakan PL/SQL secara dinamis
Albaar Rubhasy, S.Si., M.T.I.
12FASILKOM
Sistem Informasi
Outline Perkuliahan
• Dynamic SQL
• SQL Injection
• Mencegah SQL Injection
Dynamic SQLModul 11: PL/SQL Dynamic SQLMelaksanakan perintah SQL menggunakan PL/SQL secara dinamis
What Is Dynamic SQL?
• Secara umum, programmer mengetahui SQL statement yang akan dieksekusi pada saat menulis program. Terkadang, mereka juga tidak mengetahui perintah yang akan dieksekusi ketika menulis program.
• Dynamic SQL adalah metodologi pemrograman untukmenghasilkan dan menjalankan SQL statement padawaktu berjalan.
• Alasan menggunakan dynamic SQL:
– SQL yang teksnya tidak diketahui pada waktu kompilasi
– SQL yang tidak didukung sebagai static SQL
Static SQL Statement
• SELECT (this statement is also called a query)
• Data manipulation language (DML) statements:– INSERT
– UPDATE
– DELETE
– MERGE
• Transaction control language (TCL) statements:– COMMIT
– ROLLBACK
– SAVEPOINT
– SET TRANSACTION
• LOCK TABLE
Contoh Dynamic SQL
• Misalkan kita ingin drop sebuah tabel tetapi nama tabel yang ingin di-drop tidak diketahui.
• Nama tabel dibentuk dengan menggunakan kata SALES dan empat digit tahun. Contoh: SALES2000.
• Artinya nama tabel bergantung pada perubahan tahun. Sehingga, perintah DROP TABLE seharusnya menggunakan tahun sekarang dan tahun sekarang diambil dari penanggalan sistem.
• Solusi: membuat perintah DROP TABLEcmd := ‘DROP TABLE sales’ ||
to_char(sysdate,’yyyy’);
Eksekusi Dynamic SQL Statement
Tipe eksekusi perintah dalam dynamic SQL:
• EXECUTE IMMEDIATE
• OPEN-FOR, FETCH-INTO, dan CLOSE
EXECUTE IMMEDIATE Statement
• Statement digunakan untuk mengeksekusi perintah yang mengandung variabel char.
• Syntax EXECUTE IMMEDIATE
– Dynamic_string: string yang berisi perintah yang akan dieksekusi
– Variable | record: variabel yang nilainya diambil. Jika record diberikan maka seluruh baris di-copy ke dalam record.
– Bind_argumen: nilai yang diteruskan ke SQL statement yang akan dieksekusi.
EXECUTE IMMEDIATE dynamic_string
[INTO {variable[, variable]... | record}]
[USING [IN | OUT | IN OUT] bind_argument
[, [IN | OUT | IN OUT] bind_argument]...];
Stored procedure untuk mengambil nama tabel dan drop tabel:
create or replace procedure droptable
(tablename varchar2) is cmd varchar2(100);
begin
cmd := 'drop table ' || tablename;
execute immediate cmd;
end;
Call stored procedure untuk drop tabel:
execute droptable('oldsales');
Stored function untuk mengambil tahun dan delete seluruh baris dari tabel yang dibentuk dg format SALESyear:
create or replace function deletesalesrows (year
number)
return number is
cmd varchar2(100);
begin
cmd := 'delete from sales'|| year;
execute immediate cmd;
return sql%rowcount;
end;
Gunakan function untuk delete baris pada Sales2000 dan tampilkan jumlah baris yang di-delete :
begin
dbms_output.put_line( deletesalesrows(2000));
end;
OPEN-FOR, FETCH-INTO, dan CLOSE
Statement• EXECUTE IMMEDIATE statement digunakan untuk
eksekusi query yang mengembalikan hanya satu baris.
• Jika kita ingin mengeksekusi query yang berpotensi mengembalikan baris yang banyak, maka prosesnya melibatkan Cursor.
• Prosesnya:
– Membuka cursor.
– Seluruh baris yang diperoleh di-copy ke dalam cursor.
– Setiap baris diambil (melalui FETCH statement) dan diproses.
Membuka Cursor: OPEN-FOR Statement
• Langkah pertama adalah membuka cursor melalui query statement.
• Statement menghubungkan antara cursor variable dengan query yang diberikan dan mengeksekusi query.
• Syntax OPEN-FOR
– Cursor_variable: cursor variable yang tidak memiliki tipe return.
– Dynamic_string: perintah SELECT yang akan dieksekusi.
– Bind_argument: value yang akan diteruskan.
OPEN {cursor_variable}
FOR dynamic_string
[USING bind_argument[, bind_argument]...];
Mengambil Baris dari Cursor: FETCH-
INTO Statement• Langkah selanjutnya adalah mengambil setiap baris dari cursor
dan copy nilai-nilai dari kolom yang berkorespondensi dengan variabel.
• Syntax FETCH-INTO
– Cursor_variable: cursor variable yang dihubungkan dengan hasil query
– Define_variable: variabel yang nilainya diambil dari kolom yang berkorespondensi
– Record: variabel dari record type atau %ROWTYPE% yang didefinisikan oleh user
FETCH {cursor_variable } INTO {define_variable[,
define_variable] ...
| record};
Menutup Cursor: CLOSE Statement
• Langkah terakhir adalah menutup cursor setelah proses diselesaikan.
• Syntax CLOSECLOSE {cursor_variable};
Contoh Program
declare
type salescursortype is ref cursor; -- define weak ref cursor type
salescursor salescursortype; -- declare cursor variable
prodid number(5);
qty number(5);
price number(5);
begin
open salescursor for -- open cursor variable
'select proid, qty, price from sales’ || to_char(sysdate,’yyyy’);
loop
fetch salescursor into prodid, qty, price;
exit when sales_cursor%notfound; --exit when no more records exist
-- process the record here
end loop
close salescursor; -- close the cursor after it is processed.
end; -- end of the block
SQL InjectionModul 11: PL/SQL Dynamic SQLMelaksanakan perintah SQL menggunakan PL/SQL secara dinamis
SQL Injection
• SQL injection secara jahat mengeksploitasi aplikasi yang menggunakan client-supplied data dalam SQL statement.
• Dapat dilakukan pengaksesan database tanpa izin untuk view atau manipulasi data terbatas.
• Pada bagian ini akan dijelaskan kerentanan SQL injection dan bagaimana cara mencegahnya.
Setup SQL Injection Example
DROP TABLE secret_records;
CREATE TABLE secret_records (
user_name VARCHAR2(9),
service_type VARCHAR2(12),
value VARCHAR2(30),
date_created DATE
);
INSERT INTO secret_records (
user_name, service_type, value, date_created
)
VALUES ('Andy', 'Waiter', 'Serve dinner at Cafe Pete',
SYSDATE);
INSERT INTO secret_records (
user_name, service_type, value, date_created
)
VALUES ('Chuck', 'Merger', 'Buy company XYZ', SYSDATE);
SQL Injection Techniques
• Seluruh teknik SQL injection memiliki satu kerentanan: String input tidak divalidasi dengan tepat dan input diubah menjadi pernyataan SQL dinamis.
• Beberapa teknik SQL injection:
– Statement modification
– Statement injection
– Data type conversion
Statement Modification
• Statement modification: dengan sengaja mengubah dynamic SQL statement sehingga berjalan dengan cara yang tidak diinginkan oleh pengembang aplikasi.
• Biasanya, pengguna mengambil data yang tidak sahdengan mengubah klausa WHERE dari pernyataanSELECT atau dengan memasukkan klausa UNION ALL.
• Contoh klasik dari teknik ini adalah bypass otentikasipassword dengan membuat klausa WHERE selalubernilai TRUE.
Prosedur yg Rentan thd Statement Modification
CREATE OR REPLACE PROCEDURE get_record (
user_name IN VARCHAR2,
service_type IN VARCHAR2,
rec OUT VARCHAR2
)
IS
query VARCHAR2(4000);
BEGIN
-- Following SELECT statement is vulnerable to modification
-- because it uses concatenation to build WHERE clause.
query := 'SELECT value FROM secret_records WHERE user_name='''
|| user_name
|| ''' AND service_type='''
|| service_type
|| '''';
DBMS_OUTPUT.PUT_LINE('Query: ' || query);
EXECUTE IMMEDIATE query INTO rec ;
DBMS_OUTPUT.PUT_LINE('Rec: ' || rec );
END;
/
Prosedur Tanpa SQL Injection
DECLARE
record_value VARCHAR2(4000);
BEGIN
get_record('Andy', 'Waiter', record_value);
END;
/
HasilQuery: SELECT value FROM secret_records WHERE
user_name='Andy' AND
service_type='Waiter'
Rec: Serve dinner at Cafe Pete
PL/SQL procedure successfully completed.
Contoh Statement Modification
DECLARE
record_value VARCHAR2(4000);
BEGIN
get_record(
'Anybody '' OR service_type=''Merger''--',
'Anything',
record_value);
END;
/
HasilQuery: SELECT value FROM secret_records WHERE
user_name='Anybody ' OR
service_type='Merger'--' AND service_type='Anything'
Rec: Buy company XYZ
PL/SQL procedure successfully completed.
Record yang seharusnya rahasia dapat dilihat
Statement Injection
• Statment injection: pengguna menambahkan satu atau lebih SQL statement ke dynamic SQL statement.
• Anonymous blok PL / SQL rentan terhadap teknik ini.
Prosedur yg Rentan thd Statement Injection
CREATE OR REPLACE PROCEDURE p (
user_name IN VARCHAR2,
service_type IN VARCHAR2
)
IS
block1 VARCHAR2(4000);
BEGIN
-- Following block is vulnerable to statement injection
-- because it is built by concatenation.
block1 :=
'BEGIN
DBMS_OUTPUT.PUT_LINE(''user_name: ' || user_name || ''');'
|| 'DBMS_OUTPUT.PUT_LINE(''service_type: ' || service_type ||
''');
END;';
DBMS_OUTPUT.PUT_LINE('Block1: ' || block1);
EXECUTE IMMEDIATE block1;
END;
/
Prosedur Tanpa SQL Injection
BEGIN
p('Andy', 'Waiter');
END;
/
HasilBlock1: BEGIN
DBMS_OUTPUT.PUT_LINE('user_name: Andy');
DBMS_OUTPUT.PUT_LINE('service_type: Waiter');
END;
user_name: Andy
service_type: Waiter
Contoh Statement InjectionBEGIN
p('Anybody', 'Anything'');
DELETE FROM secret_records WHERE
service_type=INITCAP(''Merger');
END;
/
HasilBlock1: BEGIN
DBMS_OUTPUT.PUT_LINE('user_name: Anybody');
DBMS_OUTPUT.PUT_LINE('service_type: Anything');
DELETE FROM secret_records WHERE
service_type=INITCAP('Merger');
END;
user_name: Anybody
service_type: Anything
PL/SQL procedure successfully completed.
Satu record berhasil dihapus tanpa otorisasi!
Data Type Conversion
• Sebuah datetime atau nilai numerik yang digabungkan kedalam teks dari sebuah pernyataan SQL dinamis harusdikonversi ke VARCHAR2 tipe data.
• Konversi dapat berupa implisit maupun eksplisit(menggunakan fungsi TO_CHAR).
• Konversi nilai datetime menggunakan model format yang ditentukan dalam parameter NLS_DATE_FORMAT, NLS_TIMESTAMP_FORMAT, atauNLS_TIMESTAMP_TZ_FORMAT, tergantung pada tipe data datetime tertentu. Konversi nilai numerik berlaku desimal dankelompok pemisah yang ditentukan dalamNLS_NUMERIC_CHARACTERS parameter.
Prosedur yg Rentan thd Data Type Conversion
-- Return records not older than a month
CREATE OR REPLACE PROCEDURE get_recent_record (
user_name IN VARCHAR2,
service_type IN VARCHAR2,
rec OUT VARCHAR2
)
IS
query VARCHAR2(4000);
BEGIN
/* Following SELECT statement is vulnerable to modification
because it uses concatenation to build WHERE clause
and because SYSDATE depends on the value of NLS_DATE_FORMAT. */
query := 'SELECT value FROM secret_records WHERE user_name='''
|| user_name
|| ''' AND service_type='''
|| service_type
|| ''' AND date_created>'''
|| (SYSDATE - 30)
|| '''';
DBMS_OUTPUT.PUT_LINE('Query: ' || query);
EXECUTE IMMEDIATE query INTO rec;
DBMS_OUTPUT.PUT_LINE('Rec: ' || rec);
END;
/
Prosedur Tanpa SQL Injection
ALTER SESSION SET NLS_DATE_FORMAT='DD-MON-YYYY';
DECLARE
record_value VARCHAR2(4000);
BEGIN
get_recent_record('Andy', 'Waiter', record_value);
END;
/
HasilQuery: SELECT value FROM secret_records WHERE
user_name='Andy' AND
service_type='Waiter' AND date_created>'29-MAR-2010'
Rec: Serve dinner at Cafe Pete
Contoh Date Type ConversionALTER SESSION SET NLS_DATE_FORMAT='"'' OR
service_type=''Merger"';
DECLARE
record_value VARCHAR2(4000);
BEGIN
get_recent_record('Anybody', 'Anything', record_value);
END;
/
HasilQuery: SELECT value FROM secret_records WHERE
user_name='Anybody' AND
service_type='Anything' AND date_created>'' OR
service_type='Merger'
Rec: Buy company XYZ
PL/SQL procedure successfully completed.
Record yang seharusnya rahasia dapat dilihat
Mencegah SQL InjectionModul 11: PL/SQL Dynamic SQLMelaksanakan perintah SQL menggunakan PL/SQL secara dinamis
• Jika menggunakan dynamic SQL dalam aplikasi PL/SQL , input teks harus dicek apakah sesuai dengan yang diharapkan.
• Beberapa teknik yang dapat digunakan:
– Bind variables
– Validation checks
– Explicit formal models
Bind Variables
• Cara paling efektif untuk mencegak SQL injection.
• Database menggunakan nilai-nilai variabelmengikat secara eksklusif dan tidakmenginterpretasikan isinya dengan caraapapun.
Prosedur yg Baik
CREATE OR REPLACE PROCEDURE get_record_2 (
user_name IN VARCHAR2,
service_type IN VARCHAR2,
rec OUT VARCHAR2
)
IS
query VARCHAR2(4000);
BEGIN
query := 'SELECT value FROM secret_records
WHERE user_name=:a
AND service_type=:b';
DBMS_OUTPUT.PUT_LINE('Query: ' || query);
EXECUTE IMMEDIATE query INTO rec USING user_name, service_type;
DBMS_OUTPUT.PUT_LINE('Rec: ' || rec);
END;
/
Prosedur Tanpa SQL Injection
DECLARE
record_value VARCHAR2(4000);
BEGIN
get_record_2('Andy', 'Waiter', record_value);
END;
/
HasilQuery: SELECT value FROM secret_records
WHERE user_name=:a
AND service_type=:b
Rec: Serve dinner at Cafe Pete
PL/SQL procedure successfully completed.
Percobaan SQL InjectionDECLARE
record_value VARCHAR2(4000);
BEGIN
get_record_2('Anybody '' OR service_type=''Merger''--',
'Anything',
record_value);
END;
/
HasilQuery: SELECT value FROM secret_records
WHERE user_name=:a
AND service_type=:b
DECLARE
*
ERROR at line 1:
ORA-01403: no data found
ORA-06512: at "HR.GET_RECORD_2", line 14
ORA-06512: at line 4
Validation Checks
• Selalu validasi user input untuk menjamin telah sesuai dengan apa yang memang harus diinput.
• Contohnya dengan memvalidasi nama kolom.
• Validasi menggunakan subprogram DBMS_ASSERT.
Prosedur yg BaikCREATE OR REPLACE PROCEDURE raise_emp_salary (
column_value NUMBER,
emp_column VARCHAR2,
amount NUMBER )
IS
v_column VARCHAR2(30);
sql_stmt VARCHAR2(200);
BEGIN
-- Check validity of column name that was given as input:
SELECT column_name INTO v_column
FROM USER_TAB_COLS
WHERE TABLE_NAME = 'EMPLOYEES'
AND COLUMN_NAME = emp_column;
sql_stmt := 'UPDATE employees SET salary = salary + :1 WHERE '
|| DBMS_ASSERT.ENQUOTE_NAME(v_column,FALSE) || ' = :2';
EXECUTE IMMEDIATE sql_stmt USING amount, column_value;
-- If column name is valid:
IF SQL%ROWCOUNT > 0 THEN
DBMS_OUTPUT.PUT_LINE('Salaries were updated for: '
|| emp_column || ' = ' || column_value);
END IF;
-- If column name is not valid:
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE ('Invalid Column: ' || emp_column);
END raise_emp_salary;
/
Lanj...
DECLARE
plsql_block VARCHAR2(500);
BEGIN
-- Invoke raise_emp_salary from a dynamic PL/SQL block:
plsql_block :=
'BEGIN raise_emp_salary(:cvalue, :cname, :amt); END;';
EXECUTE IMMEDIATE plsql_block
USING 110, 'DEPARTMENT_ID', 10;
-- Invoke raise_emp_salary from a dynamic SQL statement:
EXECUTE IMMEDIATE 'BEGIN raise_emp_salary(:cvalue, :cname, :amt); END;'
USING 112, 'EMPLOYEE_ID', 10;
END;
/
HasilSalaries were updated for: DEPARTMENT_ID = 110
Salaries were updated for: EMPLOYEE_ID = 112
Explicit Format Models
• Jika Anda menggunakan datetime dan nilai-nilai numerik yang di rubah menjadi teks SQL atau pernyataan PL / SQL, dan Anda tidakdapat melewatkan mereka sebagai variabelmengikat, mengkonversikannya ke teksmenggunakan model format yang eksplisityang independen dari nilai-nilai parameter NLS sesi berjalan
Prosedur yg Baik
-- Return records not older than a month
CREATE OR REPLACE PROCEDURE get_recent_record (
user_name IN VARCHAR2,
service_type IN VARCHAR2,
rec OUT VARCHAR2
)
IS
query VARCHAR2(4000);
BEGIN
/* Following SELECT statement is vulnerable to modification
because it uses concatenation to build WHERE clause. */
query := 'SELECT value FROM secret_records WHERE user_name='''
|| user_name
|| ''' AND service_type='''
|| service_type
|| ''' AND date_created> DATE '''
|| TO_CHAR(SYSDATE - 30,'YYYY-MM-DD')
|| '''';
DBMS_OUTPUT.PUT_LINE('Query: ' || query);
EXECUTE IMMEDIATE query INTO rec;
DBMS_OUTPUT.PUT_LINE('Rec: ' || rec);
END;
/
Percobaan SQL InjectionALTER SESSION SET NLS_DATE_FORMAT='"'' OR service_type=''Merger"';
DECLARE
record_value VARCHAR2(4000);
BEGIN
get_recent_record('Anybody', 'Anything', record_value);
END;
/
HasilQuery: SELECT value FROM secret_records WHERE user_name='Anybody'
AND
service_type='Anything' AND date_created> DATE '2010-03-29'
DECLARE
*
ERROR at line 1:
ORA-01403: no data found
ORA-06512: at "SYS.GET_RECENT_RECORD", line 21
ORA-06512: at line 4
Referensi
• http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/dynamic.htm#LNPLS011
Terima KasihAlbaar Rubhasy, S.Si., M.T.I.