تزریق NoSQL

از Secure Coding

پایگاه داده های مبتنی بر nosql به دلیل انعطاف پذیری زیاد نسبت به پایگاه داده های رابطه بسیار پر استفاده هستند.

برای مثال می توان داده هارا بین چند سرور تقسیم و در یک گره از به تمام تراکنش ها دسترسی داشت.

از انواع نمونه های از پایگاه داده می توان به مبتنی بر کلید، سند، گراف اشاره کرد.

به صورت کلی امکان ایجاد آسیب پذیری به دو روش زیر تقسیم می شود.

  1. آسیب پذیری در Driver
  2. آسیب پذیری در API

Nosql.jpg

در تصویر بالا مهاجم از طریق web server و با استفاده با تزریق payload مخرب می تواند به محل ذخیره سازی داده دسترسی پیدا کند.

Nosql2.jpg

در نمونه دیگر آسیب پذیری در نوع ایجاد و استفاده از api در back-end رخ داده است.

به این صورت که json درخواستی به سمت پایگاه دستکاری و payload مخرب تزریق می شود.

برای بررسی روش حمله شیوه کار را در زبان php و پایگاه داده monogodb بررسی می کنیم.

در کد زیر می خواهیم کاربری با username و password احراز هویت کنیم.

db->logins->find(array(“username”=>$_   POST[“username”],   “password”=>$_POST[“password”]));

فرض می کنیم درخواست کاربر به شکل زیر وارد شده است.

{ username: ‘tolkien’,   password: ‘hobbit’}

با توجه به شکل بالا پس احتمال می رود درخواست به شکل زیر پیاده سازی شده باشد.

username=1&password=1

اگر مهاجم username و password را به شکل آرایه تغییر دهد

username[$ne]=1&password[$ne]=1

نمای کلی آرایه به صورت زیر تغییر خواهد کرد.

array(“username” => array(“$[ne] “ =>   1), “password” =>   array(“$ne” => 1));,

لازم به گفتن است که $ne در mongodb به معنی نامساوی یا not equal است.

درخواست در کد شکل زیر قرار میگیرد.

db.logins.find({ username: {$ne:1 },   password {$ne: 1 })

پرس و جو یا query کد بالا به شکل زیر خواهد بود.

SELECT * FROM logins WHERE username <>   1 AND password <> 1

پس درخواست به ازای هر username و password صحیح یا true خواهد بود.

راه جلوگیری از این نوع تزریق مشخص کردن نوع پارامتر درخواست کاربر است.

که می توان بدین منظور از کد زیر نمود.

db->logins->find(  array(“username”=>(string)$_    POST[“username”],  “password”=>(string)$_    POST[“password”]));

روش های جلوگیری

به صورت کلی برای جلوگیری از nosql injection می توان از روش های زیر استفاده کرد.

  1. کنترل ورودی ها
  2. استفاده از library ها

روش های جلوگیری در PHP

مثال 1)

<?php
include_once 'parseTree.php';
use control\ParseTree;
	$stime=microtime(true);
   // connect to mongodb
   $m = new MongoClient();
//   echo "Connection to database successfully";
//	$postedusername = $_REQUEST['username'];
//	$postedpassword = $_REQUEST['password'];
	
   // select a database
   $db = $m->test;
//   echo "Database mydb selected";
   $collection = $db->users;
//   echo "Collection selected succsessfully";
   $dbUsername = null;
   $dbPassword = null;
   
 //   echo $postedusername;
 //  echo $postedpassword; 
   $data = array(
   		'username' =>  $_REQUEST['username'],
   		'password' =>  $_REQUEST['password']
   		
   ); 
   $cursor = $collection->find($data);
/*    $data = array(
   		'username' => array('$ne' => 1),
   		'password' => array('$ne' => 1)
   		 
   ); */
   $string = json_encode($data);
   echo $string;
   
//   print_r($data);
   $scope = array("user" => "Carl");
   $response = $db->execute("function(greeting, name) { return greeting+', '+name+'!'; }", array("Good bye", "Joe"));
   echo $response['retval'];
//   $db->execute("db.user.insert({'assdfdf':'dsaf'})");
 //  $response = $db->execute("db.user.find({'username':'sunuyang'})");
 //  print_r($response);
//   echo $response['retval'];
//    foreach ($data as $temp){
//    	echo $temp;
//    }
 //  $cursor = $collection->find($data);
   
   
   $count = $cursor->count();
   $doc_failed = new DOMDocument();
   $doc_failed->loadHTMLFile("failed.html");
   $doc_succeed = new DOMDocument();
   $doc_succeed->loadHTMLFile("succeed.html");
   $doc_attacked = new DOMDocument();
   $doc_attacked->loadHTMLFile("attacked.html");
//   echo $count;
   $parseTree = new ParseTree();
	if($parseTree->parseTree($string)){
		echo $doc_attacked->saveHTML();
	}
	else
	{
		if($count >0 ){
	
		//   	echo "<h1>login successed</h1>"."</br>";
		   	echo $doc_succeed->saveHTML();
		   	foreach ($cursor as $user){
		   			echo 'username:'.$user['username']."</br>";
		   			echo 'password:'.$user['password']."</br>";
		   		}
		   }
		   else{
		//   	echo "<h1>not find</h1>";
		   	echo $doc_failed->saveHTML();
		   }
	}
   $etime=microtime(true);
   $total=$etime-$stime;
   $str_total = var_export($total, TRUE);
   if(substr_count($str_total,"E")){
   	$float_total = floatval(substr($str_total,5));
   	$total = $float_total/100000;
   	echo $total.'seconds';
   } else echo $total.'seconds';

اگر درخواست به شکل زیر ارسال شود می تواند احراز هویت را bypass کند.

detected_login.php?username[$ne]=9a8942&password[$ne]=bf86om

مثال 2)

<?php
$stime=microtime(true);
$m = new MongoClient();
$db = $m->test;
$collection = $db->users;
  $query_body ="
		function q() {
			var username = ".$_REQUEST["username"].";
			var password = ".$_REQUEST["password"].";if(username == '1'&&password == '1') return true; else{ return false;}}
";  
  echo $query_body;
  //username=1&password=1;return true;}//
  
  
  
//$query_body = "function q() { var username = 1; var password = 1;return true;}//if(username == '1') 
//		return true;else{return false;}";
//echo $query_body;
$result = $collection->find(array('$where'=>$query_body));
$count = $result->count();
$doc_failed = new DOMDocument();
$doc_failed->loadHTMLFile("failed.html");
$doc_succeed = new DOMDocument();
$doc_succeed->loadHTMLFile("succeed.html");
if($count>0){
	echo $doc_succeed->saveHTML();
}
else{
//	echo "<h1>username or password is wrong!</h1>";
	echo $doc_failed->saveHTML();
}
$etime=microtime(true);
$total=$etime-$stime;
$str_total = var_export($total, TRUE);
if(substr_count($str_total,"E")){
	$float_total = floatval(substr($str_total,5));
	$total = $float_total/100000;
	echo $total.'seconds';
} else echo $total.'seconds';

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


login_1.php?username=1&password=2;var date = new Date(); var curDate = null; do { curDate = new Date(); } while((Math.abs(date.getTime()-curDate.getTime()))/100 < 20); return true;}//

راه حل 1)

<?php
include_once 'parseTree.php';
use control\ParseTree;
	$stime=microtime(true);
   // connect to mongodb
   $m = new MongoClient();
//   echo "Connection to database successfully";
//	$postedusername = $_REQUEST['username'];
//	$postedpassword = $_REQUEST['password'];
	
   // select a database
   $db = $m->test;
//   echo "Database mydb selected";
   $collection = $db->users;
//   echo "Collection selected succsessfully";
   $dbUsername = null;
   $dbPassword = null;
   
 //   echo $postedusername;
 //  echo $postedpassword; 
   $data = array(
   		'username' =>  (string)$_REQUEST['username'],
   		'password' =>  (string)$_REQUEST['password']
   		
   ); 
   $cursor = $collection->find($data);
/*    $data = array(
   		'username' => array('$ne' => 1),
   		'password' => array('$ne' => 1)
   		 
   ); */
   $string = json_encode($data);
   echo $string;
   
//   print_r($data);
   $scope = array("user" => "Carl");
   $response = $db->execute("function(greeting, name) { return greeting+', '+name+'!'; }", array("Good bye", "Joe"));
   echo $response['retval'];
//   $db->execute("db.user.insert({'assdfdf':'dsaf'})");
 //  $response = $db->execute("db.user.find({'username':'sunuyang'})");
 //  print_r($response);
//   echo $response['retval'];
//    foreach ($data as $temp){
//    	echo $temp;
//    }
 //  $cursor = $collection->find($data);
   
   
   $count = $cursor->count();
   $doc_failed = new DOMDocument();
   $doc_failed->loadHTMLFile("failed.html");
   $doc_succeed = new DOMDocument();
   $doc_succeed->loadHTMLFile("succeed.html");
   $doc_attacked = new DOMDocument();
   $doc_attacked->loadHTMLFile("attacked.html");
//   echo $count;
   $parseTree = new ParseTree();
	if($parseTree->parseTree($string)){
		echo $doc_attacked->saveHTML();
	}
	else
	{
		if($count >0 ){
	
		//   	echo "<h1>login successed</h1>"."</br>";
		   	echo $doc_succeed->saveHTML();
		   	foreach ($cursor as $user){
		   			echo 'username:'.$user['username']."</br>";
		   			echo 'password:'.$user['password']."</br>";
		   		}
		   }
		   else{
		//   	echo "<h1>not find</h1>";
		   	echo $doc_failed->saveHTML();
		   }
	}
   $etime=microtime(true);
   $total=$etime-$stime;
   $str_total = var_export($total, TRUE);
   if(substr_count($str_total,"E")){
   	$float_total = floatval(substr($str_total,5));
   	$total = $float_total/100000;
   	echo $total.'seconds';
   } else echo $total.'seconds';

راه حل 2)

<?php
$stime=microtime(true);
$m = new MongoClient();
$db = $m->test;
$collection = $db->users;
  $query_body ="
		function q() {
			var username = ".addslashes($_REQUEST["username"]).";
			var password = ".addslashes($_REQUEST["password"]).";if(username == '1'&&password == '1') return true; else{ return false;}}
";  
  echo $query_body;
  //username=1&password=1;return true;}//
  
  
  
//$query_body = "function q() { var username = 1; var password = 1;return true;}//if(username == '1') 
//		return true;else{return false;}";
//echo $query_body;
$result = $collection->find(array('$where'=>$query_body));
$count = $result->count();
$doc_failed = new DOMDocument();
$doc_failed->loadHTMLFile("failed.html");
$doc_succeed = new DOMDocument();
$doc_succeed->loadHTMLFile("succeed.html");
if($count>0){
	echo $doc_succeed->saveHTML();
}
else{
//	echo "<h1>username or password is wrong!</h1>";
	echo $doc_failed->saveHTML();
}
$etime=microtime(true);
$total=$etime-$stime;
$str_total = var_export($total, TRUE);
if(substr_count($str_total,"E")){
	$float_total = floatval(substr($str_total,5));
	$total = $float_total/100000;
	echo $total.'seconds';
} else echo $total.'seconds';

روش های جلوگیری در ASP.NET

مثال 1)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Couchbase;
using Couchbase.N1QL;

namespace N1QlInjection
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();

            ClusterHelper.Initialize();
        }

        private void btnWhereUnsafe_Click(object sender, EventArgs e)
        {
            RunQuery("SELECT * FROM `beer-sample` WHERE type = 'beer' AND name LIKE '%" +
                     edtWhere.Text + "%' AND brewery_id = '21st_amendment_brewery_cafe'");
        }

        private void btnCommentUnsafe_Click(object sender, EventArgs e)
        {
            RunQuery("SELECT * FROM `beer-sample` WHERE type = 'beer' AND name LIKE '%" +
                     edtComment.Text + "%' AND brewery_id = '21st_amendment_brewery_cafe' /* 21st century only */");
        }


        private void RunQuery(string query, IDictionary<string,object> parameters = null)
        {
            edtResults.Text = query + "\r\n\r\nRunning...";
            tabControl.Enabled = false;

            Task.Run(async () =>
            {
                var bucket = ClusterHelper.GetBucket("beer-sample");

                var queryRequest = new QueryRequest(query);
                
                if (parameters != null)
                {
                    queryRequest.AddNamedParameter(parameters.ToArray());
                };

                var result = await
                    bucket.QueryAsync<dynamic>(queryRequest);
                if (!result.Success)
                {
                    if (result.Errors != null && result.Errors.Count > 0)
                    {
                        return result.Errors.First().Message;
                    }
                    else if (result.Exception != null)
                    {
                        return string.Format("{0}\r\n\r\n{1}\r\n{2}", query, result.Exception.Message,
                            result.Exception.StackTrace);
                    }
                    else
                    {
                        return "Unknown Error";
                    }
                }
                else if (result.Rows != null)
                {
                    var sb = new StringBuilder();
                    sb.AppendFormat("{0}\r\n\r\n{1} rows returned\r\n\r\n", query, result.Rows.Count);

                    foreach (var row in result.Rows)
                    {
                        sb.AppendLine(row.ToString());
                    }

                    return sb.ToString();
                }
                else
                {
                    return query + "\r\n\r\n0 row returned";
                }
            })
                .ContinueWith(task =>
                {
                    BeginInvoke(new Action(() =>
                    {
                        if (task.IsFaulted)
                        {
                            edtResults.Text = string.Format("{0}\r\n\r\n{1}\r\n{2}", query, task.Exception.Message,
                                task.Exception.StackTrace);
                        }
                        else
                        {
                            edtResults.Text = task.Result;
                        }

                        tabControl.Enabled = true;
                    }));
                });
        }
    }
}

مثال 2)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Couchbase;
using Couchbase.N1QL;

namespace N1QlInjection
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();

            ClusterHelper.Initialize();
        }

        private void btnWhereUnsafe_Click(object sender, EventArgs e)
        {
            RunQuery("SELECT * FROM `beer-sample` WHERE type = 'beer' AND name LIKE '%" +
                     edtWhere.Text + "%' AND brewery_id = '21st_amendment_brewery_cafe'");
        }

        private void btnCommentUnsafe_Click(object sender, EventArgs e)
        {
            RunQuery("SELECT * FROM `beer-sample` WHERE type = 'beer' AND name LIKE '%" +
                     edtComment.Text + "%' AND brewery_id = '21st_amendment_brewery_cafe' /* 21st century only */");
        }

        private void btnIdentifierUnsafe_Click(object sender, EventArgs e)
        {
            RunQuery("SELECT " + edtIdentifier.Text + " FROM `beer-sample` " + 
                     "WHERE type = 'beer' AND brewery_id = '21st_amendment_brewery_cafe'");
        }


        private void RunQuery(string query, IDictionary<string,object> parameters = null)
        {
            edtResults.Text = query + "\r\n\r\nRunning...";
            tabControl.Enabled = false;

            Task.Run(async () =>
            {
                var bucket = ClusterHelper.GetBucket("beer-sample");

                var queryRequest = new QueryRequest(query);
                
                if (parameters != null)
                {
                    queryRequest.AddNamedParameter(parameters.ToArray());
                };

                var result = await
                    bucket.QueryAsync<dynamic>(queryRequest);
                if (!result.Success)
                {
                    if (result.Errors != null && result.Errors.Count > 0)
                    {
                        return result.Errors.First().Message;
                    }
                    else if (result.Exception != null)
                    {
                        return string.Format("{0}\r\n\r\n{1}\r\n{2}", query, result.Exception.Message,
                            result.Exception.StackTrace);
                    }
                    else
                    {
                        return "Unknown Error";
                    }
                }
                else if (result.Rows != null)
                {
                    var sb = new StringBuilder();
                    sb.AppendFormat("{0}\r\n\r\n{1} rows returned\r\n\r\n", query, result.Rows.Count);

                    foreach (var row in result.Rows)
                    {
                        sb.AppendLine(row.ToString());
                    }

                    return sb.ToString();
                }
                else
                {
                    return query + "\r\n\r\n0 row returned";
                }
            })
                .ContinueWith(task =>
                {
                    BeginInvoke(new Action(() =>
                    {
                        if (task.IsFaulted)
                        {
                            edtResults.Text = string.Format("{0}\r\n\r\n{1}\r\n{2}", query, task.Exception.Message,
                                task.Exception.StackTrace);
                        }
                        else
                        {
                            edtResults.Text = task.Result;
                        }

                        tabControl.Enabled = true;
                    }));
                });
        }
    }
}

راه حل 1)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Couchbase;
using Couchbase.N1QL;

namespace N1QlInjection
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();

            ClusterHelper.Initialize();
        }

        private void btnWhereUnsafe_Click(object sender, EventArgs e)
        {
            RunQuery("SELECT * FROM `beer-sample` WHERE type = 'beer' AND name LIKE '%" +
                     edtWhere.Text + "%' AND brewery_id = '21st_amendment_brewery_cafe'");
        }
        
        private void btnWhereSafe_Click(object sender, EventArgs e)
        {
            RunQuery("SELECT * FROM `beer-sample` WHERE type = 'beer' AND name LIKE '%" +
                     edtWhere.Text.Replace("'", "''") + "%' AND brewery_id = '21st_amendment_brewery_cafe'");
        }

        private void btnWhereSafeParam_Click(object sender, EventArgs e)
        {
            var parameters = new Dictionary<string, object>()
            {
                { "$name", "%" + edtWhere.Text + "%" }
            };

            RunQuery("SELECT * FROM `beer-sample` WHERE type = 'beer' AND name LIKE $name " +
                     "AND brewery_id = '21st_amendment_brewery_cafe'", parameters);

        }

        private void btnCommentUnsafe_Click(object sender, EventArgs e)
        {
            RunQuery("SELECT * FROM `beer-sample` WHERE type = 'beer' AND name LIKE '%" +
                     edtComment.Text + "%' AND brewery_id = '21st_amendment_brewery_cafe' /* 21st century only */");
        }
        
        private void btnCommentSafe_Click(object sender, EventArgs e)
        {
            RunQuery("SELECT * FROM `beer-sample` WHERE type = 'beer' AND name LIKE '%" +
                     edtComment.Text.Replace("'", "''") + "%' AND brewery_id = '21st_amendment_brewery_cafe'"); // 21st century only
        }

        private void RunQuery(string query, IDictionary<string,object> parameters = null)
        {
            edtResults.Text = query + "\r\n\r\nRunning...";
            tabControl.Enabled = false;

            Task.Run(async () =>
            {
                var bucket = ClusterHelper.GetBucket("beer-sample");

                var queryRequest = new QueryRequest(query);
                
                if (parameters != null)
                {
                    queryRequest.AddNamedParameter(parameters.ToArray());
                };

                var result = await
                    bucket.QueryAsync<dynamic>(queryRequest);
                if (!result.Success)
                {
                    if (result.Errors != null && result.Errors.Count > 0)
                    {
                        return result.Errors.First().Message;
                    }
                    else if (result.Exception != null)
                    {
                        return string.Format("{0}\r\n\r\n{1}\r\n{2}", query, result.Exception.Message,
                            result.Exception.StackTrace);
                    }
                    else
                    {
                        return "Unknown Error";
                    }
                }
                else if (result.Rows != null)
                {
                    var sb = new StringBuilder();
                    sb.AppendFormat("{0}\r\n\r\n{1} rows returned\r\n\r\n", query, result.Rows.Count);

                    foreach (var row in result.Rows)
                    {
                        sb.AppendLine(row.ToString());
                    }

                    return sb.ToString();
                }
                else
                {
                    return query + "\r\n\r\n0 row returned";
                }
            })
                .ContinueWith(task =>
                {
                    BeginInvoke(new Action(() =>
                    {
                        if (task.IsFaulted)
                        {
                            edtResults.Text = string.Format("{0}\r\n\r\n{1}\r\n{2}", query, task.Exception.Message,
                                task.Exception.StackTrace);
                        }
                        else
                        {
                            edtResults.Text = task.Result;
                        }

                        tabControl.Enabled = true;
                    }));
                });
        }
    }
}

راه حل 2)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Couchbase;
using Couchbase.N1QL;

namespace N1QlInjection
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();

            ClusterHelper.Initialize();
        }

        private void btnWhereUnsafe_Click(object sender, EventArgs e)
        {
            RunQuery("SELECT * FROM `beer-sample` WHERE type = 'beer' AND name LIKE '%" +
                     edtWhere.Text + "%' AND brewery_id = '21st_amendment_brewery_cafe'");
        }

        private void btnWhereSafe_Click(object sender, EventArgs e)
        {
            RunQuery("SELECT * FROM `beer-sample` WHERE type = 'beer' AND name LIKE '%" +
                     edtWhere.Text.Replace("'", "''") + "%' AND brewery_id = '21st_amendment_brewery_cafe'");
        }

        private void btnWhereSafeParam_Click(object sender, EventArgs e)
        {
            var parameters = new Dictionary<string, object>()
            {
                { "$name", "%" + edtWhere.Text + "%" }
            };

            RunQuery("SELECT * FROM `beer-sample` WHERE type = 'beer' AND name LIKE $name " +
                     "AND brewery_id = '21st_amendment_brewery_cafe'", parameters);

        }

        private void btnCommentUnsafe_Click(object sender, EventArgs e)
        {
            RunQuery("SELECT * FROM `beer-sample` WHERE type = 'beer' AND name LIKE '%" +
                     edtComment.Text + "%' AND brewery_id = '21st_amendment_brewery_cafe' /* 21st century only */");
        }

        private void btnCommentSafe_Click(object sender, EventArgs e)
        {
            RunQuery("SELECT * FROM `beer-sample` WHERE type = 'beer' AND name LIKE '%" +
                     edtComment.Text.Replace("'", "''") + "%' AND brewery_id = '21st_amendment_brewery_cafe'"); // 21st century only
        }

        private void btnIdentifierUnsafe_Click(object sender, EventArgs e)
        {
            RunQuery("SELECT " + edtIdentifier.Text + " FROM `beer-sample` " + 
                     "WHERE type = 'beer' AND brewery_id = '21st_amendment_brewery_cafe'");
        }

        private void btnIdentifierSafe_Click(object sender, EventArgs e)
        {
            RunQuery("SELECT `" + edtIdentifier.Text.Replace("`", "``") + "` FROM `beer-sample` " +
                     "WHERE type = 'beer' AND brewery_id = '21st_amendment_brewery_cafe'");
        }

        private void RunQuery(string query, IDictionary<string,object> parameters = null)
        {
            edtResults.Text = query + "\r\n\r\nRunning...";
            tabControl.Enabled = false;

            Task.Run(async () =>
            {
                var bucket = ClusterHelper.GetBucket("beer-sample");

                var queryRequest = new QueryRequest(query);
                
                if (parameters != null)
                {
                    queryRequest.AddNamedParameter(parameters.ToArray());
                };

                var result = await
                    bucket.QueryAsync<dynamic>(queryRequest);
                if (!result.Success)
                {
                    if (result.Errors != null && result.Errors.Count > 0)
                    {
                        return result.Errors.First().Message;
                    }
                    else if (result.Exception != null)
                    {
                        return string.Format("{0}\r\n\r\n{1}\r\n{2}", query, result.Exception.Message,
                            result.Exception.StackTrace);
                    }
                    else
                    {
                        return "Unknown Error";
                    }
                }
                else if (result.Rows != null)
                {
                    var sb = new StringBuilder();
                    sb.AppendFormat("{0}\r\n\r\n{1} rows returned\r\n\r\n", query, result.Rows.Count);

                    foreach (var row in result.Rows)
                    {
                        sb.AppendLine(row.ToString());
                    }

                    return sb.ToString();
                }
                else
                {
                    return query + "\r\n\r\n0 row returned";
                }
            })
                .ContinueWith(task =>
                {
                    BeginInvoke(new Action(() =>
                    {
                        if (task.IsFaulted)
                        {
                            edtResults.Text = string.Format("{0}\r\n\r\n{1}\r\n{2}", query, task.Exception.Message,
                                task.Exception.StackTrace);
                        }
                        else
                        {
                            edtResults.Text = task.Result;
                        }

                        tabControl.Enabled = true;
                    }));
                });
        }
    }
}

روش های جلوگیری در JAVA

مثال 1)

package nosql.injection.demo.model;

import com.mongodb.*;
import com.mongodb.util.JSON;

import java.net.UnknownHostException;

public class NoSQLDatabase {

    private DBCollection characters;

    private static NoSQLDatabase instance;

    public static NoSQLDatabase getInstance() throws UnknownHostException {
        if (instance == null) {
            instance = new NoSQLDatabase();
        }
        return instance;
    }

    public InjectionResult insecureFindByName(String name) throws UnknownHostException {

        InjectionResult injectionResult = new InjectionResult();

        String stringQuery = "{ 'name' : '" + name + "'}";
        injectionResult.setStringQuery(stringQuery);

        DBObject databaseQuery = (DBObject) JSON.parse(stringQuery);
        injectionResult.setDatabaseQuery(databaseQuery);

        DBCursor result = characters.find(databaseQuery);
        injectionResult.setResult(result);

        return injectionResult;
    }

    private NoSQLDatabase() throws UnknownHostException {

        // More details at http://docs.mongodb.org/ecosystem/tutorial/getting-started-with-java-driver/
        MongoClient mongoClient = new MongoClient();

        DB gameOfThronesDatabase = mongoClient.getDB("GameOfThrones");
        gameOfThronesDatabase.dropDatabase();

        characters = gameOfThronesDatabase.getCollection("characters");
        seedData();
    }

    private void seedData() {
        BasicDBObject robb = new BasicDBObject("_id", 1).append("name", "Robb").append("surname", "Stark").append("address", "Kingslayer");
        BasicDBObject sansa = new BasicDBObject("_id", 2).append("name", "Sansa").append("surname", "Stark").append("address", "Kingslayer");
        BasicDBObject tyrion = new BasicDBObject("_id", 3).append("name", "Tyrion").append("surname", "Lannister").append("address", "Casterly Rock");
        BasicDBObject jaime = new BasicDBObject("_id", 4).append("name", "Jaime").append("surname", "Lannister").append("address", "Casterly Rock");
        BasicDBObject cersei = new BasicDBObject("_id", 5).append("name", "Cersei").append("surname", "Lannister").append("address", "Casterly Rock");
        BasicDBObject tywin = new BasicDBObject("_id", 6).append("name", "Tywin").append("surname", "Lannister").append("address", "Casterly Rock");
        characters.insert(robb);
        characters.insert(sansa);
        characters.insert(tyrion);
        characters.insert(jaime);
        characters.insert(cersei);
        characters.insert(tywin);
    }

}

راه حل 1)

package nosql.injection.demo.model;

import com.mongodb.*;
import com.mongodb.util.JSON;

import java.net.UnknownHostException;

public class NoSQLDatabase {

    private DBCollection characters;

    private static NoSQLDatabase instance;

    public static NoSQLDatabase getInstance() throws UnknownHostException {
        if (instance == null) {
            instance = new NoSQLDatabase();
        }
        return instance;
    }

    public InjectionResult insecureFindByName(String name) throws UnknownHostException {

        InjectionResult injectionResult = new InjectionResult();

        String stringQuery = "{ 'name' : '" + name + "'}";
        injectionResult.setStringQuery(stringQuery);

        DBObject databaseQuery = (DBObject) JSON.parse(stringQuery);
        injectionResult.setDatabaseQuery(databaseQuery);

        DBCursor result = characters.find(databaseQuery);
        injectionResult.setResult(result);

        return injectionResult;
    }


    public InjectionResult secureFindByName(String name) throws UnknownHostException {

        InjectionResult injectionResult = new InjectionResult();

        BasicDBObject databaseQuery = new BasicDBObject("name", name);
        injectionResult.setDatabaseQuery(databaseQuery);

        DBCursor result = characters.find(databaseQuery);
        injectionResult.setResult(result);

        return injectionResult;
    }



    private NoSQLDatabase() throws UnknownHostException {

        // More details at http://docs.mongodb.org/ecosystem/tutorial/getting-started-with-java-driver/
        MongoClient mongoClient = new MongoClient();

        DB gameOfThronesDatabase = mongoClient.getDB("GameOfThrones");
        gameOfThronesDatabase.dropDatabase();

        characters = gameOfThronesDatabase.getCollection("characters");
        seedData();
    }

    private void seedData() {
        BasicDBObject robb = new BasicDBObject("_id", 1).append("name", "Robb").append("surname", "Stark").append("address", "Kingslayer");
        BasicDBObject sansa = new BasicDBObject("_id", 2).append("name", "Sansa").append("surname", "Stark").append("address", "Kingslayer");
        BasicDBObject tyrion = new BasicDBObject("_id", 3).append("name", "Tyrion").append("surname", "Lannister").append("address", "Casterly Rock");
        BasicDBObject jaime = new BasicDBObject("_id", 4).append("name", "Jaime").append("surname", "Lannister").append("address", "Casterly Rock");
        BasicDBObject cersei = new BasicDBObject("_id", 5).append("name", "Cersei").append("surname", "Lannister").append("address", "Casterly Rock");
        BasicDBObject tywin = new BasicDBObject("_id", 6).append("name", "Tywin").append("surname", "Lannister").append("address", "Casterly Rock");
        characters.insert(robb);
        characters.insert(sansa);
        characters.insert(tyrion);
        characters.insert(jaime);
        characters.insert(cersei);
        characters.insert(tywin);
    }

}