Zaafiyetlerin oluşum sebepleri ve engellenmesini bilmek sömürmesini bilmekten daha havalı bence
( ben henüz tam bilmiyorum ) .Bu konumda SQL İnjection'a karşı PHP ve MySqli bağlantıları ile alınan ilk önlemden bahsedeceğim.
mysqli_real_escape_string
Anahtar kodumuz bu. Şimdi HTML + PHP ile çok basit bir login sayfası göstereceğim.
not: Konu'da yapılan işlemi çalıştırmanız için php my admin ve MySqli bağlantısı gerekiyor.
Login Sayfası;
<!DOCTYPE html>
<html>
<head>
<title>Login</title>
</head>
<body>
<form actionmethod="GET">
<input type="text" name="username" placeholder="Username" /><br />
<input type="password" name="password" placeholder="**********" /><br />
<input type="submit" name="login" value="LOGIN" />
</form>
</body>
</html>
Login sayfamız burda çok basit bir login sayfası. Şuanda action method GET, normalde login sayfalarında action method POST olmaldıır GET olarak girmemin sebebi az sonra GET ile POST arasında olan fark'a değieneceğim.. bir http isteği, konu da aynı zamanda GET ile POST arasındaki farkı da göreceğiz. Kodları açıklamak gerekirse DOCTYPE d o c u m e n t tipi html olarak belirledik. Browser'a bu bir html dosyası demek gibi. title ise sekme'de yazacak yazı bunları biliyorsunuz. Daha sonra bir form oluşturdum ilk baş bir action method vermedim, input'lar ile devam ettim. Kullanıcımızdan veri istememize yarıyor input textbox oluşturdum. Birisinin tipi text şeklinde diğeri ise password olarak yani yıldızlı şekilde. Placeholder ise textbox'ların üzerine biz bir şey yazmadan önce yazacak yazı ( en iyi böyle açıklayabiliyorum
) . br'ler ise bir alt satıra geçmemizi sağlayan kodlarımız. Son input ise bir buton görevi görüyor tipi submit VALUE ise üzerinde yazacak olan LOGIN.
Sayfayı göstereyim;

Sayfamız bu şekilde. Şimdi action method'a GET verdik yani bir GET isteği. GET isteği POST isteğine göre daha hızlı ama daha güvensizdir. username kısmına test pass'e de 123 giriyorum ve LOGIN olmayı deniyorum.

URL'ye dikkat ederseniz test&password=123&login=LOGIN böyle bir şey görüyorsunuz. İşte buna sebep olan olay GET isteği. Birde action method'u POST olarak değiştirelim. test&password=123&login=LOGIN bu kısmı silip enter basalım sayfa yenilenmesi için, username e test pass'e 123 girdiğimizde bu sefer URL'de böyle bir şey çıkmıyor.
Şimdi esas olayımıza, PHP kodlarımıza gelelim;
<?php
$hostname = "localhost";
$username = "root";
$password = "";
$dbname = "test";
$conn = mysqli_connect($hostnmae, $username, $password, $dbname);
if(!$conn) {
die("Unable to connect")
}
if($_POST) {
$uname = $POST["username"];
$pass = $_POST["password"];
$uname = ($uname);
$pass = ($pass);
$sql = "SELECT*FROM users_tutorial WHERE username = '$uname' AND password= '$pass' ";
$result = mysli_query($conn, $sqli);
if(mysqli_num_rows(½result) == 1) {
echo "Hoşgeldiniz, user!";
} else {
echo "Incorrect Username/Password";
}
}
?>
Conn adlı değişkenle hostname, username, password, dbname (database name) bunları mysqli_connect ettim. Bir if sorgusu ekledim ( İF yoksa zaafiyet var demektir ), Eğer conn mysqli_connect'e bağlanamazsa Unable to connect döndürecek. Daha sonra ise POST isteklerini username ve password'e bağlantı kurdum. Ve bir SQL sorgusu, klasik SELECT * FROM sorgumuzu girdim. Zaafiyet oluşumunda burası çok önemli.
"SELECT*FROM users_tutorial WHERE username = '$uname' AND password= '$pass' ";
Burdaki uname ve pass kısımlarına kullanıcının girdiği değerler gelecek. Kullanıcı istediği her şeyi girebilir şuanlık, bir tek tırnak girmesi durumunda sorgunun kafası karışacak. username=''' olacak. Bunları or, AND , 1=1 gibi şeyler ile desteklemesi durumunda login olmamızı sağlayacak. Denemek için phpmyadmin gerekli, deneme olarak username'e test' or 1=1# girin pass'e de random bir şeyler girin( #den sonrası okunmaması sağlanıyor sorgunun, pass e girilen önemli değil ). Bizi login edecek. İşte tam da buna önlem olarak mysqli_real_escape_string kullanılıyor. Bu fonksiyon ',#,(),{] ...... vb. karakterlerin girilmesi durumunda bizi login etmiyor yaptığı görev bu.
<?php
$hostname = "192.168.1.11";
$username = "root";
$password = "";
$dbname = "test";
$conn = mysqli_connect($hostnmae, $username, $password, $dbname);
if(!$conn) {
die("Unable to connect")
}
if($_POST) {
$uname = $POST["username"];
$pass = $_POST["password"];
$uname = mysqli_real_escape($uname);
$pass = mysqli_real_escape($pass);
$sql = "SELECT*FROM users_tutorial WHERE username = '$uname' AND password= '$pass' ";
$result = mysli_query($conn, $sqli);
if(mysqli_num_rows(½result) == 1) {
echo "Hoşgeldiniz, user!";
} else {
echo "Incorrect Username/Password";
}
}
?>
Siz fark etmeden ben diyeyim burda bir hata söz konusu. Kodumuza sadece mysqli_real_escape ekledik string'i koymayı unuttum aynı zamanca conn değeri de yok. Buda fonksiyonun düzgün çalışmamasına sebebiyet veriyor. Deneyip fark edince;
<?php
$hostname = "192.168.1.11";
$username = "root";
$password = "";
$dbname = "test";
$conn = mysqli_connect($hostnmae, $username, $password, $dbname);
if(!$conn) {
die("Unable to connect")
}
if($_POST) {
$uname = $POST["username"];
$pass = $_POST["password"];
$uname = mysqli_real_escape_string($conn ,$uname);
$pass = mysqli_real_escape_string($conn, $pass);
$sql = "SELECT * FROM users_tutorial WHERE username = '$uname' AND password= '$pass' ";
$result = mysli_query($conn, $sqli);
if(mysqli_num_rows(½result) == 1) {
echo" Hoşgeldiniz, user!";
} else {
echo "Incorrect Username/Password";
}
}
?>
<!DOCTYPE html>
<html>
<head>
<title>Login</title>
</head>
<body>
<form actionmethod="POST">
<input type="text" name="username" placeholder="Username" /><br />
<input type="password" name="password" placeholder="**********" /><br />
<input type="submit" name="login" value="LOGIN" />
</form>
</body>
</html>
Kodumuzun son hali bu şekilde oldu. Eğer yine test' or 1=1# girerseniz bu sefer
echo "Incorrect Username/Password"; kodunu çalıştıracak ve ekranda Incorrect Username/Password göreceğiz. Peki bu ile bir önceki kod arasındaki fark ne? Bir önceki kodda username'e test' or 1=1# denendiğinde hatalar veriyordu, hata değilde ben Incorrect Username/Password vermesini istiyordum, ( bazen hatalar üzerinden yararlanılarak DataBase bilgilerine ulaşılabilir ) . Araştırdım son hali bu...
mysqli_real_escape_string
Anahtar kodumuz bu. Şimdi HTML + PHP ile çok basit bir login sayfası göstereceğim.
not: Konu'da yapılan işlemi çalıştırmanız için php my admin ve MySqli bağlantısı gerekiyor.
Login Sayfası;
<!DOCTYPE html>
<html>
<head>
<title>Login</title>
</head>
<body>
<form actionmethod="GET">
<input type="text" name="username" placeholder="Username" /><br />
<input type="password" name="password" placeholder="**********" /><br />
<input type="submit" name="login" value="LOGIN" />
</form>
</body>
</html>
Login sayfamız burda çok basit bir login sayfası. Şuanda action method GET, normalde login sayfalarında action method POST olmaldıır GET olarak girmemin sebebi az sonra GET ile POST arasında olan fark'a değieneceğim.. bir http isteği, konu da aynı zamanda GET ile POST arasındaki farkı da göreceğiz. Kodları açıklamak gerekirse DOCTYPE d o c u m e n t tipi html olarak belirledik. Browser'a bu bir html dosyası demek gibi. title ise sekme'de yazacak yazı bunları biliyorsunuz. Daha sonra bir form oluşturdum ilk baş bir action method vermedim, input'lar ile devam ettim. Kullanıcımızdan veri istememize yarıyor input textbox oluşturdum. Birisinin tipi text şeklinde diğeri ise password olarak yani yıldızlı şekilde. Placeholder ise textbox'ların üzerine biz bir şey yazmadan önce yazacak yazı ( en iyi böyle açıklayabiliyorum
Sayfayı göstereyim;

Sayfamız bu şekilde. Şimdi action method'a GET verdik yani bir GET isteği. GET isteği POST isteğine göre daha hızlı ama daha güvensizdir. username kısmına test pass'e de 123 giriyorum ve LOGIN olmayı deniyorum.

URL'ye dikkat ederseniz test&password=123&login=LOGIN böyle bir şey görüyorsunuz. İşte buna sebep olan olay GET isteği. Birde action method'u POST olarak değiştirelim. test&password=123&login=LOGIN bu kısmı silip enter basalım sayfa yenilenmesi için, username e test pass'e 123 girdiğimizde bu sefer URL'de böyle bir şey çıkmıyor.
Şimdi esas olayımıza, PHP kodlarımıza gelelim;
<?php
$hostname = "localhost";
$username = "root";
$password = "";
$dbname = "test";
$conn = mysqli_connect($hostnmae, $username, $password, $dbname);
if(!$conn) {
die("Unable to connect")
}
if($_POST) {
$uname = $POST["username"];
$pass = $_POST["password"];
$uname = ($uname);
$pass = ($pass);
$sql = "SELECT*FROM users_tutorial WHERE username = '$uname' AND password= '$pass' ";
$result = mysli_query($conn, $sqli);
if(mysqli_num_rows(½result) == 1) {
echo "Hoşgeldiniz, user!";
} else {
echo "Incorrect Username/Password";
}
}
?>
Conn adlı değişkenle hostname, username, password, dbname (database name) bunları mysqli_connect ettim. Bir if sorgusu ekledim ( İF yoksa zaafiyet var demektir ), Eğer conn mysqli_connect'e bağlanamazsa Unable to connect döndürecek. Daha sonra ise POST isteklerini username ve password'e bağlantı kurdum. Ve bir SQL sorgusu, klasik SELECT * FROM sorgumuzu girdim. Zaafiyet oluşumunda burası çok önemli.
"SELECT*FROM users_tutorial WHERE username = '$uname' AND password= '$pass' ";
Burdaki uname ve pass kısımlarına kullanıcının girdiği değerler gelecek. Kullanıcı istediği her şeyi girebilir şuanlık, bir tek tırnak girmesi durumunda sorgunun kafası karışacak. username=''' olacak. Bunları or, AND , 1=1 gibi şeyler ile desteklemesi durumunda login olmamızı sağlayacak. Denemek için phpmyadmin gerekli, deneme olarak username'e test' or 1=1# girin pass'e de random bir şeyler girin( #den sonrası okunmaması sağlanıyor sorgunun, pass e girilen önemli değil ). Bizi login edecek. İşte tam da buna önlem olarak mysqli_real_escape_string kullanılıyor. Bu fonksiyon ',#,(),{] ...... vb. karakterlerin girilmesi durumunda bizi login etmiyor yaptığı görev bu.
<?php
$hostname = "192.168.1.11";
$username = "root";
$password = "";
$dbname = "test";
$conn = mysqli_connect($hostnmae, $username, $password, $dbname);
if(!$conn) {
die("Unable to connect")
}
if($_POST) {
$uname = $POST["username"];
$pass = $_POST["password"];
$uname = mysqli_real_escape($uname);
$pass = mysqli_real_escape($pass);
$sql = "SELECT*FROM users_tutorial WHERE username = '$uname' AND password= '$pass' ";
$result = mysli_query($conn, $sqli);
if(mysqli_num_rows(½result) == 1) {
echo "Hoşgeldiniz, user!";
} else {
echo "Incorrect Username/Password";
}
}
?>
Siz fark etmeden ben diyeyim burda bir hata söz konusu. Kodumuza sadece mysqli_real_escape ekledik string'i koymayı unuttum aynı zamanca conn değeri de yok. Buda fonksiyonun düzgün çalışmamasına sebebiyet veriyor. Deneyip fark edince;
<?php
$hostname = "192.168.1.11";
$username = "root";
$password = "";
$dbname = "test";
$conn = mysqli_connect($hostnmae, $username, $password, $dbname);
if(!$conn) {
die("Unable to connect")
}
if($_POST) {
$uname = $POST["username"];
$pass = $_POST["password"];
$uname = mysqli_real_escape_string($conn ,$uname);
$pass = mysqli_real_escape_string($conn, $pass);
$sql = "SELECT * FROM users_tutorial WHERE username = '$uname' AND password= '$pass' ";
$result = mysli_query($conn, $sqli);
if(mysqli_num_rows(½result) == 1) {
echo" Hoşgeldiniz, user!";
} else {
echo "Incorrect Username/Password";
}
}
?>
<!DOCTYPE html>
<html>
<head>
<title>Login</title>
</head>
<body>
<form actionmethod="POST">
<input type="text" name="username" placeholder="Username" /><br />
<input type="password" name="password" placeholder="**********" /><br />
<input type="submit" name="login" value="LOGIN" />
</form>
</body>
</html>
Kodumuzun son hali bu şekilde oldu. Eğer yine test' or 1=1# girerseniz bu sefer
echo "Incorrect Username/Password"; kodunu çalıştıracak ve ekranda Incorrect Username/Password göreceğiz. Peki bu ile bir önceki kod arasındaki fark ne? Bir önceki kodda username'e test' or 1=1# denendiğinde hatalar veriyordu, hata değilde ben Incorrect Username/Password vermesini istiyordum, ( bazen hatalar üzerinden yararlanılarak DataBase bilgilerine ulaşılabilir ) . Araştırdım son hali bu...
Son düzenleme:




