protect SQL Injection in oracle

 

محافظت در برابر حمله تزريق در دیتابیس اوراکل

 

?How SQL injection works چگونه كار مي كند
براي درك بهتر, مسائل را با مثال دنبال مي كنيم. در ابتدا فرض مي كنيم كه يك جدول داريم كه داراي دو فيلد username , password مي باشد
create table user_access
(
username varchar2(10) not null primary key,
password varchar2(10) not null
);
insert into user_access values ('SAEED','SAEEDPASS');
commit;
حال فرض مي كنيم كه در وب سايت مي خواهيم عمل چك پسورد را انجام دهيم
select password
from user_access
where username = username_from_the_field_on_website
استفاده از روش بالا بساير خطرناك مي باشد زيرا هر كسي با داشتن مجوز به جدول USER_ACCESS در دیتابیس Oracle مي تواند به اطلاعات دست پيدا كند
از روش ديگري استفاده مي كنيم و براي بدست آوردن صحيح بودن پسورد از يك فانكشن همانند زير ايجاد مي كنيم:
create or replace function is_password_correct
(
p_username in varchar2,
p_password in varchar2
)
return varchar2
is
l_stmt varchar2(4000);
l_check varchar2(10) := 'wrong';
begin
l_stmt :=
'select ''correct'' from user_access '||
'where username = '''||
p_username ||''' and password = '''
||p_password||'''';
dbms_output.put_line('l_stmt='||l_stmt);
execute immediate l_stmt into l_check;
return l_check;
end;
/
در روش بالا ديگر نيازي نمي باشد كه دسترسي جدول به كاربر وب سايت داده شود و عمل كنترل پسورد از طريق فانكشن انجام مي شود.
حال وب سايت به ديتابيس اوراکل با يوزر مثلا RUNUSER متصل شده ولي دسترسي به جدول USER_ACCESS ندارد و به وسيله كوئري زير مي تواند عمل چك كردن پسورد را انجام دهد:
select is_password_correct('SAEED','SAEEDPASS') from dual;
اگر خروجي “correct” بود يعني اينكه رمز عبور صحيح مي باشد و در غير اينصورت اگر خالي بود يعني پسورد اشتباه است. خوب الان هكر پسورد را ندارد ولي بوسيله ?حقه اي ? ? مي تواند خروجي “correct” را براي خودش بدست بياورد. به كوئري زير در اوراکل توجه كنيد:
SQL> select
2 is_password_correct('SAEED','WrongPass'' or ''1''=''1')
3 "Password Check"
4 from dual
5 /
Password Check
—------------
Correct
به كوئري بالا  در دیتابیس Oracle دقت كنيد با پسورد اشتباه هم توانست خروجي Correct را بدست بياورد. كوئري بالا همانند كوئري زير اجرا مي شود:
select 'correct' from user_access where username = 'SAEED' and
password = 'WrongPass' or '1'='1'
بوسيله اضافه كردن ‘1’=’1’ توانست براحتي پسورد اصلي رو دور بزند و خود را valid كند. اين همان? SQL injection? است.
خوب حالا براي جلوگيري از اين عمل چه كاري مي توانيم انجام دهيم. يك راه حل استفاده از? Bind Variables ? مي باشد. حال ما دوباره فانكشن را در دیتابیس اوراکل ، مربوط به چك كردن پسورد را بازنويسي مي كنيم.
create or replace function is_password_correct
(
p_username in varchar2,
p_password in varchar2
)
return varchar2
is
l_stmt varchar2(4000);
l_check varchar2(10) := 'wrong';
begin
l_stmt :=
'select ''correct'' from user_access '||
'where username = '''||
p_username ||''' and password = :l_password';
dbms_output.put_line('l_stmt='||l_stmt);
execute immediate l_stmt into l_check
using p_password;
return l_check;
end;
/
حال وقتي هكر دوباره كوئري بالا را اجرا مي كند نمي تواند Correct را بدست بياورد و در اين روش از SQL Injection در اوراکل جلوگيري مي شود.
SQL> select
2 is_password_correct('SAEED','WrongPass'' or ''1''=''1')
3 from dual
4 /
IS_PASSWORD_CORRECT('SAEED','WRONGPASS''OR''1''=''1')
اگر دقت كنيد نمي تواند مجوز صحت اين پسورد را بدست بياورد و در واقع در پشت صحنه كوئري همانند زير اجرا مي شود:
l_stmt=select 'correct' from user_access where username ='SAEED' and password = :l_password
استفاده از Bind Variables در اوراکل مي تواند در بعضي از مواقع مشكل ساز باشد مواقعي كه مي خواهيم مقادير نام جدول و ستون ها بصورت دايناميك باشد و اينكه بايد تغيرات زيادي را متحمل شويم. و همچنین مسائل مربوط به Performance هم نيز مطرح مي شود.
در اينجا اوراكل پكيجي به نام? DBMS_ASSERT? دارد كه بسيار موثر و مفيد مي باشد و مي تواند در اين زمينه به ما كمك كند كه به جاي استفاده از Bind Variables از آن استفاده نماييم. اين پكيج از نسخه Oracle 10g قابل استفاده مي باشد.

 

نحوه حذف تهدید با استفاده از یکی از ابزارهای داخلی Oracle
يكي از فانكشن هايي كه مي توانيم در اوراکل استفاده كنيم ?enquote_literal? مي باشد. دقيقا همان رشته اي را كه مي دهيد برمي گرداند به مثال زير توجه كنيد:
SQL> select dbms_assert.enquote_literal('WrongPass') from dual;
DBMS_ASSERT.ENQUOTE_LITERAL('WRONGPASS')
—------------------------------------—
'WrongPass'
خوب حالا هكر مي خواهد حمله SQL Injection انجام دهد و كوئري زير را اجرا مي نمايد:

select dbms_assert.enquote_literal('WrongPass'' or ''1''=''1')
from dual
*
ERROR at line 1:
ORA-06502: PL/SQL: numeric or value error
ORA-06512: at "SYS.DBMS_ASSERT", line 409
ORA-06512: at "SYS.DBMS_ASSERT", line 493
همانطور كه مي بينيد با خطا مواجه مي شود زيرا quotes نمي تواند بدرستي در هنگام اجرا تنظيم شود. و دستور دقيقا همانند مقدار وروردي اجرا مي شود.
دوباره فانكشن را در دیتابیس اوراکل ، مربوط به چك پسورد را بازنويسي مي كنيم:

create or replace function is_password_correct
(
p_username in varchar2,
p_password in varchar2
)
return varchar2
is
l_stmt varchar2(4000);
l_check varchar2(10) := 'wrong';
begin
l_stmt :=
'select ''correct'' from user_access '||
'where username = '''||
p_username ||''' and password = '||
sys.dbms_assert.enquote_literal(p_password)||'';
dbms_output.put_line('l_stmt='||l_stmt);
execute immediate l_stmt into l_check;
return nvl(l_check,'wrong');
end;
وقتي دستور زير را اجرا مي نماييم خروجي ما بدين صورت مي شود:

select
is_password_correct('SAEED','WrongPass'' or ''1''=''1')
from dual;
ERROR at line 2:
ORA-06502: PL/SQL: numeric or value error
ORA-06512: at "SYS.DBMS_ASSERT", line 409
ORA-06512: at "SYS.DBMS_ASSERT", line 493
ORA-06512: at "IS_PASSWORD_CORRECT", line 11
همانطور كه مي بينيد هكر با اجراي كوئري بالا با خطا مواجه شد. اگر بخواهيد كه خطاي numeric or value error را مشاهده نكنيد مي توانيد با استفاده از exception پيغام مورد نظر خود را نشان دهيد:

create or replace function is_password_correct
(
p_username in varchar2,
p_password in varchar2
)
return varchar2
is
l_stmt varchar2(4000);
l_sanitized_password varchar2(4000);
l_check varchar2(10) := 'wrong';
l_possible_injection_exception exception;
begin
declare
l_possible_injection_exception exception;
pragma exception_init (l_possible_injection_
exception,-6502);
begin
l_sanitized_password := sys.dbms_assert.enquote_
literal(p_password);
exception
when l_possible_injection_exception then
raise_application_error (-20001,'Possible SQL
Injection Attack');
when OTHERS then
raise;
end;
l_stmt :=
'select ''correct'' from user_access '||
'where username = ''||
p_username ||''' and password = '||
l_sanitized_password
||'';
dbms_output.put_line('l_stmt='||l_stmt);
execute immediate l_stmt into l_check;
return nvl(l_check,'wrong');
end;
/
پس از اجراي دوباره كوئري در اوراکل مي توانيد خروجي زير را مشاهده كنيد

SQL> select
2 is_password_correct('SAEED','WrongPass'' or ''1''=''1')
3 from dual
4 /
is_password_correct('SAEED','WrongPass'' or ''1''=''1')
*
ERROR at line 2:
ORA-20001: Possible SQL Injection Attack
ORA-06512: at "IS_PASSWORD_CORRECT", line 21
و در آخر اينكه مي توان براي چك كردن كوئري فانكشن ديگر به نام? simple_sql_name? نيز استفاده كرد.
امیدوار هستم که مورد استفاده دوستان قرار گیرد.

 

5/5 - (1 امتیاز)

1 دیدگاه. پیغام بگذارید

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

این قسمت نباید خالی باشد
این قسمت نباید خالی باشد
لطفاً یک نشانی ایمیل معتبر بنویسید.

keyboard_arrow_up
Oracle APEX Capabilities (OAC)