JSON در بسیاری از APIها قالب اصلی تبادل داده است، اما خود JSON هیچ سازوکار امنیتی داخلی برای محرمانگی، اصالت، مجوزدهی یا جلوگیری از دستکاری ندارد. یک payload میتواند از نظر Syntax کاملاً معتبر باشد و در عین حال شامل داده مخرب، فیلدهای اضافی، مقدارهای بیشازحد بزرگ یا اطلاعات حساس باشد. امنیت JSON در APIها یعنی کنترل تمام مسیر داده؛ از دریافت بایتها و Parse کردن تا اعتبارسنجی Schema، مجوزدهی فیلدها، ثبت رویداد، خروجیسازی و محدودکردن منابع.
Quick Answer: برای امنکردن JSON در API، فقط به معتبر بودن Syntax اکتفا نکنید. اندازه درخواست را محدود کنید، Content-Type و Encoding را کنترل کنید، داده را با Schema و قواعد کسبوکار اعتبارسنجی کنید، فیلدهای مجاز را صریحاً انتخاب کنید، از Mass Assignment جلوگیری کنید، مجوز هر عملیات را مستقل بررسی کنید و اطلاعات حساس را در پاسخ یا Log قرار ندهید.
امنیت JSON در API دقیقاً به چه معناست؟
JSON فقط یک قالب متنی برای نمایش Object، Array و مقدارهای پایه است. Parser مشخص میکند متن قابل تبدیل به داده هست یا نه؛ Validator ساختار و محدودیتها را بررسی میکند؛ لایه Authorization تعیین میکند کاربر اجازه مشاهده یا تغییر یک منبع را دارد یا نه. ترکیبکردن این وظایف یکی از ریشههای آسیبپذیری است. برای مثال JSON Validator نمیتواند تشخیص دهد کاربر جاری مجاز است فیلد role را تغییر دهد.
| لایه | پرسش اصلی | نمونه کنترل |
|---|---|---|
| Transport | داده در مسیر محافظت شده است؟ | TLS، محدودیت اندازه، Timeout |
| Parsing | متن JSON معتبر و قابل پردازش است؟ | Parser استاندارد، رد Duplicate Key طبق سیاست |
| Schema | ساختار و نوع داده مطابق قرارداد است؟ | required، type، maxLength، additionalProperties |
| Business Validation | مقدار از نظر منطق برنامه معتبر است؟ | محدوده قیمت، وضعیت سفارش، مالکیت منبع |
| Authorization | این کاربر مجاز به عملیات است؟ | کنترل سطح شیء و سطح فیلد |
| Output | پاسخ بیش از نیاز اطلاعات نمیدهد؟ | DTO خروجی، حذف رازها و داده داخلی |
مهمترین تهدیدهای JSON در APIها
۱. Mass Assignment و Over-posting
در Mass Assignment، بدنه درخواست مستقیماً روی مدل پایگاه داده یا Entity اعمال میشود. مهاجم فیلدی را میفرستد که رابط کاربری نمایش نمیدهد اما مدل آن را میپذیرد؛ مانند role، isAdmin، balance یا ownerId. راهحل امن، استفاده از DTO ورودی و Allowlist صریح فیلدهاست.
{
"displayName": "Ali",
"role": "admin",
"isVerified": true
}
حتی اگر این JSON از نظر Syntax و Schema عمومی معتبر باشد، endpoint ویرایش پروفایل نباید role یا isVerified را از کاربر بپذیرد.
۲. Broken Object Level Authorization
شناسه موجود در JSON نباید مبنای اعتماد باشد. دریافت orderId یا userId از client به معنی مجاز بودن دسترسی نیست. سرور باید مالکیت یا سطح دسترسی کاربر جاری را برای همان شیء بررسی کند و هرگز فقط به مخفیبودن شناسه تکیه نکند.
۳. فیلدهای اضافی و قراردادهای باز
پذیرفتن آزادانه additional properties باعث میشود داده ناخواسته وارد لایههای بعدی شود. در endpointهای حساس بهتر است فیلدهای ناشناخته رد شوند. در APIهایی که نیاز به سازگاری رو به جلو دارند، میتوان فیلد اضافی را نادیده گرفت، اما نباید بدون بررسی ذخیره یا به فرمان داخلی تبدیل شود.
۴. Payload بسیار بزرگ و ساختار عمیق
آرایههای بسیار بزرگ، Stringهای چندمگابایتی و Objectهای با عمق زیاد میتوانند CPU و حافظه را مصرف کنند. محدودیت باید پیش از Parse کامل اعمال شود: Content-Length، سقف بدنه، تعداد آیتمها، طول String، عمق nesting و Timeout. Rate Limit جایگزین محدودیت اندازه هر درخواست نیست.
۵. Duplicate Key و تفاوت رفتار Parserها
در JSON استاندارد، نام اعضای Object بهتر است یکتا باشد، اما Parserها ممکن است در برخورد با کلید تکراری رفتار متفاوتی داشته باشند: اولین مقدار، آخرین مقدار یا خطا. اگر Gateway و Backend رفتار متفاوتی داشته باشند، اعتبارسنجی یک مقدار و مصرف مقدار دیگری ممکن است رخ دهد. یک سیاست ثابت انتخاب و در تمام لایهها اجرا کنید.
{
"role": "user",
"role": "admin"
}
۶. افشای اطلاعات حساس
توکن، رمز عبور، کلید API، شماره کامل کارت، داده شخصی و Stack Trace نباید در JSON پاسخ یا Log ظاهر شوند. Redaction باید ساختاری باشد؛ جستجوی ساده نام فیلد کافی نیست، زیرا داده حساس ممکن است در Object تودرتو، Array یا نامهای متفاوت قرار گیرد.
اعتبارسنجی امن JSON: از Syntax تا منطق کسبوکار
یک pipeline امن معمولاً ابتدا نوع محتوا و اندازه را کنترل میکند، سپس JSON را Parse میکند، Schema را اعمال میکند، داده را به DTO محدود تبدیل میکند و در نهایت قواعد کسبوکار و Authorization را بررسی میکند. ترتیب مهم است؛ اجرای Query پایگاه داده یا عملیات پرهزینه پیش از رد ورودی نامعتبر، سطح حمله را افزایش میدهد.
const allowed = {
displayName: body.displayName,
bio: body.bio
};
if (typeof allowed.displayName !== 'string' || allowed.displayName.length > 80) {
throw new Error('Invalid displayName');
}
await updateProfile(currentUser.id, allowed);
قواعد Schema که ارزش امنیتی دارند
- تعیین type دقیق برای هر فیلد و جلوگیری از coercion مبهم
- استفاده از required فقط برای فیلدهای واقعاً ضروری
- محدودکردن maxLength و minLength برای Stringها
- محدودکردن maximum، minimum و multipleOf برای Numberها
- تعیین maxItems و uniqueItems برای Arrayها در صورت نیاز
- استفاده آگاهانه از additionalProperties: false در ورودیهای حساس
- محدودکردن patternها و پرهیز از Regexهای مستعد ReDoS
Schema Validation امنیت کامل ایجاد نمیکند. Schema نمیداند قیمت جدید از قیمت مجاز کمتر است، سفارش متعلق به کاربر است یا وضعیت جاری اجازه انتقال به وضعیت بعدی را میدهد. این موارد باید در لایه Domain بررسی شوند.
JSON Injection، XSS و قرار دادن JSON در HTML
JSON بهتنهایی executable نیست، اما قرار دادن رشته JSON بدون Escape مناسب داخل HTML یا JavaScript میتواند زمینه XSS ایجاد کند. امنترین روش این است که داده از endpoint JSON با Content-Type صحیح دریافت شود و با APIهای DOM نمایش داده شود، نه با concatenation و innerHTML. هنگام قراردادن JSON در اسکریپت inline باید کاراکترهای حساس متناسب با context Escape شوند.
// ناامن برای محتوای کنترلشده توسط کاربر
element.innerHTML = data.comment;
// امنتر برای متن ساده
element.textContent = data.comment;
همچنین Content-Type پاسخ JSON باید application/json باشد. فعالکردن nosniff در پاسخها میتواند از تفسیر نادرست نوع محتوا توسط مرورگر جلوگیری کند. CORS نیز کنترل Authorization نیست؛ CORS فقط مشخص میکند کدام Origin در مرورگر اجازه خواندن پاسخ را دارد.
امنیت Parser و Deserialize کردن
از Parser استاندارد و بهروز زبان استفاده کنید و JSON را به Objectهای اجرایی یا کلاسهای دلخواه Deserialize نکنید. در کتابخانههایی که polymorphic deserialization یا type metadata دارند، پذیرش نام نوع از ورودی میتواند خطرناک باشد. ورودی باید به DTOهای ساده و از پیش تعریفشده تبدیل شود.
عددهای بزرگ و دقت
JSON یک نوع Number دارد، اما Runtimeها محدودیتهای متفاوتی دارند. شناسههای ۶۴ بیتی ممکن است در JavaScript دقت خود را از دست بدهند. برای شناسههای بزرگ، قرارداد String میتواند امنتر و قابلپیشبینیتر باشد. همچنین NaN و Infinity بخشی از JSON معتبر نیستند و نباید بیصدا پذیرفته شوند.
Encoding و Unicode
API باید Encoding مشخص و یکسان، معمولاً UTF-8، داشته باشد. نرمالسازی Unicode در مقایسه نام کاربری، مسیر یا کلید امنیتی مهم است؛ دو رشته ظاهراً یکسان ممکن است توالی کدپوینت متفاوت داشته باشند. نرمالسازی نباید بدون شناخت دامنه روی امضاهای دیجیتال یا داده باینریشده اعمال شود.
احراز هویت، مجوزدهی و JSON
توکن احراز هویت معمولاً در Header ارسال میشود، نه در بدنه JSON. قرار دادن credential در بدنه باعث افزایش احتمال ثبتشدن آن در Log و ابزارهای مانیتورینگ میشود. بعد از احراز هویت، مجوز هر endpoint، هر شیء و در صورت لزوم هر فیلد باید بررسی شود. کنترل نقش کلی بهتنهایی برای منابع چندمستاجری کافی نیست.
{
"invoiceId": "inv_734",
"status": "paid"
}
سرور نباید تنها به دلیل معتبر بودن invoiceId و status عملیات را انجام دهد؛ باید بررسی کند فاکتور متعلق به Tenant جاری است و کاربر اجازه تغییر وضعیت را دارد.
خطاها و پاسخهای امن API
پیام خطا باید برای client قابل استفاده باشد اما جزئیات داخلی را افشا نکند. نام جدول، Query، مسیر فایل، Stack Trace و نسخه کتابخانه نباید در پاسخ عمومی قرار گیرد. در مقابل، کد خطای پایدار، نام فیلد و توضیح محدود میتواند برای اصلاح درخواست مفید باشد.
{
"error": {
"code": "VALIDATION_FAILED",
"fields": {
"displayName": "Maximum length is 80"
}
}
}
برای رخداد داخلی یک correlation id تولید کنید و جزئیات را فقط در Log امن نگه دارید. بدنه کامل درخواست را بهصورت پیشفرض Log نکنید، بهخصوص در endpointهای Login، Payment و اطلاعات شخصی.
امنیت خروجی JSON
خروجی نیز باید DTO مستقل داشته باشد. بازگرداندن مستقیم Entity میتواند فیلدهایی مانند passwordHash، internalNotes، resetToken، costPrice یا شناسههای داخلی را افشا کند. اصل کمینهسازی داده میگوید فقط فیلدهایی را برگردانید که مصرفکننده برای همان عملیات نیاز دارد.
| روش پرخطر | روش امنتر |
|---|---|
| بازگرداندن مستقیم مدل دیتابیس | Mapping به Response DTO |
| Log کردن کل body | ثبت metadata و Redaction ساختاری |
| پذیرش تمام فیلدهای body | Allowlist در DTO ورودی |
| اعتماد به userId ارسالی | استفاده از هویت server-side و کنترل مالکیت |
| فقط Syntax Validation | Schema، Domain Validation و Authorization |
امضا، رمزنگاری و Hash چه نقشی دارند؟
TLS از داده در مسیر محافظت میکند. اگر لازم است گیرنده اصالت و عدم تغییر یک payload را مستقل بررسی کند، امضای دیجیتال یا MAC با قرارداد canonicalization روشن نیاز است. Hash ساده اثباتکننده هویت فرستنده نیست. Encryption نیز جای Authorization و Validation را نمیگیرد؛ داده رمزگشاییشده همچنان ورودی غیرقابل اعتماد است.
امضای JSON خام میتواند به تفاوت فاصله، ترتیب کلیدها و نمایش عدد حساس باشد. باید دقیقاً مشخص شود کدام بایتها امضا میشوند یا از روش canonicalization استاندارد و سازگار میان تولیدکننده و مصرفکننده استفاده شود.
چکلیست امنیت JSON در APIها
- پذیرش فقط Content-Type مورد انتظار و UTF-8 مشخص
- اعمال سقف اندازه بدنه و Timeout پیش از Parse کامل
- محدودکردن عمق Object و تعداد اعضای Array
- رد یا مدیریت یکسان Duplicate Key در تمام لایهها
- Schema Validation با محدودیت طول، تعداد و بازه
- استفاده از DTO و Allowlist بهجای Binding مستقیم Entity
- کنترل Authorization در سطح endpoint، شیء و فیلد
- جلوگیری از افشای Secret در پاسخ و Log
- استفاده از Response DTO و کمینهسازی داده
- تست ورودیهای malformed، بسیار بزرگ، عمیق و دارای فیلد اضافی
- بهروزرسانی Parser و کتابخانههای Serialization
- Rate Limit و مانیتورینگ الگوهای غیرعادی
خطاهای رایج در پیادهسازی
- فرض اینکه JSON معتبر از نظر Syntax حتماً امن است
- استفاده از CORS بهعنوان جایگزین Authorization
- اعتماد به فیلدهای role، ownerId یا price از client
- Coercion خودکار String به Number یا Boolean بدون قرارداد
- پذیرش Objectهای آزاد برای endpointهای حساس
- نمایش پیام خطای خام دیتابیس یا Stack Trace
- ثبت کامل توکن و اطلاعات شخصی در Log
- اتکا به فیلتر blacklist بهجای Allowlist
جمعبندی
امنیت JSON در APIها یک قابلیت واحد یا یک Validator نیست؛ زنجیرهای از کنترلهاست. JSON باید بهعنوان ورودی غیرقابل اعتماد وارد سیستم شود، از محدودیت منابع عبور کند، با Parser ثابت و Schema مشخص بررسی شود، به DTO محدود تبدیل شود و سپس قواعد Domain و Authorization روی آن اجرا شوند. در خروجی نیز باید فقط داده ضروری نمایش داده شود. با این رویکرد، معتبر بودن JSON به نقطه شروع تبدیل میشود، نه پایان بررسی امنیتی.