public class ApplicationUser : IdentityUser { public string Email { get; set; } public string ConfirmationToken { get; set; } public bool IsConfirmed { get; set; } }
private string CreateConfirmationToken() { return ShortGuid.NewGuid(); } private void SendEmailConfirmation(string to, string username, string confirmationToken) { dynamic email = new Email("RegEmail"); email.To = to; email.UserName = username; email.ConfirmationToken = confirmationToken; email.Send(); } // // POST: /Account/Register [HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task<ActionResult> Register(RegisterViewModel model) { if (ModelState.IsValid) { string confirmationToken = CreateConfirmationToken(); var user = new ApplicationUser() { UserName = model.UserName, Email = model.Email, ConfirmationToken = confirmationToken, IsConfirmed = false }; var result = await UserManager.CreateAsync(user, model.Password); if (result.Succeeded) { SendEmailConfirmation(model.Email, model.UserName, confirmationToken); return RedirectToAction("RegisterStepTwo", "Account"); } else { AddErrors(result); } } // If we got this far, something failed, redisplay form return View(model); }
private bool ConfirmAccount(string confirmationToken) { ApplicationDbContext context = new ApplicationDbContext(); ApplicationUser user = context.Users.SingleOrDefault(u => u.ConfirmationToken == confirmationToken); if (user != null) { user.IsConfirmed = true; DbSet<ApplicationUser> dbSet = context.Set<ApplicationUser>(); dbSet.Attach(user); context.Entry(user).State = EntityState.Modified; context.SaveChanges(); return true; } return false; } [AllowAnonymous] public ActionResult RegisterConfirmation(string Id) { if (ConfirmAccount(Id)) { return RedirectToAction("ConfirmationSuccess"); } return RedirectToAction("ConfirmationFailure"); }
[HttpPost] [AllowAnonymous] [ValidateAntiForgeryToken] public async Task<ActionResult> Login(LoginViewModel model, string returnUrl) { if (ModelState.IsValid) { var user = await UserManager.FindAsync(model.UserName, model.Password); if (user != null && user.IsConfirmed) { await SignInAsync(user, model.RememberMe); return RedirectToLocal(returnUrl); } else { ModelState.AddModelError("", "Invalid username or password."); } } // If we got this far, something failed, redisplay form return View(model); }
توضیحاتی درباره کار با Postal
To: @ViewBag.To From: YOURNAME@gmail.com Subject: Confirm your registration Hello @ViewBag.UserName, Please confirm your registration by following the link bellow. @Html.ActionLink(Url.Action("RegisterConfirmation", "Account", new { id = @ViewBag.ConfirmationToken }), "RegisterConfirmation", "Account", new { id = @ViewBag.ConfirmationToken }, null)
- ViewBag.To آدرس ایمیل گیرنده را نشان میدهد.
- ViewBag.UserName نام کاربر جاری را نمایش میدهد.
- ViewBag.ConfirmationToken شناسه تولید شده برای تایید کاربر است.
@{ Layout = null; /* Overrides the Layout set for regular page views. */ }
متغیرهای سراسری در Postman
برای تعریف متغیرهای سراسری که در تمام برگههای Postman قابل دسترسی باشند، میتوان از متد pm.globals.set در قسمت Tests هر درخواست که پس از پایان درخواست جاری اجرا میشود، استفاده کرد. دراینجا فرصت خواهیم داشت تا مقدار دریافتی از سرور را در یک متغیر ذخیره کنیم. سپس میتوان از این متغیر، در حین ارسال درخواستی دیگر، استفاده کرد که نمونهای از آنرا در قسمت دوم، با تبدیل شیء response به یک شیء جاوا اسکریپتی و استخراج خاصیت uuid آن، مشاهده کردید:
let jsonResponse = pm.response.json(); pm.globals.set("uuid", jsonResponse.uuid);
که سبب باز شدن صفحهی دیالوگ زیر میشود که در آن میتوان کلید/مقدارهای جدیدی را به صورت دستی و بدون کدنویسی، تعریف و مقدار دهی کرد:
عملکرد | متد |
تعریف و مقدار دهی یک متغیر سراسری | pm.globals.set("varName", "VALUE"); |
دریافت مقدار یک متغیر سراسری | pm.globals.get("varName"); |
پاک کردن یک متغیر سراسری مشخص | pm.globals.unset("varName"); |
حذف تمام متغیرهای سراسری | pm.globals.clear(); |
یکی از کاربردهای مهم متغیرهای سراسری، دریافت توکنهای دسترسی پس از لاگین، در یک درخواست و استفادهی از این توکنها در درخواستهای دیگر میباشد.
روش استفادهی از متغیرهای تعریف شده
پس از تعریف این متغیرها، برای دسترسی به آنها میتوان از روش {{variableName}} در قسمتهای مختلف postman استفاده کرد:
Request URL: http://{{domain}}/users/{{userId}} Headers (key:value): X-{{myHeaderName}}:foo Request body: {"id": "{{userId}}", "name": "John Doe"}
متغیرهای محیطی در Postman
متغیرهای محیطی نیز بسیار شبیه به متغیرهای سراسری هستند، اما میدان دید آنها کمتر است. برای مثال فرض کنید که قصد دارید اطلاعات پایهی تنظیمات سرور و پورت آنها را در بین درخواستهای مختلف تغییر دهید؛ بدون اینکه بخواهید اصل درخواستها تغییری کنند؛ یا اینکه قسمت تعریف متغیرهای سراسری بیش از حد شلوغ شدهاست و قصد دارید آنها را گروه بندی کرده و مورد استفاده قرار دهید.
در ابتدای کار، هیچ محیط خاصی تعریف نشدهاست:
برای تعریف یک محیط جدید میتوان بر روی دکمهای با آیکن چشم، در بالای سمت راست صفحه و کلیک بر روی گزینهی Add آن، یک محیط جدید را ایجاد کرد:
در صفحهی باز شده ابتدا باید نامی را برای این محیط جدید انتخاب کرد و سپس میتوان key/valueهایی را مخصوص این محیط، تعریف نمود:
پس از تعریف متغیرهای جدید محیطی و مقادیر آنها، نحوهی استفادهی از این متغیرها دقیقا همانند روشی است که از متغیرهای سراسری استفاده کردیم و توسط روش {{variableName}} قابل دسترسی هستند.
برای ویرایش اطلاعات منتسب به یک محیط، ابتدا باید آنرا از dropdown محیطهای بالای صفحه انتخاب کرد. اکنون با کلیک بر روی دکمهای با آیکن چشم، در بالای سمت راست صفحه، لینک ویرایش این محیط انتخاب شده ظاهر میشود:
API کار با متغیرهای محیطی از طریق کد نویسی
عملکرد | متد |
تعریف و مقدار دهی یک متغیر محیطی | pm.environment.set("varName", "VALUE"); |
دریافت مقدار یک متغیر محیطی | pm.environment.get("varName"); |
پاک کردن یک متغیر محیطی مشخص | pm.environment.unset("varName"); |
حذف تمام متغیرهای محیطی | pm.environment.clear(); |
تفاوت میدان دید متغیرهای محیطی و متغیرهای سراسری
باید دقت داشت که هر دوی متغیرهای سراسری و محیطی، در تمام برگههای تعریف شده قابل دسترسی میباشند و از این لحاظ تفاوتی بین آنها نیست. اما فرض کنید یک متغیر سراسری را با نام port1 تعریف کردهاید و از آن برای ساخت آدرسی مانند https://localhost:{{port1}} استفاده کردهاید. همچنین دقیقا همین متغیر port1 را در محیط جدیدی به نام Env1 نیز تعریف کردهاید. اگر محیطی انتخاب نشده باشد، port1 به همان متغیر سراسری تعریف شده اشاره میکند.
اما اگر محیط انتخابی را به Env1 تغییر دهیم، اینبار port1، از طریق اطلاعات Env1 تامین شده و مقدار متغیر سراسری تعریف شده را بازنویسی (یا مخفی) میکند. بنابراین در حین کارکردن با محیطی مشخص، متغیرهای محیطی، بر متغیرهای سراسری مقدم هستند.
یک نکته: با نزدیک کردن اشارهگر ماوس، به یک متغیر تعریف شدهی در postman، میتوان میدان دید آنرا به سادگی مشاهده کرد و در این حالت دیگر جای حدس و گمانی باقی نمیماند.
عدم انتشار مقادیر اولیهی حساس، در حین گرفتن خروجیها
اگر به تصاویر فوق دقت کنید، حین تنظیم مقادیر متغیرها، ستون اول، initial value نام دارد و ستون دوم، current value. هنگام گرفتن خروجی از یک مجموعهی Postman، تنها این مقدار اولیه در خروجی وجود خواهد داشت و با دیگران به اشتراک گذاشته میشود. مقدار جاری همانی است که در حین ارسال درخواستها مورد استفاده قرار میگیرد. بنابراین تنها کاربرد initial value، در تهیهی خروجیها است که در انتهای قسمت سوم آنرا بررسی کردیم.
مشکل اینجا است که اگر از متدهای به روز رسانی مقادیر متغیرها استفاده کنیم، هر دو مقدار را تغییر میدهند که ممکن است علاقمند نباشید آنها را به اشتراک بگذارید. برای رفع این مشکل میتوان به منوی File->Settings آن مراجعه و گزینهی Automatically persist variable values را خاموش کرد:
با اینکار تغییر current value توسط متدهای API، سبب تغییر initial value که در exports ظاهر میشوند، نخواهد شد.
طراحی یک ماژول IpBlocker در ASP.NET MVC
نحوه نمایش ستونی خاص
معرفی کتابخانهی DNTCaptcha.Core
«من از کنترلهای تلریک استفاده میکنم که یک سری اسکریپت را بصورت
http://localhost:1244/WebResource.axd?d=aklE6L8AEfPEgIS3T-oXc6mevPfbpi6VRp_ZTP2nBVrnt5ULOFYD3GNWRrDHwANC3VDQlL8dLAa5g35dzgHyuzAgAguIpYrf-_NXIJwNNu0YRSnH3-MgKMfnwKBKF_Lk2E5oeIcLL78uDlQ0se_GxQ2&t=635231470568640000
به فرم تزریق میکند و بعضی وقتها داخلش xp و یا یک سری دستورات اسکیوال تولید میشوند. در این حالت این مسیرها توسط ISA Server در شبکه داخلی حمله تشخیص داده شده و بلاک خواهند شد و عملا برنامه از کار میافتد. آیا راهی برای خلاصی از دست آنها هست؟»
پاسخ: بلی. از دات نت 3 و نیم به بعد، امکان جایگزینی کامل اسکریپتهای خودکار مدفون شده در اسمبلیها با فایلهای استاتیک پیش بینی شدهاست که در ادامه نحوهی استخراج و کار با آنها را بررسی خواهیم کرد.
الف) یافتن اسکریپتهای مدفون در اسمبلیها
در ابتدا اسمبلی حاوی کنترلهای وب فرم مدنظر خود را باید توسط برنامههای Reflector یا ILSpy و امثال آنها گشوده و نام دقیق منبع و همچنین محتوای آن فایل اسکریپت را استخراج کنید. برای مثال:
در این تصویر، اسمبلی استاندارد System.Web.Extensions مورد بررسی قرار گرفته است. برای نمونه اگر بخواهید اسکریپتهای متناظر با ScriptManager و UpdatePanel را با معادلهای استاتیک آنها جایگزین کنید، باید دو فایل MicrosoftAjaxWebForms.js و MicrosoftAjax.js را از این اسمبلی استخراج نمائید. (برنامههای یاد شده امکان ذخیره سازی منابع را نیز میدهند)
ب) وادار کردن ASP.NET به استفاده از نسخهی استاتیک منابع
<asp:ScriptManager ID="Scriptmanager1" runat="server"> <Scripts> <asp:ScriptReference Name="MicrosoftAjaxWebForms.js" Assembly="System.Web.Extensions" Path="~/staticJS1.js" /> <asp:ScriptReference Name="MicrosoftAjax.js" Assembly="System.Web.Extensions" Path="~/staticJS2.js" /> </Scripts> </asp:ScriptManager>
The assembly 'System.Web.Extensions' does not contain a Web resource that has the name 'xyz.js'. Make sure that the resource name is spelled correctly. Make sure that the application references the correct version of an ASP.NET AJAX Framework assembly.
<script src="staticJS1.js" type="text/javascript"></script> <script src="staticJS2.js" type="text/javascript"></script>
یک نکتهی تکمیلی
در مطلب «ASP.NET 4.5 ScriptManager Improvements in WebForms » مشاهده خواهید کرد که از ASP.NET 4.5 به بعد، طی دو بستهی نیوگت که هر از چندگاهی به روز میشوند، کلیه اسکریپتهای System.Web و System.Web.Extensions خارج از این اسمبلیها نیز قابل دریافت بوده و با استفاده از سیستم bunding & minification میتوان آنها را فشرده و یکی کرد.
npm uninstall -g @angular/cli npm cache verify # if npm version is < 5 then use `npm cache clean` npm install -g @angular/cli@latest
npm i -g npm
2-حذف کردن ویژگیهای منسوخ شده از RxJS 6 با اجرای دستور زیر:
npm install -g rxjs-tslint rxjs-5-to-6-migrate -p src/tsconfig.app.json
npm update -g
برای بهروز رسانی به نسخه 7 (core framework و CLI)، دستورات زیر را اجرا کنید:
ng update @angular/cli ng update @angular/core ng update rxjs
ng update @angular/material
ng update --all --force
npm install npm-check-updates -g ncu -u npm install
واژه XSS مخفف Cross-site scripting، نوعی از آسیب پذیریست که در برنامههای تحت وب نمود پیدا میکند. به طور کلی و خلاصه، این آسیب پذیری به فرد نفوذ کننده اجازه تزریق اسکریپتهایی را به صفحات وب، میدهد که در سمت کاربر اجرا میشوند ( Client Side scripts ) . در نهایت این اسکریپتها توسط سایر افرادی که از صفحات مورد هدف قرار گرفته بازدید میکنند اجرا خواهد شد.
هدف از این نوع حمله :
بدست آوردن اطلاعات کوکیها و سشنهای کاربران ( مرتبط با آدرسی که صفحه آلوده شده در آن قرار دارد ) است. سپس فرد نفوذ کننده متناسب با اطلاعات بدست آمده میتواند به اکانت شخصی کاربران مورد هدف قرار گرفته، نفوذ کرده و از اطلاعات شخصی آنها سوء استفاده کند .
به صورت کلی دو طبقه بندی برای انواع حملات Cross-site scripting وجود دارند.
حملات XSS ذخیره سازی شده ( Stored XSS Attacks ) :
در این نوع ، کدهای مخرب تزریق شده، در سرور سایت قربانی ذخیره میشوند. محل ذخیره سازی میتواند دیتابیس سایت یا هر جای دیگری که دادهها توسط سایت یا برنامه تحت وب بازیابی میشوند و نمایش داده میشوند باشد. اما اینکه چگونه کدهای مخرب در منابع یاد شده ذخیره میشوند؟
فرض کنید در سایت جاری آسیب پذیری مذکور وجود دارد. راههای ارسال دادهها به این سایت چیست؟ نویسندگان میتوانند مطلب ارسال کنند و کاربران میتوانند نظر دهند. حال اگر در یکی از این دو بخش بررسیهای لازم جهت مقابله با این آسیب پذیری وجود نداشته باشد و نوشتههای کاربران که میتواند شامل کدهای مخرب باشد مستقیما در دیتابیس ذخیره شده و بدون هیچ اعتبار سنجی نمایش داده شود چه اتفاقی رخ خواهد داد؟ مسلما با بازدید صفحه آلوده شده، کدهای مخرب بر روی مرورگر شما اجرا و کوکیهای سایت جاری که متعلق به شما هستند برای هکر ارسال میشود و ...
حملات XSS منعکس شده ( Reflected XSS Attacks ) :
در این نوع از حمله، هیچ نوع کد مخربی در منابع ذخیره سازی وبسایت یا اپلیکیشن تحت وب توسط فرد مهاجم ذخیره نمیشود ! بلکه از ضعف امنیتی بخشهایی همچون بخش جستجو وب سایت، بخشهای نمایش پیغام خطا و ... استفاده میشود ... اما به چه صورت؟
در بسیاری از سایتها، انجمنها و سیستمهای سازمانی تحت وب، مشاهده میشود که مثلا در بخش جستجو، یک فیلد برای وارد کردن عبارت جستجو وجود دارد. پس از وارد کردن عبارت جستجو و submit فرم، علاوه بر نمایش نتایج جستجو، عبارت جستجو شده نیز به نمایش گذاشته میشود و بعضا در بسیاری از سیستمها این عبارت قبل از نمایش اعتبار سنجی نمیشود که آیا شامل کدهای مخرب میباشد یا خیر. همین امر سبب میشود تا اگر عبارت جستجو شامل کدهای مخرب باشد، آنها به همراه نتیجهی جستجو اجرا شوند.
اما این موضوع چگونه مورد سوء استفاده قرار خواهد گرفت؟ مگر نه اینکه این عبارت ذخیره نمیشود پس با توضیحات فوق، کد فقط بر روی سیستم مهاجم که کد جستجو را ایجاد میکند اجرا میشود، درست است؟ بله درست است ولی به نقطه ضعف زیر توجه کنید ؟
www.test.com/search?q=PHNjcmlwdD5hbGVydChkb2N1bWVudC5jb29raWUpOzwvc2NyaXB0Pg==
این آدرس حاصل submit شدن فرم جستجو وبسایت test (نام وبسایت واقعی نیست و برای مثال است ) و ارجاع به صفحه نتایج جستجو میباشد. در واقع این لینک برای جستجوی یک کلمه یا عبارت توسط این وبسایت تولید شده و از هر کجا به این لینک مراجعه کنید عبارت مورد نظر مورد جستجو واقع خواهد شد. در واقع عبارت جستجو به صورت Base64 به عنوان یک query String به وبسایت ارسال میشود؛ علاوه بر نمایش نتایج، عبارت جستجو شده نیز به کاربر نشان داده شده و اگر آسیب پذیری مورد بحث وجود داشته باشد و عبارت شامل کدهای مخرب باشد، کدهای مخرب بر روی مرورگر فردی که این لینک را باز کرده اجرا خواهد شد!
در این صورت کافیست فرد مهاجم لینک مخرب را به هر شکلی به فرد مورد هدف بدهد ( مثلا ایمیل و ... ). حال در صورتیکه فرد لینک را باز کند (با توجه به اینکه لینک مربوط به یک سایت معروف است و عدم آگاهی کاربر از آسیب پذیری موجود در لینک، باعث باز کردن لینک توسط کاربر میشود)، کدها بر روی مرورگرش اجرا شده و کوکیهای سایت مذکور برای مهاجم ارسال خواهد شد ... به این نوع حمله XSS ، نوع انعکاسی میگویند که کاملا از توضیحات فوق الذکر، دلیل این نامگذاری مشخص میباشد.
اهمیت مقابله با این حمله :
برای نمونه این نوع باگ حتی تا سال گذشته در سرویس ایمیل یاهو وجود داشت. به شکلی که یکی از افراد انجمن hackforums به صورت Private این باگ را به عنوان Yahoo 0-Day XSS Exploit در محیط زیر زمینی و بازار سیاه هکرها به مبلغ چند صد هزار دلار به فروش میرساند. کاربران مورد هدف کافی بود تا فقط یک ایمیل دریافتی از هکر را باز کنند تا کوکیهای سایت یاهو برای هکر ارسال شده و دسترسی ایمیلهای فرد قربانی برای هکر فراهم شود ... ( در حال حاظر این باگ در یاهو وجو ندارد ).
چگونگی جلوگیری از این آسیب پذیری
در این سری از مقالات کدهای پیرامون سرفصلها و مثالها با ASP.net تحت فریم ورک MVC و به زبان C# خواهند بود. هر چند کلیات مقابله با آسیب پذیری هایی از این دست در تمامی زبانها و تکنولوژیهای تحت وب یکسان میباشند.
خوشبختانه کتابخانهای قدرتمند برای مقابله با حمله مورد بحث وجود دارد با نام AntiXSS که میتوانید آخرین نسخه آن را با فرمان زیر از طریق nugget به پروژه خود اضافه کنید. البته ذکر این نکته حائز اهمیت است که Asp.net و فریم ورک MVC به صورت توکار تا حدودی از بروز این حملات جلوگیری میکند. برای مثال به این صورت که در View ها شما تا زمانی که از MvcHtmlString استفاده نکنید تمامی محتوای مورد نظر برای نمایش به صورت Encode شده رندر میشوند. این داستان برای Url ها هم که به صورت پیش فرض encode میشوند صدق میکند. ولی گاها وقتی شما برای ورود اطلاعات مثلا از یک ادیتور WYSWYG استفاده میکنید و نیاز دارید دادهها را بدون encoding رندر کنید. آنگاه به ناچار مجاب بر اعمال یک سری سیاستهای خاصتر بر روی داده مورد نظر برای رندر میشوید و نمیتوانید از encoding توکار فوق الذکر استفاده کنید. آنگاه این کتابخانه در اعمال سیاستهای جلوگیری از بروز این آسیب پذیری میتواند برای شما مفید واقع شود.
PM> Install-Package AntiXSS
… var reviewContent = model.UserReview; reviewContent = Microsoft.Security.Application.Encoder.HtmlEncode(review); …
امیدوارم در اولین بخش از این سری مقالات، به صورت خلاصه مطالب مهمی که باعث ایجاد فهم کلی در رابطه با حملات Xss وجود دارد، برای دوستان روشن شده و پیش زمینه فکری برای مقابله با این دست از حملات برایتان به وجود آمده باشد.