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

 در مطلب گذشته کدنویسی امن به موضوع اعتبارسنجی ورودی‌ها پرداختیم. در این مقاله قصد داریم تا کدگذاری خروجی‌ها (Output encoding) را به‌عنوان یکی دیگر از راه‌های افزایش امنیت کدهای خود بررسی کنیم. اما چه تفاوتی بین این دو روش وجود دارد؟

تفاوت کدگذاری خروجی با اعتبارسنجی ورودی

 اعتبارسنجی ورودی (Input Validation) فرایندی است برای بررسی اینکه آیا داده‌ای ارائه شده توسط کاربران یا منابع دیگر با قالب، نوع و محدوده مورد انتظار ما مطابقت دارند یا خیر. کدگذاری خروجی فرایند تبدیل داده‌های ارسالی به مرورگر یا سایر مقاصد به یک قالب امن و نامتناقض است. به طور خلاصه اعتبارسنجی ورودی می‌گوید من فقط داده‌هایی را می‌پذیرم که آشکارا داده‌ها هستند درحالی‌که کدگذاری خروجی می‌گوید من فقط داده‌ها و کدهایی را منتقل می‌کنم که بتوان از یکدیگر جدا کرد. هدف هر دو روش جلوگیری از به خطر انداختن عملکرد، امنیت یا قابلیت استفاده برنامه شماست به‌طوری‌که داده‌های مخرب راهی به ساختار سیستم شما نداشته باشند.

کدگذاری خروجی‌ها (Output encoding)

 واضح است که موضوع اصلی توانایی تفکیک بین “کد” و “داده” است. این کار در بین توسعه‌دهندگان اغلب به‌وسیله یک “قرارداد کد” (code contract) انجام می‌شود که مشخص می‌کند کدام بخش از متن ارسالی کد و کدام بخش داده است. راه‌های مختلفی برای انجام این کار وجود دارد و به همان اندازه که به سازوکار ارتباطی (پروتکل) با همکارتان بستگی دارد، به کتابخانه/زبان برنامه‌نویسی/پلتفرم کد شما نیز وابسته است.

مثال اول

 یک مثال ساده ارسال یک ایمیل از طریق پروتکل انتقال ایمیل ساده (SMTP) است. با فرض اینکه شما فرستنده ایمیل هستید، پس از اتصال و آماده‌شدن برای ارسال ایمیل، دستورات “RCPT TO <a@example.com> ” و “MAIL FROM <b@example.com> ” را ارسال می‌کنید تا تشخیص دهید که چه کسی فرستنده و چه کسی گیرنده ایمیل است و به دنبال آن دستور “DATA”. پس از دستور DATA، همان‌طور که انتظار دارید داده‌های پیام خط‌به‌خط می‌آید. (اطلاعات سرآیند ایمیل هم در این قسمت ارسال و بررسی می‌شود که برای ساده نگه‌داشتن مثال از آن چشم‌پوشی می‌کنیم).

 ولی داده‌ها کجا تمام می‌شوند؟ با یک خط که فقط حاوی یک نقطه است. حالا تصور کنید یک مهاجم می‌تواند یک ایمیل با یک نقطه در خط خودش ارسال کند و به دنبال آن برخی از دستورات SMTP مخرب بفرستد، و شما، فرستنده نامه، اساساً از سرور ایمیل می‌خواهید این دستورات را اجرا کند. یا ممکن است شخصی به طور تصادفی یک نقطه را به‌تنهایی وارد کند و دستورات تصادفی را برای اجرا راه‌اندازی کند.

 راه‌حلی که طراحان SMTP برای رفع این مشکل در نظر گرفته‌اند این است که هنگام ارسال یک خط از یک ایمیل که با یک نقطه شروع می‌شود، قبل از آن یک نقطه دیگر اضافه می‌شود؛ بنابراین، یک نقطه به‌خودی‌خود تبدیل به دونقطه، دونقطه تبدیل به سه، و… می‌شود و سرور می‌داند که این یک خط داده است و نه دستوری که باید اجرا شود. این روش که به آن نقطه پر کردن (dot-stuffing) می‌گویند یکی از روش‌های کدگذاری Base64 است که در پروتکل SMTP مورداستفاده قرار می‌گیرد و توسط سرآیند (Header) روی ایمیل ارسالی اجرا می‌شود.

 شاید این ساده‌ترین مثال از کدگذاری خروجی باشد.

در مثال زیر استفاده از dot-stuffing در زبان برنامه نویسی PHP آورده شده:

$message = "This is a message.\n.It starts with a dot.";
$dot_stuffed_message = str_replace("\n.", "\n..", $message);
echo $dot_stuffed_message;

خروجی:

This is a message.
..It starts with a dot.

مثال دوم

 نمونه‌ای دیگر از کدگذاری خروجی شامل فراخوانی HtmlEncode (یا یک تابع مشابه برای فریم‌ورک شما)، روی داده‌هایی است که می‌دانید نباید به‌عنوان HTML اجرا شوند. اگر کد HTML داخل داده‌ها وجود نداشته باشد، تابع HtmlEncode به داده‌ها دست نمی‌زند و تغییری در آن ایجاد نمی‌کند، اما در غیر این صورت با فراخوانی یک تابع ساده شما از حملات XSS (Cross-Site Scripting) و HTML injection جلوگیری می‌کنید.

در مثال زیر استفاده از HtmlEncode در زبان برنامه نویسی PHP آورده شده.

$string = "This is some text that needs to be encoded & < >.";
$encoded_string = htmlspecialchars($string);
echo $encoded_string;

خروجی:

This is some text that needs to be encoded &amp; &lt; &gt;.

جمع بندی

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

 به طور خلاصه برخی از تکنیک‌های اشاره شده توسط OWASP عبارت‌اند از:

  • اعتبارسنجی داده‌ها در یک سیستم قابل‌اعتماد.
  •  از یک‌روال استاندارد و آزمایش شده برای هر نوع رمزگذاری خروجی استفاده کنید.
  •  کدگذاری همه کاراکترها مگر اینکه برای مفسر هدف امن تلقی شوند.
  • اطمینان حاصل کنید که هر محتوای تولید شده توسط کاربر که در پرس‌وجوهایSQL، XML و LDAP استفاده می‌شود، کدگذاری شده باشد. این شامل ورودی کاربر، مقادیر پایگاه داده یا هر داده دیگری است که توسط کاربران قابل تغییر است.
  • پاک‌سازی خروجی داده‌های نامعتبر به دستورات سیستم عامل.

کدنویسی امن