مشکلات امنیتی رایج استفاده جاوااسکریپت در بک اند

finance-monthlyامروز جاوااسکریپت فقط در فرانت استفاده نمی شود و استفاده از جاوا اسکریپت در بک اند توسط runtime هایی همچون nodejs متداول شده است.در این مطلب میخواهیم مشکلاتی که اغلب خود برنامه نویسان در بک اند به وجود می آورند را بررسی کنیم.انواع Injectionدر این نوع attack ها سعی ما بر این است از جاهایی که توسعه دهنده مقادیر ورودی را کنترل نکرده است مقادیر خودمان را وارد کنیم.۱- تزریق SQL/noSQL injectionمثال noSQLدر مثال ما پایگاه داده مورد استفاده ما mongodb است.در این پایگاه داده متغیر هایی مانند ne$(به معنی نابرابر) و gt$( به معنی بزرگتر) که می توان از آن ها سوء استفاده کرد.همین موضوع کافی است تا در query که از ما گرفته میشود به جای مقدار درخواست شده متغیر ne$ یا gt$ بگذاریم.برای مثال در json زیر ایمیل و کلمه عبور از ما گرفته می شود و با مدل User چک می شود، کافی است به جای مقدار واقعی payload خود را بگذاریم.{ "email": {"$gt": ""}, "password": {"$gt": ""} }این مقدار ها باعت می شود دیتابیس هر مقداری را که بزرگتر از "" را برگرداند و این موضوع یعنی اینکه همه کاربرانی که ایمیل و کلمه عبورشان بزرگتر از "" میتواند منظور query ما باشد.حالا نگاهی به کد آسیب پذیر بی اندازیم:app.post('/login',function(req,res){ User.findOne({'email':req.body.email,'password':req.body.password},function(err,data){ if(err){ res.send(err); }else if(data){ res.send('User Login Successful'); }else { res.send('Wrong Username Password Combination'); } })});توسعه دهنده بدون هیچ input validation مقادیر ایمیل و پسورد را از کاربر می گیرد کد بهبود یافته مانند زیر می شود:app.post('/login',function(req,res){ var email = req.body.email; var password = req.body.password; User.findOne({'email': { $in: [email] },'password': { $in: [password] }},function(err,data){ if(err){ res.send(err); }else if(data){ res.send('User Login Successful'); }else { res.send('Wrong Username Password Combination'); } })});بهبود فقط با اضافه شدن in$ به این معنی که مقدار فرستاده شده کاربر اگر در آرایه مقادیر بود مقدار True برگردان.توضیحات بیشتر در scotch.io مثال SQLفرض کنید توسعه دهنده نام کاربری را به این شکل در query خود قرار می دهد.SELECT * FROM users WHERE username = '" + username + "';خب ما میتوانیم داخل username این payload را قرار دهیم' OR '1'='1';یعنی query را ببندیم و مقدار ۱=۱ را قرار دهیم تا query توسط ما True شود.اگر هم بعد از username مقادیر دیگری هم مانند مثال زیر گرفته می شود کافی است بقیه query را کامنت کنیم.SELECT * FROM users WHERE username = '" + username + "' and password = '" + password + "';پس ' OR '1'='1';--برای بهبود کد می توان به جای اینکه مستقیم مقدار کاربر را در query قرار داد آن را توسط کتابخانه pg از کاربر گفت.توضیحات بیشتر به همراه آموزش تست توسط sqlmap در nearform.comمثال جالب دیگر برای دور زدن Authentication در medium۲- تزریق Command Injectionتوابعی مثل ()eval، setTimeout()، setInterval()، Function() که مقادیری را از کاربر می توانند بگیرند اگر دستوراتی مانند:while(1)process.exit()process.kill(process.pid) بگیرند باعث حملات تکذیب سرور یا Denial of Service شود.البته می توان فایل های سیستمی یا دایرکتوری ها را نیز هم با این Attack احتمالا خوانددستوراتی مانند: res.end(require('fs').readdirSync('../..').toString()) res.end(require('fs').readFileSync('../../../../../../../../../../etc/passwd')) کد آسیب پذیر:var cmd = eval(req.body.cmd);کد بهبود یافته:var cmd = parseInt(req.body.cmd);توضیحات بیشتر در کتابچه nodegoat۳- حملات XXEفرض کنید قرار است اطلاعاتی را از کاربر در قالب xml بگیرید مانند کد زیر var products = libxmljs.parseXmlString(req.files.products.data.toString('utf8'), {noent:true,noblanks:true})به صورت پیش فرض کتابخانه libxmljs می تواند فایل های اکسترنال را هم فراخوانی کنید و ما هم از این فرصت استفاده می کنیم و یک entity تعریف می کنیم و ارسال می کنیم:<!DOCTYPE foo [<!ELEMENT foo ANY ><!ENTITY bar SYSTEM "file:///etc/passwd" >]><products> <product> <name>Playstation 4</name> <code>274</code> <tags>gaming console</tags> <description>&bar;</description> </product></products>عملا باید بتوانیم محتوا فایل passwd را بخوانیم.کد بهبود یافته: var products = libxmljs.parseXmlString(req.files.products.data.toString('utf8'), {noent:false,noblanks:true})توضیحات بیشتر در کتابچه appsecco۵-حملات Insecure Deserializationاول از همه نگاهی به payload اتک بی اندازیم:{"rce":"_$$ND_FUNC$$_function (){require('child_process').exec('id;cat /etc/passwd', function(error, stdout, stderr) { console.log(stdout) });}()"} با این payload می توانیم محتوا passwd را بخوانیم! چطور؟اگر موقع deserialization کردن مانند کد زیر به صورت نا امن deserialization بکنیم این آسیب پذیری به وجود می آید: var products = serialize.unserialize(req.files.products.data.toString('utf8'))کد بهبود یافته می تواند مانند زیر باشد:var products = JSON.parse(req.files.products.data.toString('utf8'))توضیح بیشتر در کتابچه appseccoمنابعSlideShareAppseccoBaweTechمعذرت بابت کم و کاستی های فراوان این مطلب خیلی خوشحال میشوم نظرات خود را اینجا بگذاریدبا تشکر از شما