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

finance-monthly
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

منابع



معذرت بابت کم و کاستی های فراوان این مطلب
خیلی خوشحال میشوم نظرات خود را اینجا بگذارید

با تشکر از شما