Forum

SQL Injection Nedir...
 
Bildirimler
Hepsini Temizle

SQL Injection Nedir?

1 Yazılar
1 Üyeler
0 Likes
7,392 Görüntüleme
(@onurserhatuygur)
Gönderiler: 129
Estimable Member
Konu başlatıcı
 

Sql İnjection


SQL
Injection bir veritabanına SQL üzerinden sızma! olarak
özetlenebilir.Yazılan basit, masum SQL ler hiç farkında olunmadan
yapması gereken işlemler dışında programcının istemeyeceği sonuçlara
yol açabilir.Bu durum ,verileri dış dünyaya verme ya da veritabanında
bir paket cağırma vs. şeklinde olabilir.
SQL Injection olması için
veritabanında yazılan kodun “dynamic sql(dynamic sql)” olması
gerekir.Yani SQL , gelecek parametrelere göre runtime esnasında
oluşturulmalıdır.(“bind variable” kullanmanın tek avantajının
performanslı kodlar yazmak olmadığı, veritabanı güvenliği (database
security) içinde önemli olduğu buradan anlaşılmaktadır)

Peki bu
nasıl oluyor?Böyle bir ortamı sağlamak için basit bir yapı
oluşturalım.Elimizde müşterinin ad soyad tlelefon fax ve tip
bilgilerinin tutulduğu bir “customer” tablomuz olsun :
create table customers(
CUSTOMER_FORNAME VARCHAR2(30),
CUSTOMER_SURNAME VARCHAR2(30),
CUSTOMER_PHONE VARCHAR2(30),
CUSTOMER_FAX VARCHAR2(30),
CUSTOMER_TYPE NUMBER(10)
);
Şimdi de birkaç veri girelim :
declare
begin
insert into customers values(’Ali’,’Yilmaz’,999444888,999444889,3);
insert into customers values(’Ahmet’,’Celik’,999555888,999555889,2);
insert into customers values(’Veli’,’Gocer’,999777888,999777889,1);
commit;
end;
Müşterinin soyadını verince telefon numarasını veren bir fonksiyonun aşağıdaki gibi yazıldığını varsayalım:
create or replace procedure getCustPhone(p_surname varchar2)
is
type refCursor ref cursor;
rc refCursor;
thePhone customers.customer_phone%type;
stmt varchar2(32767):=’select customer_phone ‘||
‘from customers ‘||
’where customer_surname=”’||
P_surname||”’’;
begin
dbms_output.put_line(’select str : ‘|| stmt);
open rc for stmt;
loop
fetch rc into thePhone;
exit when cv%notfound;
dbms_output.put_line(’customer phone : ‘||thePhone);
end loop;
close rc;
end getCustPhone;
Ortamımızı hazırladık.Şimdi de mesela soyadı “Yilmaz” olan müşterinin telefon numarası alalım :
declare
cust varchar2(200) := ‘Yilmaz’;
begin
getCustPhone(cust);
dbms_output.put_line(’TEST SONLANDI….’);
end;
CIKTI :
select str : select customer_phone from customers where customer_surname=’Yilmaz’
customer phone : 999444888
TEST SONLANDI….
Buraya kadar her şey yolunda, soyadını verdiğiniz müşterinin telefon numarasını alabiliyorsunuz.
Diyelim
ki bana tüm müşterilerin telefon numarası lazım Bunu elimizdeki bu
fonksiyonla getirebilir miyiz sizce ? Gönderilen parametreyi biraz
düzenleyip!!! deneyelim :
declare
cust varchar2(200) := ‘Yilmaz”’ || ‘ or exists (select 1 from sys.dual) and ‘’x’’ = ‘’x’;
begin
getCustPhone(cust);
dbms_output.put_line(’TEST SONLANDI….’);
end;
CIKTI :
select
str : select customer_phone from customers where
customer_surname=’Yilmaz’ or exists (select 1 from sys.dual) and ‘x’ =
‘x’
customer phone : 999444888
customer phone : 999555888
customer phone : 999777888
TEST SONLANDI….
Evet, başardık  Elimizde sisteme kayıtlı tüm telefon numaraları var artık.
Peki bunu nasıl basardık? “getCustPhone” fonksiyonuna bir göz atalım.Dinamik SQL şu şekilde tasarlanmış :
stmt := ’select customer_phone ‘||’from customers ‘||
‘where customer_surname=”’||p_surname||”’’;
Burada
“p_surname” değişkenine biz ne yazarsak “stmt” SQL stringi o şekilde
oluşacak!!! Zaten SQL Injection durumuna sebeb olan noktada
burası.”Yilmaz” gönderdiğimizde olusan SQL string :
select customer_phone from customers where customer_surname=’Yilmaz’
Son
örneğimizde gönderdiğimiz gibi “’Yilmaz”’ || ‘ or exists (select 1 from
sys.dual) and ‘’x’’ = ‘’x’;” gönderirsek oluşan SQL stringi ise :
select customer_phone from customers
where customer_surname=’Yilmaz’
or exists (select 1 from sys.dual) and ‘x’ = ‘x’
şeklinde!!!”customer_name
= ” eşitliğini sağ tarafına SQL in seyrini değiştirecek fazladan SQL
ler yazabildik! (Ektra yazdıgımız ‘x’ = ‘x’ sadece açık kalacak bir
tırnağı kapamak için kullanılıyor)
Şimdi bu örnekleri arttıralım :
Kurduğumuz “connection”’ın hangi “user” üzerinden yapıldıgını bulalım :
declare
cust varchar2(200) := ‘Yilmaz”’ || ‘ union select sys.login_user from sys.dual where ‘’x’’=’’x’;
begin
getCustPhone(cust);
dbms_output.put_line(’TEST SONLANDI….’);
end;
CIKTI :
select
str : select customer_phone from customers where
customer_surname=’Yilmaz’ union select sys.login_user from sys.dual
where ‘x’=’x’
customer phone : 999444888
customer phone : CUSTINFOUSER
TEST SONLANDI….
Bu
örnekleri arttırmak mümkün.Hatta diğer bir veritabanına giden bir linki
biliyorsak yukarıdakilere benzer örneklerle oradaki bilgilere ulaşmak
bile!Sonuç olarak SQL Injection durumları karşılaşılmayacak seyler
değil ama korunulmasıda gayet basit.”Bind Variable” kullanın!

Şimdi İnternetin keşfiyle birlikte müthiş bir bilgi patlaması yaşandı. İnsanlar
ellerinde olan bilgileri internet aracılığıyla paylaşmaya ve başkaları
tarafından paylaşılmış olan bilgilere ulaşıp yararlanma imkânına kavuştular.
Bilgiler önce salt HTML kodlarında saklanırken bunun verimli olmadığı
anlaşıldı ve dinamik bir dil (Perl, PHP, ASP, ASP.NET , CGI, CFM, JSP vs.) ve
veritabanı sistemleri (MySQL, SQL Server, ORACLE, DB2, Access vs.) ikilisi
web uygulamalardaki yerlerini almaya başladılar. Veritabanı sistemleri
sayesinde daha çok veri saklandı, verilere daha hızlı erişildi ve hemen
hemen neredeyse veritabanı kullanmayan web uygulamaları kalmadı.
Geliştirilen SQL veri sorgulama dili sayesinde veriler veritabanından etkili
bir şekilde çekildi ve kullanıma sunuldu. Fakat internetin getirmiş olduğu
bir zaaf vardı: Güvenlik Eksikliği. Bilgiler, internette güvenli bir şekilde
paylaşılmalıydı ve herkesin kendi yetkisi dahilinde bilgi ve belgeye
ulaşabilmesi sağlanmalıydı. Bunun için web sunucularda güvenliğe önem
verildi. Güvenlik kontrolleri arttırıldı ve daha güvenli bilgi paylaşımı
imkanı sunuldu. Bu sırada gözden kaçan bir nokta vardı: Uygulama Güvenliği.
Acaba yazılan uygulamalar yeterince güvenli miydi? Bu gözden kaçan nokta
aslında büyük bir güvenlik açığı oluşturdu: SQL Injection.

SQL Injection Nedir?

SQL Injection kelime manasıyla da anlaşılabileceği gibi SQL sorgularının
arasına dışarıdan zararlı veri ekleme işlemine verilen isimdir. Dinamik web
uygulamalarında bir veritabanı ve o veritabanı üzerinde çalışan SQL
sorguları vardır. Bu sorgular masum amaçlı bir veya birden fazla tablodan
veriler çekerek etkileşimi sağlamayı amaçlamaktadır. Ama dışarıdaki
kullanıcının uygulamaya gelen girdilere zararlı veri karıştırması sonucu
masum sorgularımız korkunç bir faciaya sebep olurlar.

Web uygulamaları genelde kullanıcıyla etkileşime geçerek dinamik bir arayüz
sunarlar. Bu sırada kullanıcıdan bir takım girdiler(Formdan, URL
Sorgularından, çerezlerden vs.) alırlar ve bunu uygulama içinde işleme
sokarlar ve belli bir çıktı verirler. Bu sırada uygulamamızda bir takım
veritabanına erişecek kodlar, veritabanı üzerinde bir takım sorgular
çalışırlar ve belli bir veri elde ederler. Sonra da bu veriyi düzenleyip
kullanıcıya gönderirler. İşte SQL Injection bu işlemler sırasında devreye
girer. çünkü veritabanı üzerinde bir takım sorgular çalıştırılmak
istenmiştir. Böylece zararlı sorgularımız veritabanı üzerinde çalıştırılmış
olur.

SQL Injection’ın uygulamamıza verebileceği zarar sadece sorgu çalıştırmaktan
ibaret değildir. Sistem, veritabanı ve uygulama yetkilerine göre sistemi
tamamen devre dışı bırakabileceği gibi aynı ağdaki internete açık olmayan
kurumsal makinelerdeki bilgileri erişimden, o ağ kaynaklarını kullanarak
başka yerlere saldırı yapmaya kadar uzanabilen bir yolu açmış demektir.
 Click this bar to view the full image.

Shot at 2007-07-14
Şekil-1: Bir SQL Injection kullanan saldırının anatomisi

Ne kadar sıklıkta gözükür?
• Dinamik websiteleri için en sık gözüken güvenlik açığıdır!
• Uygulama içerisinde yer alan bir çatlaktır. VT veya web sunucu problemi değildir.
• Bir çok programcı bu açıktan habersizdir.
• Webde yer alan birçok uygulama hala SQL Injection barındırmaktadır.
• İnternette yer alan çözümler çok da yeterli değildir.
Hedef Sistemler
• Hemen hemen tüm SQL veritabanı yönetim sistemleri ve programlama dilleri tehdit altındadır:
• MS SQL Server, Oracle, MySQL, Postgres, DB2, MS Access, Sybase, Informix vs.
• Genelde bu dillerde geliştirilmiş uygulamalarda yer almaktadır:
• Veritabanına erişen Perl ve CGI scriptleri • ASP, JSP, PHP , ASP.NET, CFM…
• XML, XSL ve XSQL
• Javascript
• VB, MFC, ve diğer ODBC tabanlı araçlar ve API ’ler
• Raporlamalar ve VT Uygulamaları
• ve bir çok dil…
SQL Injection Nasıl çalışır?

En çok rastlanan login sorgusu:
PHP- Kodu:
SELECT * FROM users WHERE login = ‘ musa ’ AND password = ‘ 123 ’

ASP içerisinde, kullanıcıdan gelen verileri MS SQL Server’da denetlemek üzere şu şekilde bir SQL ifadesi oluşturulur:
PHP- Kodu:
sql = " SELECT * FROM users WHERE login = ’ " + formusr + " ’ AND password = ’ " + formpwd + " ’ ";

SQL Injection için formusr değişkenine şu şekilde bir ifade geldiğini düşünelim:
PHP- Kodu:
formusr = ’ or 1=1 – –formpwd = herhangi bir string

Sorgumuzun son hali aşağıdaki gibi olacaktır:
PHP- Kodu:
SELECT * FROM users WHERE login = ’ ’ or 1=1 -- AND password = ‘ herhangi... ’

Bildiğiniz
gibi – MS SQL Server ve MS Access için SQL sorgularında özel bir anlam
taşımaktadır. – karakterlerinden sonraki gelen herşey yorum(comment)
olarak kabul edilir ve veritabanı motoru tarafından işlenmez.

Veritabanımızı oluşturacak SQL sorguları:
PHP- Kodu:
create
table users( id int, username varchar(255), password varchar(255),
privs int)insert into users values( 0, ’admin’, ’admin’, 100 )insert
into users values( 0, ’guest’, ’guest’, 1 )

Login Sayfamız: login.asp
PHP- Kodu:
<HTML><HEAD><TITLE>Login
Page</TITLE></HEAD><BODY bgcolor=’ 000000’
text=’cccccc’><FONT Face=’tahoma’
color=’cccccc’><CENTER><H1>Login</H1><FORM
action=’process_login.asp’
method=post><TABLE><TR><TD>Username:</TD><TD><INPUT
type=text name=username size=100%
width=100></INPUT></TD></TR><TR><TD>Password:</TD><TD><INPUT
type=password name=password size=100%
width=100></INPUT></TD></TR></TABLE><INPUT
type=submit value=’Submit’><INPUT type=reset
value=’Reset’></FORM></FONT></BODY></HTML>
Login işlemini kontrol eden asp scriptimiz:
PHP- Kodu:
<HTML><BODY
bgcolor=’ 000000’ text=’ffffff’><FONT Face=’tahoma’
color=’ffffff’><STYLE>p { font-size=20pt ! important}font {
font-size=20pt ! important}h1 { font-size=64pt !
important}</STYLE><%@LANGUAGE = JScript %><%function
trace( str ) { if( Request.form("debug") == "true" ) Response.write(
str );} <HTML><BODY bgcolor=’ 000000’
text=’ffffff’><FONT Face=’tahoma’
color=’ffffff’><STYLE>p { font-size=20pt ! important}font {
font-size=20pt ! important}h1 { font-size=64pt !
important}</STYLE><%@LANGUAGE = JScript %><%function
trace( str ) { if( Request.form("debug") == "true" ) Response.write(
str );} //Bağlantıyı Oluşturalım var username; var cn =
Server.createobject( "ADODB.Connection" ); cn.open( "Driver={SQL
Server};server=localhost;uid=sa;pwd=sa;database=No rthwind" ); username
= new String( Request.form("username") ); if( username.length > 0) {
Login( cn ); } cn.close();}Main();%>

Şimdi gelin Tek tırnağın(’) Gücünü hep birlikte adım adım analiz edelim.
• Önce string parametreyi kapattı.
• Ardından gelen bütün ifadeler SQL sorgusu olarak işlendi.
• Ve böylece sisteme yetkisiz erişim hakkı sağlandı
çözüm nedir?
İnternette
yer alan genel çözüm (‘) tek tırnağı 2 tane tek tırnakla (‘’)
değiştirmeniz böylece açılan bir yolu kapatmanız yönünde. Ama aslında
bu çok da yeterli değil. Nedenine değinmeden önce database string
fieldları dışında başka ne gibi fieldlarda sql injection uygulanabilir,
ona bakalım.

Nümerik Alanlar
Eğer nümerik bir alan varsa veritabanında? Evet, onlar da sql injection uygulanabiliyor.
PHP- Kodu:
SELECT * FROM clients WHERE account = 12345678 AND pin = 1111
PHP/MySQL login yapısı:
PHP- Kodu:
$sql="SELECT * FROM clients WHERE “. "account = $formacct AND " . "pin = $formpin";

Nümerik Alana Injection
PHP- Kodu:
$formacct = 1 or 1=1 # $formpin = 1111

Sorgumuzun son hali:
PHP- Kodu:
SELECT * FROM clients WHERE account = 1 or 1=1 # AND pin = 1111

MySQL
için SQL cümleciklerindeki # (diyez) karakteri yorumlardan önce
gelmektedir. Böylece sorgumuzun geri kalan kısmı işleme alınmayacaktır.

Veritabanında tablomuzu oluşturacak SQL sorguları:
PHP- Kodu:
DROP
TABLE IF EXISTS `accounts`;CREATE TABLE IF NOT EXISTS `accounts` (`id`
bigint(20) unsigned NOT NULL auto_increment,`account` bigint(20) NOT
NULL default ’ 0’ ,`pin` bigint(20) NOT NULL default ’ 0’ ,`user_name`
varchar(128) NOT NULL default ’’,PRIMARY KEY (`id`)) TYPE=MyISAM
AUTO_INCREMENT=3 ;---- Tablo döküm verisi `accounts`--INSERT INTO
`accounts` VALUES (1, 123, 123, ’ULKER’);INSERT INTO `accounts` VALUES
(2, 456, 456, ’MUSA’);
Login ekranımızın ve kontrollerimizin olduğu php kodları:
PHP- Kodu:
require(’classes.php’);
session_start();
$db = new db("root","","sql_demo","localhost");
error_reporting(0);

if($_POST[’account’] && $_POST[’pin’]){
if($user=$db->get_row(" SELECT * FROM accounts WHERE account=".$_POST[’account’]." AND pin=".$_POST[’pin’]." LIMIT 1 ")){
echo "Hoş geldiniz $user->user_name ";
}
else
echo "Erişim engellendi !!";
}
else {
?>
<html>
<head>
<title>Güvenli Bir İnternet Sitesi </title>
</head>
<bOdy>
<form id="login" action="<?=$_SERVER[’PHP_SELF’] ?>" method="POST" >
Kullanıcı adı: <input type="text" value="<?=$_POST[’acocount’]?>" size="24" maxlength="20" name="account" />

şifre :<input name="pin" type="text" size="24" maxlength="20" value="<?=$_POST[’pin’]?>"/>

<input type="submit" value="Gönder" />
</form>

Örnekler:

kullanıcı:

1 or 1=1 #

şifre:

1111
</bOdy></html>
<?php}
?>

SQL Injection Karakterleri
PHP- Kodu:

veya " string karakter ayracı -- veya # tek satır yorum /*…*/ çok satır
yorum + toplama, concatenate işlemi (veya URL’de space) || (çift pipe)
concatenate (Oracle ve PostgreSQL’de) % wildcard-ayraç ?Param1= xyz
&Param2= klm URL parametreleri PRINT non-transactional komut olarak
@variable local değişken @@variable global değişken waitfor delay
’0:0:10‘ süre gecikmesi # Access’de tarih ayıracı – çıkarma – Check
Constraint Range

SQL Injection Bulunabilecek Yerler
Formlardaki alanlar
URL sorgu stringlerindeki parametreler
Cookieler
Bu alanların iyi kontrol edilmesi gerekir!

Tek tırnaktan( ’ ) Korunmak
• Bir fonksiyon yardımıyla ( ’ ) karakterini ( ’ ’ ) ile değiştirebiliriz.
• Peki ama ASCII kodu???
ASCII KOD
DEĞER

32
Boşluk

39

45
-

49
1

61
=

79
O

82
R
PHP- Kodu:
SELECT CHAR(49) + CHAR(39) + CHAR(32) + CHAR(79) + CHAR(82) + CHAR(32) + CHAR(49) + CHAR(61) + CHAR(49) + CHAR(45) + CHAR(45)

Sonuçta, Tek tırnak ( ’ ) karakterini temizlesek bile CHAR ve Concat Operatörünü(+) de gelen inputtan arındırmamız gerekiyor.

Sql Enjeksiyonundan Korunma Yaklaşımları

Genel olarak 3 temel yaklaşım var:
1. Sadece İyileri Kabul Etmek
2. Kötüleri Reddetmek
3. Kötüleri Filtreleyerek Kabul Etmek

Sadece İyileri Kabul Etmek

Kullanıcının
sadece belli karakterleri kullanmasına izin vermek.
(abcd........yz012....89 gibi) Bazı bankalarda bu yöntem kullanıyor.
Gelen inputu karakter karakter kontrol edilmesi gerekiyor.

Kötüleri Reddetmek
Güvenli sayılabilir. Ama bazen kullanıcı nerede hata yaptığını anlamaz.

“SELECT”, “ INSERT”, “ UPDATE”, “ DELETE”, “DROP”, “OR”, “,”, “+”

vb. gibi kelimeler barındırıyorsa devam etmeden direk reddedilir.

Kötüleri Filtreleyerek Kabul Etmek
En
basit korunma yöntemidir. Kötüleri reddetme yönteminde olduğu gibi
INSERT + vs özel karakterleri, SQL spesifik kelimeleri arındırarak
kabul etmek.Temel bir koruma sağlar, ama yeterli değildir.

Korunmak için genel kontrol listesi
1. Bütün girdileri kontrol edin!
2. Tüm gelen inputları aksini ispatlayana kadar zararlı olduğunu düşünün.
3. Sisteminize uygun veriye alın ve gerisini reddedin
4. Regular Expressions kullanarak zararlı karakterlerden verinizi temizleyin.
5. Numeric alanları IsNumeric tarzı kontrollerden geçirin.
6. Kodlarınızı en düşük yetkiyle çalıştırın
1. MS SQL için ASLA “sa” yı kullanmayın!
2. MySQL için ASLA “root” kullanmayın!
3. MSSQL için system stored procedürlerinin çalıştırılmasına izin vermeyin
7. Stored Procedure veya parametrize edilmiş SQL cümlecikleri kullanın
8. Database hatalarını kullanıcıya göstermeyin.
Sonuç:
• SQL Injection küçümsenmemesi gereken büyük bir güvenlik açığıdır.
• Yeni yazılımlar çok dikkatli kodlanmalı, eskiler çok dikkatlice gözden geçirilmelidir.
• Burada gösterilmeyen birçok ileri SQL Injection yöntemleri vardır.

 

Kaynak: C|EH

 
Gönderildi : 28/02/2008 06:11

Paylaş: