مطالب
نحوه‌ی بستن یک بازه‌ی IP در IIS
یک سری از ربات‌ها مدام سایت‌ها را برای یافتن یک سری از اسکریپت‌های خاص اسکن می‌کنند. IPهای آن‌ها نیز عموما متعلق است به چین و هسایگان آن. مشکلی که با این ربات‌ها وجود دارد این است که از یک IP خاص نشات نمی‌گیرند و به نظر صدها سرور آلوده را جهت مقاصد خود مورد استفاده قرار می‌دهند. به همین جهت نیاز است بتوان یک بازه‌ی IP را در IIS بست.

بستن یک بازه‌ی IP در IIS 6

در IIS6 باید به خواص وب سایت و برگه‌ی Directory security آن مراجعه کرد. سپس در این قسمت، در حین افزودن IP مد نظر، باید گزینه‌ی Group of computers را انتخاب نمود.


در اینجا برای مثال برای بستن IPهایی که با 194 شروع می‌شوند، باید 194.0.0.0 را وارد کرد و در این حالت subnet mask را نیز باید 255.0.0.0 انتخاب کرد. با این subnet mask خاص، اعلام می‌کنیم که فقط اولین قسمت IP وارد شده برای ما اهمیت دارد و سه قسمت بعدی خیر. به این ترتیب تمام IPهای شروع شده با 194 با هر سه جزء دیگر دلخواهی، بسته خواهند شد.


بستن یک بازه‌ی IP در IISهای 7 به بعد

در IISهای 7 به بعد نیاز است مراحل زیر را طی کرده و نقش «IP and Domain Restrictions » را نصب کنید.
 Administrative Tools -> Server Manager -> expand Roles
-> Web Server (IIS) ->  Role Services -> Add Role Services -> select IP and Domain Restrictions
پس از آن با استفاده از تنظیمات ذیل در فایل web.config می‌توان یک IP و یا بازه‌ای از IPها را بست:
   <system.webServer>
      <security>
         <ipSecurity>
            <add ipAddress="192.168.100.1" />
            <add ipAddress="169.254.0.0" subnetMask="255.255.0.0" />
         </ipSecurity>
      </security>
   </system.webServer>
البته علاوه بر نصب نقش یاد شده، باید Feature Delegation نیز جهت استفاده از آن فعال گردد:
 IIS 7 -> root server -> Feature Delegation -> IP and Domain Restrictions
->  Change the delegation to Read/Write
مطالب
React 16x - قسمت 26 - احراز هویت و اعتبارسنجی کاربران - بخش 1 - ثبت نام و ورود به سیستم
می‌خواهیم به برنامه‌ی لیست فیلم‌هایی که تا این قسمت تکمیل کردیم، امکانات جدیدی را مانند ورود به سیستم، خروج از آن، کار با JWT، فراخوانی منابع محافظت شده‌ی سمت سرور، نمایش و یا مخفی کردن المان‌های صفحه بر اساس سطوح دسترسی کاربر و همچنین محافظت از مسیرهای مختلف تعریف شده‌ی در برنامه، اضافه کنیم.
برای قسمت backend، از همان برنامه‌ی تکمیل شده‌ی قسمت قبل استفاده می‌کنیم که به آن تولید مقدماتی JWTها نیز اضافه شده‌است. البته این سری، مستقل از قسمت سمت سرور آن تهیه خواهد شد و صرفا در حد دریافت توکن از سرور و یا ارسال مشخصات کاربر جهت لاگین، نیاز بیشتری به قسمت سمت سرور آن ندارد و تاکید آن بر روی مباحث سمت کلاینت React است. بنابراین اینکه چگونه این توکن را تولید می‌کنید، در اینجا اهمیتی ندارد و کلیات آن با تمام روش‌های پیاده سازی سمت سرور سازگار است (و مختص به فناوری خاصی نیست). پیشنیاز درک کدهای سمت سرور قسمت JWT آن، مطالب زیر هستند:
  1. «معرفی JSON Web Token»
  2. «اعتبارسنجی مبتنی بر JWT در ASP.NET Core 2.0 بدون استفاده از سیستم Identity» 
  3. «پیاده سازی JSON Web Token با ASP.NET Web API 2.x»
  4. « آزمایش Web APIs توسط Postman - قسمت ششم - اعتبارسنجی مبتنی بر JWT»  


ثبت یک کاربر جدید

فرم ثبت نام کاربران را در قسمت 21 این سری، در فایل src\components\registerForm.jsx، ایجاد و تکمیل کردیم. البته این فرم هنوز به backend server متصل نیست. برای کار با آن هم نیاز است شیءای را با ساختار زیر که ذکر سه خاصیت اول آن اجباری است، به endpoint ای با آدرس https://localhost:5001/api/Users به صورت یک HTTP Post ارسال کنیم:
{
  "name": "string",
  "email": "string",
  "password": "string",
  "isAdmin": true,
  "id": 0
}
در سمت سرور هم در Services\UsersDataSource.cs که در انتهای بحث می‌توانید پروژه‌ی کامل آن‌را دریافت کنید، منحصربفرد بودن ایمیل وارد شده بررسی می‌شود و اگر یک رکورد دو بار ثبت شود، یک BadRequest را به همراه پیام خطایی، بازگشت می‌دهد.

اکنون نوبت به اتصال کامپوننت registerForm.jsx، به سرویس backend است. تا اینجا دو سرویس src\services\genreService.js و src\services\movieService.js را در قسمت قبل، به برنامه جهت کار کردن با endpoint‌های backend server، اضافه کردیم. شبیه به همین روش را برای کار با سرویس سمت سرور api/Users نیز در پیش می‌گیریم. بنابراین فایل جدید src\services\userService.js را با محتوای زیر، به برنامه‌ی frontend اضافه می‌کنیم:
import http from "./httpService";
import { apiUrl } from "../config.json";

const apiEndpoint = apiUrl + "/users";

export function register(user) {
  return http.post(apiEndpoint, {
    email: user.username,
    password: user.password,
    name: user.name
  });
}
توسط متد register این سرویس می‌توانیم شیء user را با سه خاصیت مشخص شده، از طریق HTTP Post، به آدرس api/Users ارسال کنیم. خروجی این متد نیز یک Promise است. در این سرویس، تمام متدهایی که قرار است با این endpoint سمت سرور کار کنند، مانند ثبت، حذف، دریافت اطلاعات و غیره، تعریف خواهند شد.
اطلاعات شیء user ای که در اینجا دریافت می‌شود، از خاصیت data کامپوننت RegisterForm تامین می‌گردد:
class RegisterForm extends Form {
  state = {
    data: { username: "", password: "", name: "" },
    errors: {}
  };
البته اگر دقت کرده باشید، در شیء منتسب به خاصیت data، خاصیتی به نام username تعریف شده‌است، اما در سمت سرور، نیاز است خاصیتی با نام Name را دریافت کنیم. یک چنین نگاشتی در داخل متد register سرویس کاربر، قابل مشاهده‌‌است. در غیراینصورت می‌شد در متد http.post، کل شیء user را به عنوان پارامتر دوم، درنظر گرفت و ارسال کرد.

پس از تعریف userService.js، به registerForm.jsx بازگشته و ابتدا امکانات آن‌را import می‌کنیم:
import * as userService from "../services/userService";
می‌شد این سطر را به صورت زیر نیز نوشت، تا تنها یک متد از ماژول userService را دریافت کنیم:
import { register } userService from "../services/userService";
اما روش as userService * به معنای import تمام متدهای این ماژول است. به این ترتیب نام ذکر شده‌ی پس از as، به عنوان شیءای که می‌توان توسط آن به این متدها دسترسی یافت، قابل استفاده می‌شود؛ مانند فراخوانی متد userService.register. اکنون می‌توان متد doSubmit این فرم را به سرور متصل کرد:
  doSubmit = async () => {
    try {
      await userService.register(this.state.data);
    } catch (ex) {
      if (ex.response && ex.response.status === 400) {
        const errors = { ...this.state.errors }; // clone an object
        errors.username = ex.response.data;
        this.setState({ errors });
      }
    }
  };


مدیریت و نمایش خطاهای دریافتی از سمت سرور

در این حالت برای ارسال اطلاعات یک کاربر، در بار اول، یک چنین خروجی را از سمت سرور می‌توان شاهد بود که id جدیدی را به این رکورد نسبت داده‌است:


اگر مجددا همین رکورد را به سمت سرور ارسال کنیم، اینبار خطای زیر را دریافت خواهیم کرد:


که از نوع 400 یا همان BadRequest است:


بنابراین نیاز است بدنه‌ی response را در یک چنین مواردی که خطایی از سمت سرور صادر می‌شود، دریافت کرده و با به روز رسانی خاصیت errors در state فرم (همان قسمت بدنه‌ی catch کدهای فوق)، سبب درج و نمایش خودکار این خطا شویم:


پیشتر در قسمت بررسی «کار با فرم‌ها» آموختیم که برای مدیریت خطاهای پیش بینی شده‌ی دریافتی از سمت سرور، نیاز است قطعه کدهای مرتبط با سرویس http را در بدنه‌ی try/catch‌ها محصور کنیم. برای مثال در اینجا اگر ایمیل شخصی تکراری وارد شود، سرویس یک return BadRequest("Can't create the requested record.") را بازگشت می‌دهد که در اینجا status code معادل BadRequest، همان 400 است. بنابراین انتظار داریم که خطای 400 را از سمت سرور، تحت شرایط خاصی دریافت کنیم. به همین دلیل است که در اینجا تنها مدیریت status code=400 را در بدنه‌ی catch نوشته شده ملاحظه می‌کنید.
سپس برای نمایش آن، نیاز است خاصیت متناظری را که این خطا به آن مرتبط می‌شود، با پیام دریافت شده‌ی از سمت سرور، مقدار دهی کنیم که در اینجا می‌دانیم مرتبط با username است. به همین جهت سطر errors.username = ex.response.data، کار انتساب بدنه‌ی response را به خاصیت جدید errors.username انجام می‌دهد. در این حالت اگر به کمک متد setState، کار به روز رسانی خاصیت errors موجود در state را انجام دهیم، رندر مجدد فرم، در صف انجام قرار گرفته و در رندر بعدی آن، پیام موجود در errors.username، نمایش داده می‌شود.


پیاده سازی ورود به سیستم

فرم ورود به سیستم را در قسمت 18 این سری، در فایل src\components\loginForm.jsx، ایجاد و تکمیل کردیم که این فرم نیز هنوز به backend server متصل نیست. برای کار با آن نیاز است شیءای را با ساختار زیر که ذکر هر دو خاصیت آن اجباری است، به endpoint ای با آدرس https://localhost:5001/api/Auth/Login به صورت یک HTTP Post ارسال کنیم:
{
  "email": "string",
  "password": "string"
}
با ارسال این اطلاعات به سمت سرور، درخواست Login انجام می‌شود. سرور نیز در صورت تعیین اعتبار موفقیت آمیز کاربر، به صورت زیر، یک JSON Web token را بازگشت می‌دهد:
var jwt = _tokenFactoryService.CreateAccessToken(user);
return Ok(new { access_token = jwt });
یعنی بدنه‌ی response رسیده‌ی از سمت سرور، دارای یک شیء JSON خواهد بود که خاصیت access_token آن، حاوی JSON Web token متعلق به کاربر جاری لاگین شده‌است. در آینده اگر این کاربر نیاز به دسترسی به یک api endpoint محافظت شده‌ای را در سمت سرور داشته باشد، باید این token را نیز به همراه درخواست خود ارسال کند تا پس از تعیین اعتبار آن توسط سرور، مجوز دسترسی به منبع درخواستی برای او صادر شود.

در ادامه برای تعامل با منبع api/Auth/Login سمت سرور، ابتدا یک سرویس مختص آن‌را در فایل جدید src\services\authService.js، با محتوای زیر ایجاد می‌کنیم:
import { apiUrl } from "../config.json";
import http from "./httpService";

const apiEndpoint = apiUrl + "/auth";

export function login(email, password) {
  return http.post(apiEndpoint + "/login", { email, password });
}
متد login، کار ارسال ایمیل و کلمه‌ی عبور کاربر را به اکشن متد Login کنترلر Auth، انجام می‌دهد و خروجی آن یک Promise است. برای استفاده‌ی از آن به کامپوننت src\components\loginForm.jsx بازگشته و متد doSubmit آن‌را به صورت زیر تکمیل می‌کنیم:
import * as auth from "../services/authService";

class LoginForm extends Form {
  state = {
    data: { username: "", password: "" },
    errors: {}
  };

  // ...

  doSubmit = async () => {
    try {
      const { data } = this.state;
      const {
        data: { access_token }
      } = await auth.login(data.username, data.password);
      console.log("JWT", access_token);
      localStorage.setItem("token", access_token);
      this.props.history.push("/");
    } catch (ex) {
      if (ex.response && ex.response.status === 400) {
        const errors = { ...this.state.errors };
        errors.username = ex.response.data;
        this.setState({ errors });
      }
    }
  };
توضیحات:
- ابتدا تمام خروجی‌های ماژول authService را با نام شیء auth دریافت کرده‌ایم.
- سپس در متد doSubmit، اطلاعات خاصیت data موجود در state را که معادل فیلدهای فرم لاگین هستند، به متد auth.login برای انجام لاگین سمت سرور، ارسال کرده‌ایم. این متد چون یک Promise را باز می‌گرداند، باید await شود و پس از آن متد جاری نیز باید به صورت async معرفی گردد.
- همانطور که عنوان شد، خروجی نهایی متد auth.login، یک شیء JSON دارای خاصیت access_token است که در اینجا از خاصیت data خروجی نهایی دریافت شده‌است.
- سپس نیاز است برای استفاده‌های آتی، این token دریافتی از سرور را در جایی ذخیره کرد. یکی از مکان‌های متداول اینکار، local storage مرورگرها است (اطلاعات بیشتر).
- در آخر کاربر را توسط شیء history سیستم مسیریابی برنامه، به صفحه‌ی اصلی آن هدایت می‌کنیم.
- در اینجا قسمت catch نیز ذکر شده‌است تا خطاهای حاصل از return BadRequestهای دریافتی از سمت سرور را بتوان ذیل فیلد نام کاربری نمایش داد. روش کار آن، دقیقا همانند روشی است که برای فرم ثبت یک کاربر جدید استفاده کردیم.

اکنون اگر برنامه را ذخیره کرده و اجرا کنیم، توکن دریافتی، در کنسول توسعه دهندگان مرورگر لاگ شده و سپس کاربر به صفحه‌ی اصلی برنامه هدایت می‌شود. همچنین این token ذخیره شده را می‌توان در ذیل قسمت application->storage آن نیز مشاهده کرد:



لاگین خودکار کاربر، پس از ثبت نام در سایت

پس از ثبت نام یک کاربر در سایت، بدنه‌ی response بازگشت داده شده‌ی از سمت سرور، همان شیء user است که اکنون Id او مشخص شده‌است. بنابراین اینبار جهت ارائه‌ی token از سمت سرور، بجای response body، از یک هدر سفارشی در فایل Controllers\UsersController.cs استفاده می‌کنیم (کدهای کامل آن در انتهای بحث پیوست شده‌است):
var jwt = _tokenFactoryService.CreateAccessToken(user);
this.Response.Headers.Add("x-auth-token", jwt);



در ادامه در کدهای سمت کلاینت src\components\registerForm.jsx، برای استخراج این هدر سفارشی، اگر شیء response دریافتی از سرور را لاگ کنیم:
const response = await userService.register(this.state.data);
console.log(response);
یک چنین خروجی را به همراه دارد که در آن، هدر سفارشی ما درج نشده‌است و فقط هدر content-type در آن مشخص است:


برای اینکه در کدهای سمت کلاینت بتوان این هدر سفارشی را خواند، نیاز است هدر مخصوص access-control-expose-headers را نیز به response اضافه کرد:
var jwt = _tokenFactoryService.CreateAccessToken(data);
this.Response.Headers.Add("x-auth-token", jwt);
this.Response.Headers.Add("access-control-expose-headers", "x-auth-token");
به این ترتیب وب سرور برنامه، هدر سفارشی را که قرار است برنامه‌ی کلاینت به آن دسترسی پیدا کند، مجاز اعلام می‌کند. اینبار اگر خروجی دریافتی از Axios را لاگ کنیم، در لیست هدرهای آن، هدر سفارشی x-auth-token نیز ظاهر می‌شود:


اکنون می‌توان این هدر سفارشی را در متد doSubmit کامپوننت RegisterForm، از طریق شیء response.headers خواند و در localStorage ذخیره کرد. سپس کاربر را توسط شیء history سیستم مسیریابی، به ریشه‌ی سایت هدایت نمود:
class RegisterForm extends Form {
  // ...

  doSubmit = async () => {
    try {
      const response = await userService.register(this.state.data);
      console.log(response);
      localStorage.setItem("token", response.headers["x-auth-token"]);
      this.props.history.push("/");
    } catch (ex) {
      if (ex.response && ex.response.status === 400) {
        const errors = { ...this.state.errors }; // clone an object
        errors.username = ex.response.data;
        this.setState({ errors });
      }
    }
  };

کدهای کامل این قسمت را از اینجا می‌توانید دریافت کنید: sample-26-backend.zip و sample-26-frontend.zip
مطالب
نگه‌داری ساده‌تر نرم‌افزار با معماری Vertical Slices - قسمت اول
معمولا معماری‌های ارائه شد،ه بر اساس جداسازی لایه‌های نرم‌افزار می‌باشد. برای مثال در معماری Hexagonal که آن‌را به Port & Adaptor هم میشناسیم، نرم‌افزار، با استفاده از لایه‌های Domain، Application، Infra و ... تفکیک می‌شوند. منطق تجاری در Domain پیاده سازی می‌شود و رابط‌های مربوط به کار با دیتا تعریف می‌شوند. در لایه‌ی Application، Portها و Adaptorهای مورد نیاز برای استفاده، پیاده‌سازی می‌شوند. در لایه‌ی Infra، رابط‍‌های تعریف شده در Domain پیاده‌سازی شده و در لایه‌ی Application، Adaptorهای پیاده‌سازی شده مورد استفاده قرار میگیرند.
تمام این اتفاقات در سطح لایه‌های برنامه اتفاق می‌افتند و بر همین اساس ما نیاز داریم برای جلوگیری از تغییرات بزرگ، از Abstraction استفاده کنیم و بسیار زیاد استفاده میکنیم. Abstraction یکی از راه‌های غیرمستقیم (InDirection) کردن دسترسی فراخوان به منبع یا تارگت مورد نظر می‌باشد که مزایای زیادی را مانند استفاده‌ی مجدد، جداسازی بخش‌هایی که باعث پیچیدگی می‌شوند و همچنین مخفی کردن وابستگی‌ها برای ما دارد.

 

Abstraction



می‌دانیم که غیرمستقیم کردن دسترسی به منابع در طراحی نرم‌افزار یک اصل است. اما Abstraction تنها راه جداسازی نیست. راه دیگر طراحی زیرساخت می‌باشد. مانند استفاده از Message Queue (مانند استفاده از MediatR) و یا Load Balancer. 



البته منظور این نیست که استفاده‌ی غیر مستقیم از لایه‌های نمایش داده شده را حذف کنیم. مشخصا MediatR در اینجا جداسازی خوبی را برای ما ایجاد کرده که مزایای آن بر کسی پوشیده نیست. مسئله‌ی مهمی که معمولا به آن توجهی نمی‌شود، هزینه‌ی Abstraction می‌باشد. اگر بخواهیم درباره‌ی هزینه‌های Abstraction صحبت کنیم، اشاره به موارد زیر قابل تامل است:

ابتدا، فهم سخت بعد از استفاده از Abstraction می‌باشد. در واقع ما با ایجاد این Abstractionها، مسیر رسیدن به هدف را در بین یکسری لایه‌ها قرار داده‌ایم که فهم دقیق آن‌ها، ارتباط مستقیمی با منطق پیاده‌سازی ما دارد. البته مزیت اینکار عدم درگیری با لایه‌های مشخص شده می‌باشد.

دوم کارآیی پایین. البته فقط صحبت در مورد مصرف زیاد حافظه و یا CPU نیست. یکی از این موارد، به دلیل Generic تعریف شدن Repositoryها می‌باشد که باعث می‌شود داده‌های بیشتر از نیازی را به لایه‌های دیگر ارسال کنیم. برای بررسی دقیق‌تر می‌توانید این مقاله‌ را مطالعه بفرمایید.

اما Vertical Slices چگونه به ما در این زمینه کمک میکند. در این معماری، ما به جای تمرکز بر روی لایه‌ها، تمرکز خود را روی فیچرها میگذاریم. در واقع نرم‌افزار را به قسمت‌های بسیار کوچکتری تقسیم میکنیم و از Abstraction اضافی جلوگیری میکنیم. در این صورت اگر تغییری لازم به اعمال شدن دارد، در سطح فیچر اعمال می‌شود و نه در سطح لایه‌ها. در ضمن دیگر Repository و یا Specification ی برای تست وجود ندارد؛ پس میزان تست‌های نوشته شده کاهش پیدا می‌کنند و طبیعتا برای تست Integration میتوانیم کل فیچر را تست کنیم.

در اینجا ما بجای تمرکز بر روی ساختار کل کدبیس، تمرکز خود را بر روی ساختار کدبیس یک فیچر خاص نگه میداریم. 

در Vertical Slices Arch ما مشکلی با اشتراک‌گذاری Domain بین فیچر‌ها نداریم. زیرا Domain ما به هیچ فریموورکی وابسته نیست و بصورت مستقیم مورد استفاده قرار میگیرد. لطفا به تصویر زیر توجه بفرمایید:

 

Vertical Slices Arch


زمانیکه این فیچرهای کوچک توسعه داده می‌شوند، دلیلی برای تعریف Repository و یا Specificationهای بی مورد نداریم. پس میتوانیم به راحتی آن‌ها را حذف کنیم و به صورت مستقیم از EF و یا هر ORM دیگری استفاده کنیم و یا میتوانیم به راحتی از Raw Query‌ها و مزیت آن‌ها بهره‌مند شویم. نگه‌داری یک فیچر کوچک که Command، Handler و Viewها و سایر نیازمندی‌هایش(به استثنای Domain) داخل خودش قرار گرفته و شامل یک ساختار ویژه‌ی خودش با توجه به نیازمندی‌های تعریف شده می‌باشد، بسیار کار ساده‌تری است تا نگه‌داری یک سری لایه که به صورت گسترده از Abstraction در آن‌ها استفاده شده‌است. 

مطالب
Anti CSRF module for ASP.NET

CSRF یا Cross Site Request Forgery به صورت خلاصه به این معنا است که شخص مهاجم اعمالی را توسط شما و با سطح دسترسی شما بر روی سایت انجام دهد و اطلاعات مورد نظر خود را استخراج کرده (محتویات کوکی یا سشن و امثال آن) و به هر سایتی که تمایل دارد ارسال کند. این‌کار عموما با تزریق کد در صفحه صورت می‌گیرد. مثلا ارسال تصویری پویا به شکل زیر در یک صفحه فوروم، بلاگ یا ایمیل:

<img src="http://www.example.com/logout.aspx">

شخصی که این صفحه را مشاهده می‌کند، متوجه وجود هیچگونه مشکلی نخواهد شد و مرورگر حداکثر جای خالی تصویر را به او نمایش می‌دهد. اما کدی با سطح دسترسی شخص بازدید کننده بر روی سایت اجرا خواهد شد.

روش‌های مقابله:
  • هر زمانیکه کار شما با یک سایت حساس به پایان رسید، log off کنید. به این صورت بجای منتظر شدن جهت به پایان رسیدن خودکار طول سشن، سشن را زودتر خاتمه داده‌اید یا برنامه نویس‌ها نیز باید طول مدت مجاز سشن در برنامه‌های حساس را کاهش دهند. شاید بپرسید این مورد چه اهمیتی دارد؟ مرورگری که امکان اجازه‌ی بازکردن چندین سایت با هم را به شما در tab های مختلف می‌دهد، ممکن است سشن یک سایت را در برگه‌ای دیگر به سایت مهاجم ارسال کند. بنابراین زمانیکه به یک سایت حساس لاگین کرده‌اید، سایت‌های دیگر را مرور نکنید. البته مرورگرهای جدید مقاوم به این مسایل شده‌اند ولی جانب احتیاط را باید رعایت کرد.
برای نمونه افزونه‌ای مخصوص فایرفاکس جهت مقابله با این منظور در آدرس زیر قابل دریافت است:

  • در برنامه خود قسمت Referrer header را بررسی کنید. آیا متد POST رسیده، از سایت شما صادر شده است یا اینکه صفحه‌ای دیگر در سایتی دیگر جعل شده و به برنامه شما ارسال شده است؟ هر چند این روش آنچنان قوی نیست و فایروال‌های جدید یا حتی بعضی از مرورگرها با افزونه‌هایی ویژه، امکان عدم ارسال این قسمت از header درخواست را میسر می‌سازند.
  • برنامه نویس‌ها نباید مقادیر حساس را از طریق GET requests ارسال کنند. استفاده از روش POST نیز به تنهایی کارآمد نیست و آن‌را باید با random tokens ترکیب کرد تا امکان جعل درخواست منتفی شود. برای مثال استفاده از ViewStateUserKey در ASP.Net . جهت خودکار سازی اعمال این موارد در ASP.Net، اخیرا HTTP ماژول زیر ارائه شده است:

تنها کافی است که فایل dll آن در دایرکتوری bin پروژه شما قرار گیرد و در وب کانفیگ برنامه ارجاعی به این ماژول را لحاظ نمائید.

کاری که این نوع ماژول‌ها انجام می‌دهند افزودن نشانه‌هایی اتفاقی ( random tokens ) به صفحه‌ است که مرورگر آن‌ها را بخاطر نمی‌سپارد و این token به ازای هر سشن و صفحه منحصر بفرد خواهد بود.

برای PHP‌ نیز چنین تلاش‌هایی صورت گرفته است:
http://csrf.htmlpurifier.org/


مراجعی برای مطالعه بیشتر
Prevent Cross-Site Request Forgery (CSRF) using ASP.NET MVC’s AntiForgeryToken() helper
Cross-site request forgery
Top 10 2007-Cross Site Request Forgery
CSRF - An underestimated attack method

نظرات اشتراک‌ها
تفاوت اعتبارسنجی ورودی ها با اعتبارسنجی مرتبط با قواعد تجاری
یک مطلب مرتبط
A next-level validation is domain validation, or as I've often seen referred, "business rule validation". This is more of a system state validation, "can I affect the change to my system based on the current state of my system". I might be checking the state of a single entity, a group of entities, an entire collection of entities, or the entire system. The key here is I'm not checking the request against itself, but against the system state.  

اشتراک‌ها
معرفی فریم ورک Asp.Net Unique Architecture
 یک فریم ورک ساده و سبک برای تولید پروژه‌های با هر مقیاس (کوچک و بزرگ) می‌باشد. فریم ورک Asp.Net Unique Architecture به دلیل شفافیت در ساختار، قابل استفاده در تمام معماری‌های (Micro service، CQRS,، ... (می باشد. همچنین فریم ورک AUA پر از الگو‌های طراحی مختلف بوده که یک منبع بسیار خوب برای معماران نرم افزار و توسعه دهنده‌ها می‌باشد. استفاده از فریم ورک AUA موجب صرفه جویی در زمان و هزینه می‌شود و همچنین امکان توسعه‌ی نرم افزار به شکلی ساده و سریع، را فراهم می‌کند. با کمک فریم ورک AUA آیوآ می‌توان به راحتی کدنویسی بهتر، سریع تر، منظم‌تر و با تمرکز بالاتری داشته باشیم. این فریم ورک بر اساس مفاهیم، ساختار‌ها و معماری‌های جدید و به روز نوشته شده است 

از جمله مفاهیم استفاده شده در فریم ورک AUA


طراحی دامنه محور (DDD) Domain Driven Design

Clean Architecture

Clean Code
Domain-driven design (DDD)
SOLID Principle
Code Refactoring
GRASP pattern 
GRASP pattern امکان توسعه‌ی نرم افزار به شکلی ساده و سریع
مبتنی بر اصول SOLID
طراحی پیمانه ای یا ماژولار
معماری لایه بندی شده

  آدرس سایت فریم ورک AUA

https://auaframework.com

معرفی فریم ورک  Asp.Net Unique Architecture
اشتراک‌ها
اوبونتو ۲۱.۰۴ با پشتیبانی از اکتیودایرکتوری ارائه می‌شود!

امکان  استفاده از گروپ‌پالیسی‌ها  و...

Ubuntu 21.04 desktops can now join an AD domain at installation for central configuration. In turn, AD administrators can now manage Ubuntu workstations, which simplifies compliance with company policies. 


The new Ubuntu also adds the ability to configure system settings from an AD domain controller. Using Ubuntu's AD Group Policy Client or other Group Policy Clients, system administrators can specify security policies on all connected clients, such as password policies and user access control, and desktop environment settings, such as login screen, background, and favorite programs. 

اوبونتو ۲۱.۰۴ با پشتیبانی از اکتیودایرکتوری ارائه می‌شود!
اشتراک‌ها
مخزن آموزشی Net. Core با مثالهای پیاده سازی شده

در این مخزن روش‌های بهینه و توصیه شده جهت ساخت برنامه‌های تحت وب با استفاده از Net Core. در قالب 12 پروژه پیاده سازی شده است که منبع خوبی جهت الگو برداری است.

Boilerplate for ASP.NET Core reference application with Entity Framework Core, demonstrating a layered application architecture with DDD best practices. Implements NLayer Hexagonal architecture (Core, Application, Infrastructure and Presentation Layers) and Domain Driven Design (Entities, Repositories, Domain/Application Services, DTO's...) and aimed to be a Clean Architecture, with applying SOLID principles in order to use for a project template. Also implements best practices like loosely-coupled, dependency-inverted architecture and using design patterns such as Dependency Injection, logging, validation, exception handling, localization and so on. 

مخزن آموزشی Net. Core با مثالهای پیاده سازی شده
اشتراک‌ها
فریمورک تهیه شده با Asp.net Mvc و Asp.net Web Api به صورت NTier با پشتیبانی از چند زبانگی

These are some key features of the framework itself:

Modular and NLayered architecture
Multi-tenancy
Dependency Injection
Domain Driven Design
Unit of work implementation
Flexible Localization system
Automatic data filters
Audit logging
Setting management
Menu management
Authorization
Exception handling
Validation
Logging
Event bus for domain events
Auto-creating Web API layer for Application Services
Auto-creating Javascript proxy layer to use Web API layer
Javascript helper methods for ajax, notifications, message boxes, making UI busy...
Easily working with embedded resources
Useful extension and helper methods   

فریمورک تهیه شده با Asp.net Mvc و Asp.net Web Api به صورت NTier با پشتیبانی از چند زبانگی
مطالب
تغییر استراتژی ساخت مدل در EF5 و رفع مشکل WCF Ria
Entity framework 5 نسبت به نسخه‌های پیشین شاهد تغییرات بسیاری بوده است و مانند هر تغییر دیگری اینجا نیز ممکن است تغییرات ؛ باعث بروز مشکلاتی در روند توسعه نرم افزار شوند. EF در نسخه جدید خود در کدهای پشت صحنه Model به جای ObjectContext از DbContext که نسخه محدود شده ObjectContext می‌باشد استفاده می‌کند. همین امر به خودی خود باعث محدود شدن متدهای شئی Context شده است. متدها و خواصی که گاها برای انجام اعمال خاصی به آنها نیاز پیدا می‌کنیم ولی دیگر در دسترس نیستند. برای مثال برای یک برنامه خاص می‌خواستم مقدار CommandTimeout   را به صورت دستی برای شئی Context تنظیم کنم ؛ ولی کد زیر دیگر قابل استفاده نبود:
  context.CommandTimeout = 180;
همچنین این استفاده از DbContext در هنگام استفاده از WCF Ria در سیلورلایت باعث بروز مشکل شده و کلاس‌های مدل در هنگام تعریف Domain Service Class توسط WCF Ria قابل شناسایی نیستند.یعنی WCF RIA به صورت خودکار قادر به تشخیص کلاس‌های Model نمی‌باشد.
 

برای رفع این مشکل مراحل زیر را انجام دهید:

  1. دو فایل tt موجود در مدل را حذف نمایید.

 2. مدل را در حالت Designer باز کنید و در بخش خصوصیات مدل مقدار Code Generation Strategy را از None  به Default تغییر دهید.

3. پروژه را Rebuild نمایید. مشکل به همین سادگی رفع می‌شود.
حالا با خیال راحت می‌توانید کلاس‌های مدل را در پنجره Add New Domain Service Class مشاهده نمایید.