ويژگيهاي جديد SQL Server 2012

مدتي از انتشار نسخه 2012 ه SQL Server با كد نام Denali ميگذره در اين پست قصد دارم چنديدن ويژگي جديد اين نسخه رو معرفي كنم.ضمنا دريافت اين نسخه و تبديل اون به نسخه نهايي رو از اين پست ميتونيد پيگيري كنيد.

AlwaysOn : يكي از مهمترين ويژگيها در SQL Server 2012 در بحث High Availability يا در دسترس بودن هست و در واقع تكميل كننده Database Mirroring در نسخه هاي قبلي ميباشد.در Mirroring ما به صورت تك تك ديتابيس هامون رو ميرور ميكنيم ولي در AlwaysOn اينكار به صورت گروهي انجام ميشه يعني چندين ديتابيس و همچنيا ميتونيم دو روش همزمان (Synchronous) و غير همزمان (Asynchronous) رو با هم تركيب كنيم.بر خلاف ميرورينگ ديتابيس ما به صورت فقط خواندني قابل كوئري گرفتنه و حتي بكاپ گرفتن.
نكته:در نسخه هاي قبلي با گرفتن Snapshot از ديتابيس Mirror ميتوان به صورت فقط خواندني از ديتابيس استفاده كرد و

پشتيباني از Windows Server Core : يادمه دوره كارداني استاد شبكه اي داشتيم كه لينوكس رو بهمون به صورت Command ي درس ميداد كلي از دستش شاكي بوديم كه چرا GUI نه ...
نسخه 2012 ي SQL Server قابل نصب روي Windows Server Core هست يعني شما نسخه اي از SQL Server رو نصب ميكنيد كه هيچ GUI ي نداره و ارتباط شما از طريق Command Prompt و Powershell انجام ميشه.در واقع اين كار براي نرم افزارهاي كه به صورت back-end خدمات ميدن استفاده ميشه و در نتيحه سرعت و امنيت و عدم نياز به Patch كردن رو براي ما فراهم ميكنه.

Power View : يك ابزار گزارش گيري تعاملي تحت وب كه با Silverlight نوشته شده (با كد نام Crescent) هست كه به كاربران كه معمولا آناليزورهاي ديتا هستن امكان گزارش گيري هاي ad hoc رو ميده.
نكته : براي كار با Power View نياز به SharePoint Server 2010 هست.

SQL Server Data Tools : يك محيط يكپارچه توسعه داخل Visual Studio هست كه به شما امكان طراحي ديتابيس رو ميده.از قابليت هاي جالب اين محيط ميشه به قابليت IntelliSense و ديباگ كردن اشاره كرد.SQL Server Data Tools ميتونه به SQL Server 2005 به بعد وصل بشه.

Columnstore Indexes : يكي از ويزگي هاي منحصر به فرد SQL Server هست كه ديتا ها رو بجاي ذخيره به صورت سطري و در يك Page كه روش سنتي هست; مياد ستون هاي رو كه در يك ايندكس هستند رو به صورت ستوني و در چند Page ذخيره ميكنه.سوالي كه پيش مياد اينه كه خب اين كار چه سودي داره؟

  • سرعت بالا هنگام كوئري زدن با توجه به اينكه فقط ستون هاي كه در كوئري اومدن لود ميشن
  • فشردگي بيشتر با توجه به احتمال تكراري بودن ديتا امكان فشردگي بر اساس الگوريتم هاي موجود بيشتر ميشود.

نكته : با اين نوع ايندكس جدول فقط خواندني ميشود بنابراين مناسب براي OLTP نيست و در واقع براي Data Warehouse ها طراحي شده.

Contained Databases : با اين روش ما ميتونيم يك ديتابيس جامع و يه جورايي Stand Alone داشته باشيم.يعني ما ميتونيم يك ديتابيس روي سرور A بسازيم بعد همين ديتابيس رو ببريم روي سرور B استفاده كنيم بودن هيچ كار اضافه اي.سوالي كه پيش مياد اينه كه پس User هاي اون ديتابيس چي ميشن؟
زيبايي كار همينه و در واقع از اسم اين نوع ديتابيس هم مشخصه «Contained» يعني User ما داخل ديتابيس هست و در سرور B فقط و فقط به اين ديتابيس دسترسي داره.

پيشرفت در T-SQL : پشتيباني از دنباله اعداد , عملگر TRY_CONVERT كانورت و تبديل كردن ديتاها ,  استفاده از Syntax ه OFFSET و FETCH براي صفحه صفحه كردن ديتا يا Data Paging , تابع جديد FORMAT براي راحت كردن قالب بندي ديتاي خروجي , عملگر THROW براي انجام بهينه تره رسيدگي به خطا (Exception Handaling) و

User-Defined Server Roles : در سطح سرور ما تعداد محدودي Role داريم فرض كنيد بعنوان DBA ميخوايم به تيم Develop شركت دسترسي read/write به تمام ديتابيس ها بديم متاسفانه چنين Role ي در سطح سرور نداريم و بايد به ازاي تك تك ديتابيس ها اين دسترسي رو بديم.SQL Server 2012 اين مشكل رو براي ما حل كرده.

Data Quality Services : ابزاري هست براي برسي كيفيت و تصحيح كردن ديتاهاي غلط بر اساس اطلاعات و دانشي كه ما بهش ميديم در واقع اين سروريس knowledge-based هست.براي مثال فرض كنيد فيلدي بنام جنسيت داريم كه داخلش هم M هست هم Male و حتي عدد يك.متخصص داده در سازمان تعيين ميكنه مقدار اين فيلد بايد Male باشه كه در واقع ميشه knowledge اين سرويس و بر اساس اون اين سرويس ديتا رو تصحيح ميكنه.

Distributed Replay : يه اصطلاحي در دنياي كامپيوتر هست بنام زير بار گذاشتن يا بار كشيدن مثلا براي تست CPU ميايم يه پردازش سنگين رو اجرا ميكنيم تا ببينم CPU زير اين بار جواب ميده.حالا فرض كنيد همين كارو بخواهيم براي SQL Server انجام بديم.براي مثال ميخواهيم باركاري (Workload) سيستم جاري (درحال استفاده) رو روي سرور جديد خريداري شده تست كنيم.براي اين كار باركاري رو از سرور جاري دريافت (Capture) و در سرور جديد و مثلا از طريق چند Client (قابل كانفيگ) مجددا اجر (Replay) ميكنيم.

جلوگیری از حملات دستکاری آدرس در ASP.NET MVC‌

یکی از ویژگی های ASP.NET MVC نحوه آدرس دهی صفحات و منابع یا همون URL هست که تر و تمیزه و از سوی کاربر قابل فهمه یا به عبارتی SEO Friendly URLs ه.مثلا اگه شما Controller ی بنام Profile داشته باشید که یکی از Action Method های اون Index باشه موقع کار با این Controller آدرس های ارسالی به صورت زیر میشن.

www.dotnetdev.info/Profile/2

همه چی آرومه! تا اینکه یه کاربر کنجکاو اون 2 ی آخر URl رو میکنه 3 و…
اینجاس که وب سایت شما در مقابل «حمله دستکاری آدرس» یا URL Manipulation Attack یا Parameter Manipulation ضعف داره.
و اماچه باید کرد؟
برای جلوگیری از این حمله روش های مختلفی موجود که بعضیاش شکننده و آماتور و بعضیاش حرفه ای ن و البته راه حل نهایی.
همونطور که گفتم روش های متفاوتی موجوده که بر میگرده به سناریوی ما که مهمترینش وجود رابطه بین درخواست ارسالی از سمت کاربر و هویت اون کاربره مثلا تو مثال بالا حتما رابطه یک به یک بین پروفایل و کاربر موجوده و یا مثلا یک سیستم اتوماسیون اداری رو در نظر بگیرید بین درخواست های ایجاد شده در سیستم و کاربر رابطه موجوده.خب حالا این رابطه ها کجا بکار میاد ؟
زمانی که شما به درخواستی جواب میدید براحتی میتونید چک کنید این کاربر مجاز به دیدن جواب این درخواست هست.مثلا تو مثال بالا ID ی کاربر درخواست کننده صفحه نمایش پروفایل با ID ی پروفایل درخواست شده یکیه؟
من سه روشی رو که خودم مطالعه داشتم براتون لیست میکنم اگه شما هم روشی دارید خوشحال میشم آشنا شم.

0-پیش نیاز تمام روش ها
در ASP.NET MVC میتونیم با استفاده از Attribute ی بنام Authorize در سطح Controller دسترسی کاربر لاگین نکرده به این آدرس رو بگیریم.البته این اول راهه چون کاربر لاگین کرده میتونه به آدرس بالا دسترسی داشته باشه و اونو تغییر بده.

[Authorize]
public ActionResult Index(int profileId)

1-ابتدایی ترین کار و البته ضعیف و شکننده ترین کار برسی Referrer هست تا مطمئن بشیم منبع; درخواست وارد شده از وب سایت ماس مثلا کلیک کردن روی یک لینک در صفحه ولی اگه ما همین لینک رو مستقیما در آدرس بار تایپ کنیم چون Referrer مقداری نداره متوجه میشیم که کاربر داره «حمله دستکاری آدرس» انجام میده و…

if (Request.UrlReferrer.Host != "dotnetdev.info")
       {
         RedirectToAction("Error");
       }

چه خوب با کمترین مقدار  کد نویسی مشکل حل شد.(نوچ)
همون کاربر کنجکاوه میدونه که متغییر Referrer در مرورگر به راحتی قابل تغییره و به راحتی با نصب افزونه  RefControl این روش رو دور میزنه.
نکته:این روش محدود به ASP.NET MVC نیست و مثلا در ASP.NET هم قابل استفاده است.

2-همنطور که گفتم بسته به سناریوی ما اگه رابطه ای بین درخواست ارسال شده وکاربر باشه با یه چکینگ ساده تمام مشکلات حله و…

[Authorize]
public ActionResult Index(int profileId)
{
    //روش غلط
    var profile= _dbContext.Profiles.SingleOrDefault(s=>s.Id==profileId); 

    //روش درست
    var profile= _dbContext.Profiles.SingleOrDefault(s=>s.Id==profileId 
           && s.Username==User.Identity.Name
           ); 
}

همنطور که توکد میبینید شرط خوندن پروفایل از دیتابیس نام کاربر رو هم چک میکنه و با اینکار مطمئن میشم کاربر لاگین کرده; فقط و فقط پروفایل خودش رو میتونه ببینه.اگه سناریوی شما و طراحیتون رابطه ی بین درخواست وارد شده و کاربر داشته باشه تقریبا میشه گفتد راه حل نهایی اینه.

3-در مواقعی که نمیتونیم از هویت کاربر استفاده کنیم و به نوعی سناریو و طراحی بشکلی هست که رابطه ی بین درخواست وارد شده و کاربر نیست از این روش استفاده میکنیم.
همنطور که میدونید در ASP.NET MVC قابلیتی بنام AntiForgeryToken برای متدهای از نوع POST وجود داره(برای آشنایی بیشتر این پست جناب مددی رو مطالعه کنید) ولی برای GET به صورت توکار ما چنین قابلیتی نداریم.جناب Albin Abel (همیشه به هندیا بخاطر زبان انگلیسیشون حسودیم میشه)این تکنیک رو برای متدهای GET طراحی کردن.به این شکل که ما همیشه یه پارامتر اضافه بنام Token (به صورت هش شده) داریم که براساس URL ما تهیه میشه و به ته URL اضافه میشه و سمت سرور این Token مجددا تولید و با Token ارسالی مقایسه میشه و…
مثالی رو هم که ایشون مطرح کردن در رابطه با بانک سوالات هست.البته با توجه به رابطه ی بین سوالات و موضوع و کاربر فکرمیکنم از روش دوم هم میشه استفاده کرد.

public static string generateUrlToken(string controllerName, string actionName, ArrayList argumentParams, string password)
{
     string token = "";
     string salt = "#testsalt";
     
     //آماده کردن آدرس 
     string stringToToken = controllerName + "/" + actionName + "/";
     foreach (string param in argumentParams)
        {
         stringToToken += "/" + param;
        }
     
    //آماده کردن توکن و نمک پاش کردن اون 
    byte[] saltValueBytes = System.Text.Encoding.ASCII.GetBytes(salt);
    Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(password, saltValueBytes);
    byte[] secretKey = key.GetBytes(16);  
    HMACSHA1 tokenHash = new HMACSHA1(secretKey);
    tokenHash.ComputeHash(System.Text.Encoding.ASCII.GetBytes(stringToToken));

    token = Convert.ToBase64String(tokenHash.Hash);
    return token;
}

کار این متد ساختن Token هست که برای امنیت بیشتر نمک پاشش کرده و…

هنگام ساختن لینک در View از متد generateUrlToken استفاده میکنیم.

<%
     ArrayList args = new ArrayList();
     args.Add(Convert.ToString(item.ExamId));
     string token = SecureUrl.Models.SecureUrlToken.generateUrlToken("Questions", "QuestionsView", args, "QuestionList");
%>
 <%: Html.ActionLink("Questions- Secured Link", "QuestionsView", "Questions", new {id = item.ExamId,urltoken=token }, null)%>

و سر آخر قبل از نمایش سوال مربوطه Token ارسالی رو با Token ساخته شده برسی میکنیم و…

public ActionResult QuestionsView(string id, string urltoken)
 {
    //ساخت مجدد توکن
    ArrayList args = new ArrayList();
    args.Add(Convert.ToString(id));
    
    string token = SecureUrlToken.generateUrlToken("Questions", "QuestionsView", args, "QuestionList");
 
   if (token == urltoken)
   {
    //مجاز
   }
 }

نکته 1: که باید توجه کنید با این روش لینک های ما از حالت SEO Friendly URLs در میان.
نکته 2: نسخه جدید این متد (generateUrlToken) از یکه مقدار تصادفی در هر Session برای داینامیک کردن Token های ایجادی استفاده کرده و قابلیتهای دیگه.