Thursday, August 9, 2012

SQL Injection Attack ကို ဘယ္လို ကာကြယ္ၾကမလဲ

From -ျမန္မာ့ကြန္ပ်ဴတာအေရးေပၚတံုျပန္ေရးအဖြဲ႕႕
SQL Injection ကို ကာကြယ္ရာတြင္ User Input တြင္ လက္ခံေသာ characters မ်ားကို ကန္႔သတ္ထားျခင္း၊ data access အတြက္ သတ္မွတ္ထားေသာ SQL query မ်ားကို သံုးျခင္း၊ database တြင္ ခြင့္ျပဳခ်က္ကန္႔သတ္ခ်က္မ်ား႐ွိသည့္ အနည္းဆံုး privileged account တစ္ခုကိုသံုးျခင္း အစ႐ွိသည့္ေျဖ႐ွင္းနည္းမ်ားျဖင့္ ေျဖ႐ွင္းရပါမည္။
ရည္႐ြယ္ခ်က္မ်ား

♦ SQL injection attacks အလုပ္လုပ္ပံုကို ေလ့လာရန္
♦ SQL injection ကို ကာကြယ္ရန္အတြက္ user input လက္ခံသည္မ်ားကို ကန္႔သတ္ရန္
♦ SQL injection ကို ကာကြယ္ရန္ လံုၿခံဳမႈ႐ွိသည့္ SQL Command parameters မ်ားကို အသံုးျပဳရန္
♦ Database ႏွင့္ ခ်ိတ္ဆက္ရန္ အနည္းဆံုး ကန္႔သတ္ထားသည့္ account တစ္ခုကို အသံုးျပဳရန္
♦ Risk ေလ်ာ့ခ်မႈကို အက်ဳိးျပဳရန္အတြက္ ေျဖ႐ွင္းနည္းမ်ားကို ေနာက္ထပ္ ေလ့လာရန္

သံုးသပ္ခ်က္မ်ား
မသမာသည့္ရည္႐ြယ္ခ်က္ျဖင့္အသံုးျပဳမည့္သူတစ္ေယာက္ကို အေထာက္အကူ ျပဳေစႏိုင္ေသာ database commands မ်ား အလုပ္လုပ္သြားေစႏိုင္သည့္ Login page မွ အားနည္းခ်က္မ်ားကို အသံုးျပဳျခင္းျဖင့္ SQL injection တစ္ခုျဖစ္ေျမာက္ ႏိုင္ပါသည္။ application မွ database ကို ခ်ိတ္ဆက္ရန္ over-privileged account တစ္ခုကို အသံုးျပဳလွ်င္ ဒီျပသနာက ပိုၿပီး ႀကီးႏိုင္ပါတယ္။ ဥပမာအားျဖင့္ သင့္ application’s Login page တြင္ database တစ္ခုကို ဖ်က္ပစ္ႏုိင္သည့္ ကာကြယ္မႈမ်ဳိး မလုပ္ထားဘူးဆုိလွ်င္ Attacker တစ္ေယာက္က ဖ်က္ပစ္ႏုိင္ပါလိမ့္မည္။
SQL injection attacks မ်ားျဖစ္ရန္ သင့္ရဲ႕ Data လက္ခံသည့္ေနရာတြင္ သံသရျဖစ္စရာ Code မ်ား ပါသည့္ အဓိက အားနည္းခ်က္မ်ားမွာ
- User ႐ိုက္လိုက္သည္မ်ားကို စစ္ေဆးမႈ အားနည္းျခင္း
- စနစ္က်သည့္ parameters မ်ားကို မသံုးဘဲ SQL statements မ်ားကို တည္ေဆာက္ျခင္း
- Over-privileged database login မ်ားကို သံုးျခင္း

SQL Injection နမူနာ
User တစ္ေယာက္က SSN လို႔ အမည္ေပးထားတဲ့ text box တြင္ ေအာက္တြင္ျပထားေသာ String ကို ႐ိုက္လိုက္တဲ့အခါ ဘယ္လိုျဖစ္မလဲ စဥ္းစားၾကည့္ပါ။
' ; DROP DATABASE pubs --
၄င္း string ကို text box တြင္ ထည့္လိုက္ျခင္းျဖင့္ ၄င္း application တြင္ ေအာက္မွာေဖာ္ျပထားေသာ Dynamic SQL Statement (သို႔) Store Procedure (SQL statement တစ္ခု ကဲ့သို႔ အတြင္းပိုင္းတြင္ အလုပ္လုပ္ေသာ) တို႔မွာ အလုပ္ လုပ္သြားပါတယ္။

    // Use dynamic SQL
    SqlDataAdapter myCommand = new SqlDataAdapter(
         "SELECT au_lname, au_fname FROM authors WHERE au_id = '" + 
          SSN.Text + "'", myConnection);

    // Use stored procedures
    SqlDataAdapter myCommand = new SqlDataAdapter(
         "LoginStoredProcedure '" + SSN.Text + "'", myConnection);

Code ကို run သည့္အခါ ၄င္း code တြင္ user ၏ အခ်က္အလက္ကို ထည့္ၿပီး ေအာက္ပါ SQL Statement တစ္ခုကို ျဖစ္ေပၚေစျခင္းသည္ Developer ၏ ရည္႐ြယ္ခ်က္ျဖစ္ပါသည္။
    SELECT au_lname, au_fname FROM authors WHERE au_id = '172-32-9999'
သို႔ေသာ္လည္း Code တြင္ user ၏ malicious ပါ၀င္သည့္ အခ်က္အလက္ကို ထည့္ၿပီး ေအာက္ပါ query ကို ျဖစ္ေပၚေစပါသည္။
    SELECT au_lname, au_fname FROM authors WHERE au_id = ''; DROP DATABASE pubs --'
အေၾကာင္းမွာ ‘ (single quotation mark) မွာ Malware ပါသည့္ input သည္ SQL statement တြင္ ႐ွိေသာ တိက်တဲ့ current string တစ္ခုကို ရပ္လိုက္ပါသည္။ ေအာက္ပါသာဓကမွာ current statement ကို ဆက္၍ အလုပ္မလုပ္ပါ။ ဒါေပမယ့္ new statement တစ္ခုကို စလုပ္လွ်င္ current statement ကို ပိတ္လိုက္ျခင္းျဖစ္သည္။ လႊဲမွားတဲ့ input ရဲ႕ single quotation mark အဖြင့္သည္ ေအာက္ပါ စာေၾကာင္းတြင္ အက်ဳိးဆက္ကို ေတြ႕ႏိုင္ပါသည္။
    SELECT au_lname, au_fname FROM authors WHERE au_id = ' '
; (semicolon) မွာ SQL statement တြင္ statement တစ္ခု အလုပ္ၿပီးဆံုးသြားလွ်င္ ပိတ္သည့္ သေကၤတျဖစ္ၿပီး ေအာက္ပါ malicious SQL code မွာ ယင္း ; (semicolon) ၏ ေနာက္တြင္ပါလာျခင္းျဖစ္သည္။
    ; DROP DATABASE pubs
; သည္ SQL statements မ်ားကို ခြဲျခားရန္ လိုအပ္သည့္ လိုအပ္မႈမ်ဳိးမဟုတ္ပါ။ vendor (သို႔) implementation ေပၚတြင္ မူတည္ပါသည္။ သို႔ေသာ္ Microsoft SQL Server သည္ ၄င္းတို႔ကို မလုိအပ္ပါ။ ဥပမာ SQL Server မွာ သီးျခား စာေၾကာင္း ႏွစ္ခုကဲ့သို႔ ေအာက္တြင္ ခြဲလိုက္ပါသည္။
    SELECT * FROM MyTable DELETE FROM MyTable
ေနာက္ဆံုး -- (double dash) သည္ text ေတြကို အလုပ္မလုပ္ဖို႔ ပိတ္ထားသည္ SQL comment တစ္ခုျဖစ္ပါသည္။ SQL သည္ တျခားနည္းျဖင့္ SQL parser error တစ္ခုကို ျဖစ္ေစသည့္ ‘ (single quotation mark ) အပိတ္ကို ဂ႐ုမျပဳပါ။
--'
လမ္းၫႊန္ခ်က္မ်ား
SQL injection attacks မ်ားကို တုန္႔ျပန္ရန္ လိုအပ္ခ်က္မ်ားမွာ-
- Input data မ်ားကို ကန္႔သတ္ထားရန္ႏွင့္ ေသခ်ာစစ္ေဆးပါ။ type , length, format ႏွင့္ range မ်ားကို စစ္ျခင္းျဖင့္ သန္႔စင္သည့္ data ျဖစ္ရန္ စစ္ေဆးရပါမည္။
- Data access အတြက္ လံုၿခံဳစိတ္ခ်ရတဲ့ SQL parameters မ်ားကို သံုးပါ။ SQL paramenters မ်ားအား stored procedures (သို႔) SQL command strings မ်ားကို တည္ေဆာက္သည့္ dynamically ေနရာမ်ားတြင္လည္း သံုးႏိုင္ပါသည္။
   - SQLParameterCollection ကဲ့သို႔ Parameter collections မ်ားသည္ type စစ္ျခင္းႏွင့္ Length validation တို႔ကို ေထာက္ပံ့သည္။ parameters collection တစ္ခုကို သံုးလွ်င္ input ကို တိက်တဲ့တန္ဖိုးတစ္ခုကဲ့သို႔ သံုးၿပီး SQL Server သည္ excutable code ကဲ့သို႔ ၄င္းကို မသံုးပါ။ parameter collection တစ္ခုကို သံုးျခင္းျဖင့္ type ႏွင့္ length စစ္ျခင္းမ်ားကို အတည္ျပဳႏိုင္သည့္ အက်ဳိးေက်းဇူးရွိပါသည္။ Values outside of the range trigger an exception. ၄င္းမွာ နက္နဲတဲ့ ကာကြယ္မႈ ဥပမာေကာင္းတစ္ခုျဖစ္ပါသည္။
- Database တြင္ permissions ကန္႔သတ္ထားေသာ account တစ္ခုကို သံုးပါ။ အထူးသျဖင့္ database တြင္ stored procedures မ်ားကို ေ႐ြးခ်ယ္ဖို႔ လုပ္ေဆာင္ႏိုင္သည့္ permissions မ်ားကိုသာ သေဘာတူသင့္ၿပီး table မ်ားကို တိုက္႐ုိက္ လက္ခံမႈမ်ဳိး မ႐ွိသင့္ပါ။
- Database Error Information မ်ားကိုထုတ္ေဖာ္ေျပာျခင္းမ်ဳိးကို ေ႐ွာင္ပါ။ database error မ်ား၏ အေသးစိတ္ error မ်ားကို user မ်ားအား ထုတ္ေဖာ္မေျပာမိေစရန္ သတိျပဳပါ။
မွတ္ခ်က္ ။ ။ လံုၿခံဳမႈအား SSL (Secure Socket Layer) ႏွင့္ IP Security မ်ားကို သံုးျခင္းျဖင့္ တိုင္းတာပါ။

အက်ဥ္းခ်ဳပ္အဆင့္မ်ား
SQL injection မွ ကာကြယ္ရန္ ေအာက္ပါအခ်က္မ်ားကို ေဆာင္႐ြက္ပါ။
- အဆင့္ ၁ input ကို ကန္႔သတ္ပါ။
- အဆင့္ ၂ stored procedures မ်ားႏွင့္အတူ parameters မ်ားကို သံုးပါ။
- အဆင့္ ၃ dynamic SQL ႏွင့္အတူ parameters မ်ားကို သံုးပါ။

အဆင့္ ၁ input ကို ကန္႔သတ္ျခင္း ASP.NET application တြင္ type ၊ length ၊ format ႏွင့္ range တို႔အတြက္ input အားလံုးကို စစ္သင့္ပါသည္။ data access queries တြင္ input ကို ကန္႔သတ္ျခင္းျဖင့္ SQL injection ကာကြယ္ႏိုင္ပါသည္။
မွတ္ခ်က္ ။ ။ input ကန္႔သတ္သည့္ျခင္းသည္ လက္ခံေသာ characters မ်ား စာရင္းတစ္ခုကို ဖန္တီးရန္ အေလ့အက်င့္ေကာင္း တစ္ခုျဖစ္ၿပီး လက္ခံေသာ characters မ်ား စာရင္းတြင္ မပါသည့္ မည္သည့္ characters မ်ဳိးမဆို ဖယ္႐ွားရန္ regular expressions ကို သံုးပါ။ validation မလုပ္ဘဲ လက္မခံတဲ့ character မ်ားကို လက္ခံျခင္းသည္ ဆံုး႐ႈံးမႈ အလားအလာျဖစ္ပါတယ္။

ASP.NET web page မ်ားတြင္ input ကို ကန္႔သတ္ျခင္း
ASP.NET web page မ်ားအတြက္ input ေတြကို ကန္႔သတ္ရန္ server side code မွာ ေရးပါ။ client-side validation ကို မမွီခိုပါႏွင့္ အဘယ္ေၾကာင့္ဆိုေသာ္ ၄င္းကို အလြယ္တကူ ေက်ာ္ႏိုင္လို႔ပါ။ server to client ႏွင့္ client to server သြားသည့္ round trip ကို ေလ်ာ့ခ်ရန္ ႏွင့္ user experience ကို တိုးျမွင့္ရန္သာ client-side validation သံုးသည္။
Server controls ကို သံုးလွ်င္ input ကို ကန္႔သတ္ရန္ RegularExpressionValidator ႏွင့္ RangeValidator ကဲ့သို႔ ASP.NET validator controls မ်ားကို သံုးပါ။ ပံုမွန္ HTML input controls ကို သံုးလွ်င္ input ကို ကန္႔သတ္ရန္ server-side code တြင္ Regex class ကို သံုးပါ။
ၿပီးခဲ့တဲ့ code နမူနာတြင္ ASP.NET TextBox control တစ္ခုက SSN အမည္႐ွိတဲ့ Textbox မွ Value ကို ဖမ္းယူခဲ့ပါတယ္။ ၄င္း Value ကို ေအာက္တြင္ေဖာ္ျပထားေသာ RegularExpressionValidator တစ္ခုကို သံုးျခင္းျဖင့္ ၄င္း Value ကို ကန္႔သတ္ႏုိင္ပါသည္။
    <%@ language="C#" %>
    <form id="form1" runat="server">
        <asp:TextBox ID="SSN" runat="server"/>
        <asp:RegularExpressionValidator ID="regexpSSN" runat="server"         
                                        ErrorMessage="Incorrect SSN Number" 
                                        ControlToValidate="SSN"         
                                        ValidationExpression="^\d{3}-\d{2}-\d{4}$" />
    </form>

SSN input သည္ HTML control တစ္ခု၊ query string parameter တစ္ခု (သို႔) cookie တစ္ခု အေနနဲ႔ျဖစ္မည္ဆိုလွ်င္ System.Text.RegularExpressions namespace မွ Regex class ကို သံုးျခင္းျဖင့္ ကန္႔သတ္ထားႏိုင္ပါသည္။ ေအာက္ပါ ဥပမာတြင္ Input သည္ cookie တစ္ခုမွ ရတယ္လို႔ ယူဆရပါတယ္။
    using System.Text.RegularExpressions;
    if (Regex.IsMatch(Request.Cookies["SSN"], "^\d{3}-\d{2}-\d{4}$"))
    {
        // access the database
    }
    else
    {
        // handle the bad input
    }

ASP.Net တြင္ Injection Attacks မ်ားမွ ဘယ္လုိကာကြယ္မလဲ ၾကည့္ၾကရေအာင္။

Data လက္ခံသည့္ Code ေရးတဲ့ေနရာတြင္ user input မ်ားကို ကန္႔သတ္ပါ
ASP.NET page-level validation အျပင္ data access code တြင္ validation လုပ္ဖို႔လုိအပ္ပါတယ္။ Data access code တြင္ validation လုပ္ရန္ အဓိကအေျခအေန (၂)ခု ႐ွိပါတယ္။

Untrusted Clients
Data သည္ မယံုၾကည္ရတဲ့ေနရာတစ္ခုမွ လာႏိုင္လွ်င္ (သို႔) သင့္မွာ data ေတြကို ဘယ္လို validate ႏွင့္ ကန္သတ္မႈမ်ားကို လုပ္ရန္ အာမမခံႏိုင္ဘူးဆိုလွ်င္ data လက္ခံတဲ့လမ္းေၾကာင္းတြင္ input ကို ကန္႔သတ္တဲ့ validation logic ကို ထည့္ပါ။

Library code
သင့္ data access code မွာ library တစ္ခုကဲ့သို႔ packaged ျဖစ္လွ်င္ သင့္ data access code ကို ကိုယ္ပိုင္ validation ကိုု ျပဳလုပ္သင့္ပါတယ္။ အဘယ္ေၾကာင့္ဆိုေသာ္ client applications နဲ႔ပတ္သက္ေသာ လံုၿခံဳမႈမ႐ွိေသာ ယူဆခ်က္မ်ား သင့္ ျပဳလုပ္ႏိုင္ပါတယ္။
Regular expressions ကို သံုးျခင္းျဖင့္ data access လမ္းေၾကာင္းတစ္ခု ဘယ္လုိ validate လုပ္ႏိုင္လဲဆိုတာကို ေအာက္ပါဥပမာတြင္ ျပထားပါတယ္။
    using System;
    using System.Text.RegularExpressions;

    public void CreateNewUserAccount(string name, string password)
    {
        // Check name contains only lower case or upper case letters, 
        // the apostrophe, a dot, or white space. Also check it is 
        // between 1 and 40 characters long
        if ( !Regex.IsMatch(userIDTxt.Text, @"^[a-zA-Z'./s]{1,40}$"))
        throw new FormatException("Invalid name format");

        // Check password contains at least one digit, one lower case 
        // letter, one uppercase letter, and is between 8 and 10 
        // characters long
        if ( !Regex.IsMatch(passwordTxt.Text, 
                      @"^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$" ))
        throw new FormatException("Invalid password format");

        // Perform data access logic (using type safe parameters)
        ...
    }

အဆင့္ (၂) Stored Procedure ႏွင့္အတူ Parameter မ်ားကို သံုးပါ
Stored procedures မ်ားကို သံုးျခင္းသည္ SQL injection ကို ေသခ်ာေပါက္ မကာကြယ္ပါ။ လုပ္ေဆာင္ဖုိ႔ အေရးအႀကီးဆံုးအရာကေတာ့ stored procedure မ်ားႏွင့္အတူ parameter မ်ားကို သံုးပါ။ parameter မ်ားကို အသံုးမျပဳလွ်င္၊ Overview က႑တြင္ ေဖာ္ျပထားသလုိ unfiltered input ကို သံုးမယ္ဆိုလွ်င္ SQL injection ျဖစ္ႏိုင္ပါတယ္။
ေအာက္ပါ code မွာ stored procedure တစ္ခု ေခၚတဲ့အခါ SqlParameterCollection ကို ဘယ္လုိသံုးလဲဆိုတာကို ျပထားတာပါ။
    using System.Data;
    using System.Data.SqlClient;

    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        DataSet userDataset = new DataSet();
        SqlDataAdapter myCommand = new SqlDataAdapter( 
            "LoginStoredProcedure", connection);
        myCommand.SelectCommand.CommandType = CommandType.StoredProcedure;
        myCommand.SelectCommand.Parameters.Add("@au_id", SqlDbType.VarChar, 11);
        myCommand.SelectCommand.Parameters["@au_id"].Value = SSN.Text;

        myCommand.Fill(userDataset);
    }

ဤ code တြင္ @au_id parameter သည္ တိက်ေသာတန္ဖိုးတစ္ခုကဲ့သို႔ ျပဳလုပ္ၿပီး executable code ကဲ့သို႔ မျပဳလုပ္ပါ။ သို႔ေသာ္လည္း parameter မ်ားကို type ႏွင့္ length အတြက္ စစ္ေဆးခဲ့ပါတယ္။ code ဥပမာ ရဲ႕ ဦးစားေပးမႈမွာ input တန္ဖိုးကို character (၁၁)လုပ္ထက္ မပိုရန္ျဖစ္သည္။ data မ်ားသည္ parameter မ်ားက သတ္မွတ္ထားတဲ့ type (သို႔) length မွာ လိုက္ေလ်ာမညီပါက SqlParameter class သည္ exception တစ္ခုအျဖစ္ throw လုပ္လိုက္ပါတယ္။

Application တြင္ Parameterized Stored Procedure အသံုးျပဳမႈကို ျပန္လည္ သံုးသပ္ျခင္း
အဘယ္ေၾကာင့္ Parameter မ်ားႏွင့္အတူ stored procedure မ်ားကိုသံုးျခင္းမွာ SQL injection ကို ေသခ်ာေပါက္ မကာကြယ္ႏုိင္တာပါ။ ဤ stored procedure type ၏ အသံုးျပဳမႈကို သင္ ျပန္လည္သံုးသပ္သင့္ပါတယ္။ ဥပမာ ေအာက္ပါ parameterized stored procedure မွာ လံုၿခံဳမႈ အားနည္းမႈ အမ်ားအျပား ႐ွိပါတယ္။
    CREATE PROCEDURE dbo.RunQuery
    @var ntext
    AS
        exec sp_executesql @var
    GO

ေအာက္ပါ အားနည္းခ်က္မ်ား႐ွိတဲ့ ေ႐ွ႕ေရာက္ေနတဲ့ code example တြင္ တစ္ခုႏွင့္တူေသာ stored procedure တစ္ခုကို သံုးထားပါတယ္။
• ဘယ္ statement မဆုိ passed ျဖစ္တဲ့အခါ stored procedure မ်ား execute လုပ္ပါတယ္။ @var variable သည္ DROP TABLE ORDERS;ကို ျဖစ္ေစသည္။ ဤ code သည္ ORDERS ဆိုတဲ့ table ကို ဖ်က္ခ်လိမ့္မည္။
• Stored procedure ကို Dbo privileges ႏွင့္အတူ run ပါ။
• Store procedure အမည္ RunQuery သည္ ေ႐ြးခ်ယ္မႈ နည္းပါးမႈတစ္ခုျဖစ္ပါတယ္။ attacker တစ္ေယာက္က database ကို သက္ေသျပႏိုင္လွ်င္ attacker က stored procedure အမည္ကို ျမင္ပါလိမ့္မယ္။ RunQuery အမည္ႏွင့္တူတာကို attacker မွာ query ကုိ run သြားရန္ အလားအလာ႐ွိတဲ့ stored procedure ကို မွန္းဆ ႏိုင္ပါတယ္။

အဆင့္ (၃) Dynamic SQL ႏွင့္အတူ Parameter မ်ားကို သံုးပါ။
သင္ဟာ Stored Procedure ကို အသံုးမျပဳလွ်င္ Dynamic SQL statement ေတြကို တည္ေဆာက္တဲ့အခါမွာ parameters မ်ားကို အသံုးျပဳေနေသးသင့္ပါတယ္။ ေအာက္ပါ code မွာ dynamic SQL ႏွင့္အတူ SqlParametersCollection ကို ဘယ္လိုသံုးမလဲဆိုတာပါ။
    using System.Data;
    using System.Data.SqlClient;

    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        DataSet userDataset = new DataSet();
        SqlDataAdapter myDataAdapter = new SqlDataAdapter(
         "SELECT au_lname, au_fname FROM Authors WHERE au_id = @au_id", 
         connection);                
        myCommand.SelectCommand.Parameters.Add("@au_id", SqlDbType.VarChar, 11);
        myCommand.SelectCommand.Parameters["@au_id"].Value = SSN.Text;
        myDataAdapter.Fill(userDataset);
    }

Parameter Batching ကို သံုးျခင္း
အဓိက လြဲေခ်ာ္တဲ့ စိတ္ကူးကေတာ့ single round trip တစ္ခုတြင္ server ဆီသို႔သြားတဲ့ a batch of statement ကို ပို႔ရန္ SQL statement အေျမာက္အမ်ားႏွင့္ ဆက္စပ္လွ်င္ parameter မ်ားကို အသံုးမျပဳႏိုင္ပါ။ သို႔ေသာ္လည္း parameter name မ်ားမွာ မထပ္ဘူးဆိုတာ ေသခ်ာလွ်င္ ဒီ နည္းပညာကို သံုးႏိုင္ပါတယ္။ SQL text concatenation တြင္ unique parameter ကို အေသအခ်ာ သံုးျခင္းျဖင့္ ေအာက္တြင္ ျပထားသလို အလြယ္တကူ လုပ္ႏိုင္ပါတယ္။
    using System.Data;
    using System.Data.SqlClient;
    . . .
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
      SqlDataAdapter dataAdapter = new SqlDataAdapter(
           "SELECT CustomerID INTO #Temp1 FROM Customers " +
           "WHERE CustomerID > @custIDParm; SELECT CompanyName FROM Customers " +
           "WHERE Country = @countryParm and CustomerID IN " +
           "(SELECT CustomerID FROM #Temp1);",
           connection);
      SqlParameter custIDParm = dataAdapter.SelectCommand.Parameters.Add(
                                              "@custIDParm", SqlDbType.NChar, 5);
      custIDParm.Value = customerID.Text;

      SqlParameter countryParm = dataAdapter.SelectCommand.Parameters.Add(
                                          "@countryParm", SqlDbType.NVarChar, 15);
      countryParm.Value = country.Text;

      connection.Open();
      DataSet dataSet = new DataSet();
      dataAdapter.Fill(dataSet);
    }
    . . .
SQL injection ကို ကာကြယ္ရန္စဥ္းစားတဲ့အခါမွာ အျခားစဥ္းစားစရာအခ်က္ေတြက
- Special input characters မ်ားကို ေျဖ႐ွင္းရန္ escape routines ကို သံုးျခင္း
- အနည္းဆံုး Privileged database account တစ္ခုကို သံုးျခင္း
- Error information ေတြကို ေဖာ္ျပျခင္းမွ ေ႐ွာင္ျခင္း

Special input characters မ်ားကို ေျဖ႐ွင္းရန္ escape routines ကို သံုးျခင္း
Dynamic SQL ႏွင့္အတူ Special input characters မ်ားမွာ threat တစ္ခုအျဖစ္ ဟန္ေဆာင္ပါတယ္။ parameterized SQL ကို သံုးတဲ့အခါမွာေတာ့ မဟုတ္ပါဘူး။ ေအာက္တြင္ေဖာ္ျပတဲ့ code အခ်ဳိ႕က SQL Server ကို အႏၱရာယ္မ႐ွိေအာင္ Escape routines တြင္ Special meaning ျဖစ္တဲ့ characters မ်ားကို escape character တစ္ခုထည့္ထားပါတယ္။
    private string SafeSqlLiteral(string inputSQL)
    {
      return inputSQL.Replace("'", "''");
    }

A Least-Privileged database account တစ္ခုကို သံုးျခင္း
Privileged account ကိုအသံုးျပဳၿပီး သင့္ application ကို database ျဖင့္ ခ်ိတ္သင့္ပါတယ္။ Windows authentication ကို သံုးရာတြင္လည္း Operation System ႐ႈေထာင့္မွ အနည္းဆံုး privileged account ႐ွိသင့္ၿပီး limited privileges ႐ွိရန္ႏွင့္ Windows resources ေတြကို ရ႐ွိဖို႔ ကန္႔သတ္ထားရပါမယ္။ ဒါ့အျပင္ windows authentication (သို႔) SQL authentication ကို အသံုးျပဳလား အသံုးမျပဳလားဆိုရာတြင္ တူညီေနတဲ့ SQL Server login ကို database တြင္ permissions ျဖင့္ ကန္႔သတ္သင့္ပါတယ္။
Microsoft Windows Server 2003 ေပၚတြင္ run ထားတဲ့ ASP.NET application တစ္ခုကို စဥ္းစားၾကည့္ရေအာင္။ default အေနနဲ႔ ASP.NET application သည္ Network Service account ေအာက္တြင္ run တဲ့ application pool တစ္ခုထဲတြင္ run ပါတယ္။ ဒီ account သည္ a least privileged account ျဖစ္ပါတယ္။
Network Service account ႏွင့္အတူ SQL Server ကို လက္ခံရန္
၁။ Web server ၏ Network Service account အတြက္ SQL Server Login တစ္ခုကို တည္ေဆာက္ပါ။ Network Service account မွာ DOMAIN\WEBSERVERNAME$ လုိ႔ database server မွာ ေဖာ္ျပေနတဲ့ network credentials မ်ား ႐ွိပါတယ္။ ဥပမာ သင့္ domain သည္ XYZ လုိ႔ေခၚၿပီး Web Server သည္ 123 လုိ႔ေခၚတယ္ဆိုလွ်င္ သင္က XYZ/123$ အတြက္ database login ကို တည္ေဆာက္ပါ။
၂။ database user တစ္ခုကို တည္ေဆာက္ျခင္းႏွင့္ database role တစ္ခုသို႔ user ကိုထည့္ျခင္းျဖင့္ လိုအပ္ေသာ database ကုိ လက္ခံဖို႔အတြက္ Login အသစ္ကို ခြင့္ျပဳပါ။
၃။ ဒီ database role က database ထဲမွာ ႐ွိတဲ့ လုိအပ္တဲ့ table ေတြ ကို လက္ခံရန္ႏွင့္ လိုအပ္တဲ့ stored procedure ေတြကို ေခၚယူဖို႔ကို ခြင့္ျပဳဖို႔ permission မ်ားကို တည္ေဆာက္ပါ။ application က အသံုးျပဳဖို႔ လိုအပ္တဲ့ stored procedures မ်ားကို လက္ခံရန္သာ ခြင့္ျပဳရန္ႏွင့္ application ရဲ႕ အနည္းဆံုးလိုအပ္ခ်က္မ်ားေပၚတြင္ အေျခခံတဲ့ table မ်ားကို လံုလံုေလာက္ေလာက္လက္ခံရန္သာ ခြင့္ျပဳပါ။
ဥပမာ ASP.NET application သည္ database ကို ၾကည့္ရန္အတြက္သာ လုပ္ေဆာင္ၿပီး data ေတြကို update မလုပ္ဘူးဆိုလွ်င္ table မ်ားကို read access ကို သာ ခြင့္ျပဳဖို႔လုိပါတယ္။ ထိုသို႔လုပ္ျခင္းဟာ attacker မွ SQL injection attack တစ္ခုကို ေအာင္ျမင္တယ္ဆိုရင္ attacker တစ္ေယာက္ မွ ျဖစ္ေစသည့္ ပ်က္စီးမႈအတိုင္းအတာကို ကန္႔သတ္ျခင္း ျဖစ္ပါတယ္။

Error information ေတြကို ေဖာ္ျပျခင္းမွ ေ႐ွာင္ျခင္း
Error မ်ားကို ဖမ္းဖို႔ exception handling ပံုစံကို သံုးၿပီး client ဘက္တြင္ ၄င္း error မ်ားကို ေဖာ္ျပျခင္း ကာကြယ္ပါ။ အေသးစိတ္ error information မ်ားကို Local တြင္ Log အေနနဲ႔ထားပါ။ ဒါေပမယ့္ client ဘက္မွာေတာ့ အေသးစိတ္ error မ်ားကို မျပပါႏွင့္။
User က database ကို ခ်ိတ္ဆက္စဥ္ error ေပၚေပါက္မယ္ဆိုလွ်င္ user မ်ားသို႔ error nature မ်ားကို ကန္႔သတ္ သတ္မွတ္ထားမႈ ထား႐ွိပါ။ data ေတြကို လက္ခံရန္ ဆက္စပ္ေနတဲ့ သတင္းအခ်က္အလက္မ်ားႏွင့္ database error မ်ားကို ေဖာ္ျပမယ္ဆိုလွ်င္ သင့္ database security ကို compromise လုပ္ရန္ သံုးႏိုင္တဲ့ အသံုး၀င္တဲ့ သတင္းအခ်က္ႏွင့္အတူ malicious user တစ္ေယာက္ကို ေထာက္ပံ့ႏိုင္ပါတယ္။ Attacker မ်ားက SQL query တစ္ခုကို deconstruct လုပ္ရန္ အကူအညီျဖစ္မည့္ error message အေသးစိတ္တြင္႐ွိတဲ့ သတင္းအခ်က္အလက္မ်ားကို အသံုးျပဳၿပီး သူတို႔သည္ malicious code ေတြႏွင့္အတူ ထိုးေဖာက္ဖို႔ ႀကိဳးစားေနၾကပါတယ္။ error message အေသးစိတ္ တစ္ခုဟာ connection string, SQL server name သို႔မဟုတ္ table ႏွင့္ database naming conventions မ်ားကဲ့သို႔ တန္ဖိုး႐ွိတဲ့ သတင္းအခ်က္အလက္ကို ထုတ္ေဖာ္ႏိုင္ပါတယ္။

Reference : http://msdn.microsoft.com

 

No comments:

Post a Comment