এসকিউএল ইঞ্জেকশন যা mysql_real_escape_string () এর আশেপাশে পায়


645

mysql_real_escape_string()ফাংশন ব্যবহার করার পরেও কি কোনও এসকিউএল ইঞ্জেকশন সম্ভাবনা রয়েছে ?

এই নমুনা পরিস্থিতি বিবেচনা করুন। এসকিউএল এইভাবে পিএইচপিতে নির্মিত হয়:

$login = mysql_real_escape_string(GetFromPost('login'));
$password = mysql_real_escape_string(GetFromPost('password'));

$sql = "SELECT * FROM table WHERE login='$login' AND password='$password'";

আমি অসংখ্য মানুষ আমাকে বলতে শুনেছি যে এর মতো কোডটি এখনও বিপজ্জনক এবং এমনকি mysql_real_escape_string()ব্যবহৃত ফাংশন সহ হ্যাক করাও সম্ভব । তবে আমি কোনও সম্ভাব্য শোষণের কথা ভাবতে পারি না?

ক্লাসিক ইনজেকশনগুলি এর মতো:

aaa' OR 1=1 --

কাজ করোনা.

উপরের পিএইচপি কোডের মাধ্যমে পাওয়া কোনও সম্ভাব্য ইনজেকশন সম্পর্কে আপনি কি জানেন?


34
@ থিফমাস্টার - আমি অবৈধ ব্যবহারকারীর / অবৈধ পাসওয়ার্ডের মতো ভার্বোস ত্রুটি না দেওয়া পছন্দ করি ... এটি নিষ্ঠুর জাল ব্যবসায়ীদের বলে যে তাদের একটি বৈধ ইউজার আইডি আছে, এবং এটি কেবল তাদের পাসওয়ার্ড অনুমান করা দরকার
মার্ক বাকের

18
যদিও ব্যবহারের দিক থেকে এটি ভয়াবহ। কখনও কখনও আপনি আপনার মূল ডাকনাম / ব্যবহারকারীর নাম / ইমেল-ঠিকানা ব্যবহার করতে পারেন না এবং কিছু সময় পরে এটি ভুলে যেতে পারেন বা সাইটটি আপনার অ্যাকাউন্টটি নিষ্ক্রিয়তার জন্য মুছে ফেলেছে। তারপরে এটি অত্যন্ত বিরক্তিকর যদি আপনি পাসওয়ার্ড ব্যবহার করে চালিয়ে যান এবং এমনকি আপনার আইপিটি অবৈধ হলেও আপনার আইপিটি ব্লক হয়ে যায়।
চোরমাস্টার

50
দয়া করে mysql_*নতুন কোডে ফাংশন ব্যবহার করবেন না । এগুলি আর রক্ষণাবেক্ষণ করা হয় না এবংএটিতে অবমূল্যায়ন প্রক্রিয়া শুরু হয়েছে। দেখুন লাল বক্স ? পরিবর্তে প্রস্তুত বিবৃতি সম্পর্কে জানুন, এবং PDO বা মাইএসকিউএলি ব্যবহার করুন- এই নিবন্ধটি আপনাকে সিদ্ধান্ত নিতে সহায়তা করবে। আপনি যদি PDO চয়ন করেন তবে এখানে একটি ভাল টিউটোরিয়াল রয়েছে
tereško

13
@ মেশিনেডিক্টিক্ট, 5.5 সাল থেকে (যা সম্প্রতি প্রকাশিত হয়েছিল) mysql_*ফাংশনগুলি ইতিমধ্যে E_DEPRECATEDসতর্কতা তৈরি করে। ext/mysql10 বছরের বেশি সময় ধরে এই এক্সটেনশনটি বজায় রাখা হয়নি। আপনি কি আসলেই এত বিভ্রান্তিকর?
tereško

13
@ মেশিনেডিক্টিক্ট তারা কেবল পিএইচপি 7.0 এ সেই এক্সটেনশনটি সরিয়েছে এবং এটি এখনও 2050 নয়।
জিজিজি

উত্তর:


379

নিম্নলিখিত কোয়েরি বিবেচনা করুন:

$iId = mysql_real_escape_string("1 OR 1=1");    
$sSql = "SELECT * FROM table WHERE id = $iId";

mysql_real_escape_string()এর বিরুদ্ধে আপনাকে রক্ষা করবে না। আপনি ' 'আপনার প্রশ্নের ভিতরে আপনার ভেরিয়েবলের চারপাশে একক উদ্ধৃতি ( ) ব্যবহার করেন তা হ'ল এটি আপনাকে এর বিরুদ্ধে রক্ষা করে। নিম্নলিখিতটিও একটি বিকল্প:

$iId = (int)"1 OR 1=1";
$sSql = "SELECT * FROM table WHERE id = $iId";

9
তবে এটি আসল সমস্যা হবে না, কারণ mysql_query()একাধিক বিবৃতি কার্যকর করে না, না?
পেক্কা 21

11
@ পেপকা, যদিও এর সাধারণ উদাহরণ, বাস্তবে DROP TABLEআক্রমণকারীর সম্ভাবনা বেশি SELECT passwd FROM users। পরবর্তী ক্ষেত্রে, দ্বিতীয় ক্লোয়ারটি সাধারণত একটি UNIONধারা ব্যবহার করে কার্যকর করা হয় ।
জ্যাকো

58
(int)mysql_real_escape_string- এর কোন মানে নেই. এটা তোলে থেকে ভিন্ন নয় (int)এ সব। এবং তারা প্রতিটি ইনপুট
zerkms

28
এটি অন্য কোনও কিছুর চেয়ে ফাংশনটির অপব্যবহারের বেশি। সর্বোপরি, এর নামকরণ হয়েছে mysql_real_escape_string, নেই mysql_real_escape_integer। এটি পূর্ণসংখ্যার ক্ষেত্রগুলির সাথে ব্যবহার করার অর্থ নয়।
নাল ইউজারএক্সসেপশন

11
@ ক্যারম্যাক্সেল, তবুও উত্তরটি সম্পূর্ণ বিভ্রান্তিকর। অবশ্যই প্রশ্নটি উদ্ধৃতিগুলির মধ্যে থাকা সামগ্রীগুলি সম্পর্কে জিজ্ঞাসা করছে । "দর নেই" হয় না এই প্রশ্নের উত্তর।
পেসিয়ার

629

সংক্ষিপ্ত উত্তর হ্যাঁ, হ্যাঁ কাছাকাছি যাওয়ার উপায় আছেmysql_real_escape_string()

খুব অস্পষ্ট এজ এর জন্য !!!

দীর্ঘ উত্তর এত সহজ নয়। এটি এখানে প্রদর্শিত একটি আক্রমণ ভিত্তিক ।

আক্রমণ

সুতরাং, আসুন আক্রমণ দেখিয়ে শুরু করা যাক ...

mysql_query('SET NAMES gbk');
$var = mysql_real_escape_string("\xbf\x27 OR 1=1 /*");
mysql_query("SELECT * FROM test WHERE name = '$var' LIMIT 1");

নির্দিষ্ট পরিস্থিতিতে, এটি 1 সারির বেশি ফিরে আসবে। আসুন এখানে কী চলছে তা ছড়িয়ে দিন:

  1. একটি অক্ষর সেট নির্বাচন করা হচ্ছে

    mysql_query('SET NAMES gbk');

    কাজ এই আক্রমণ, আমরা এনকোডিং প্রয়োজন যে সার্ভারের উভয় সঙ্কেতাক্ষরে লিখা সংযোগে আশা 'হওয়া ASCII অর্থাত হিসেবে 0x27 এবং কিছু চরিত্র যার চূড়ান্ত বাইট একটি ASCII হয় আছে \অর্থাত 0x5c। এটি সক্রিয় আউট হিসাবে, 5 ধরনের ডিফল্টরূপে মাইএসকিউএল 5.6 সমর্থিত এনকোডিং আছেন: big5, cp932, gb2312, gbkএবং sjis। আমরা gbkএখানে নির্বাচন করব ।

    এখন, SET NAMESএখানে ব্যবহার নোট করা খুব গুরুত্বপূর্ণ । এই অক্ষর সেট সেট করে সার্ভারে । যদি আমরা সিপিআই ফাংশনে কলটি ব্যবহার করি তবে mysql_set_charset()আমরা ভাল হয়ে যাব (২০০ since সাল থেকে মাইএসকিউএল প্রকাশে)। তবে কেন এক মিনিটের মধ্যে আরও ...

  2. পে লোড

    আমরা এই ইঞ্জেকশনের জন্য যে পেডলোডটি ব্যবহার করতে যাচ্ছি তা বাইট সিকোয়েন্স দিয়ে শুরু হয় 0xbf27। ইন gbk, এটি একটি অবৈধ মাল্টিবাইট চরিত্র; ইন latin1, এটি স্ট্রিং ¿'। মনে রাখবেন যে, মধ্যে latin1 এবং gbk , 0x27তার নিজের একটি আক্ষরিক হয় 'অক্ষর।

    আমরা এই পে-লোডটি বেছে নিয়েছি কারণ, যদি আমরা addslashes()এটির আহ্বান করি তবে আমরা একটি এএসসিআইআই \অর্থাত অক্ষরের 0x5cআগে sert োকাতাম '। সুতরাং আমরা সাথে বয়ে যাব 0xbf5c27, যা gbkএকটি দুটি চরিত্রের ক্রম: এর 0xbf5cপরে 0x27। বা অন্য কথায়, একটি অবৈধ অক্ষর অনুসরণ করে একটি বৈধ অক্ষর '। কিন্তু আমরা ব্যবহার করছি না addslashes()। পরবর্তী পদক্ষেপে তাই ...

  3. mysql_real_escape_string ()

    সি এপিআই কলটি এর চেয়ে mysql_real_escape_string()পৃথক addslashes()হয় যা এটি সংযোগের অক্ষর সেটটি জানে। সুতরাং এটি সার্ভারের দ্বারা প্রত্যাশিত অক্ষর সেটটি ঠিকঠাকভাবে সম্পাদন করতে পারে। যাইহোক, এই মুহূর্ত পর্যন্ত, ক্লায়েন্ট মনে করে যে আমরা এখনও latin1সংযোগের জন্য ব্যবহার করছি , কারণ আমরা এটি অন্যথায় কখনও বলিনি। আমরা যে সার্ভারটি ব্যবহার করছি তা আমরা জানিয়েছি gbk, তবে ক্লায়েন্ট এখনও মনে করে এটি এটি latin1

    অতএব mysql_real_escape_string()ব্যাকস্ল্যাশ সন্নিবেশ করানোর জন্য কলটি , এবং 'আমাদের "পালানো" সামগ্রীতে আমাদের একটি বিনামূল্যে ঝুলন্ত চরিত্র রয়েছে! বস্তুত, যদি আমরা তাকান ছিল $varমধ্যে gbkঅক্ষর সেট, আমরা দেখতে চাই:

    OR 'বা 1 = 1 / *

    কোনটি ঠিক কি আক্রমণ প্রয়োজন।

  4. প্রশ্ন

    এই অংশটি কেবল একটি আনুষ্ঠানিকতা, তবে এখানে রেন্ডার্ড কোয়েরি রয়েছে:

    SELECT * FROM test WHERE name = '縗' OR 1=1 /*' LIMIT 1

অভিনন্দন, আপনি সবেমাত্র সফলভাবে একটি প্রোগ্রাম আক্রমণ করে mysql_real_escape_string()...

খারাপ জন

এটা খুব খারাপ হচ্ছে. মাইএসকিউএল সহ প্রস্তুত বিবৃতি অনুকরণেরPDO ডিফল্ট । এর অর্থ ক্লায়েন্টের পক্ষে এটি মূলত (সি লাইব্রেরিতে) একটি স্প্রিন্টফ করে , যার অর্থ নিম্নলিখিতগুলি সফল ইনজেকশনের ফলে আসবে:mysql_real_escape_string()

$pdo->query('SET NAMES gbk');
$stmt = $pdo->prepare('SELECT * FROM test WHERE name = ? LIMIT 1');
$stmt->execute(array("\xbf\x27 OR 1=1 /*"));

এখন, এটি লক্ষণীয় যে আপনি অনুকরণীয় প্রস্তুত বিবৃতি অক্ষম করে এটি প্রতিরোধ করতে পারেন:

$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

এটি সাধারণত একটি সত্য প্রস্তুত বিবৃতিতে (যেমন কোয়েরি থেকে পৃথক প্যাকেটে ডেটা প্রেরণ করা হবে) ফলাফল করে। যাইহোক, সচেতন থাকবেন PDO চুপটি হবে ফলব্যাক বিবৃতি এমুলেট যে মাইএসকিউএল স্থানীয়ভাবে প্রস্তুত পারে না: ঐ যে এটা করছে পারেন তালিকাভুক্ত ম্যানুয়াল কিন্তু উপযুক্ত সার্ভার সংস্করণ নির্বাচন করুন করার জন্য) হুঁশিয়ার।

কুৎসিত

আমি প্রথম দিকে বলেছিলাম যে আমরা যদি এর mysql_set_charset('gbk')পরিবর্তে ব্যবহার করে থাকি তবে আমরা এই সমস্ত কিছু রোধ করতে পারতাম SET NAMES gbk। এবং এটি সত্য যদি আপনি 2006 সাল থেকে একটি মাইএসকিউএল রিলিজ ব্যবহার করছেন true

আপনি আগের মাইএসকিউএল রিলিজ, তারপর একটি ব্যবহার করেন, তাহলে বাগ মধ্যে mysql_real_escape_string()অর্থ ছিল যেমন আমাদের পে লোড ঐ অবৈধ multibyte অক্ষর উদ্দেশ্যে পলায়নের জন্য একক বাইট পরিণত হওয়ার উপক্রম হয়েছিল এমনকি যদি ক্লায়েন্ট সঠিকভাবে সংযোগ এনকোডিং অবগত করা হয়েছে এবং তাই এই হামলা would এখনও সফল। বাগটি MySQL 4.1.20 , 5.0.22 এবং 5.1.11 এ স্থির করা হয়েছিল ।

তবে সবচেয়ে খারাপ দিকটি হ'ল 5.3.6 পর্যন্ত সিআইপি PDOপ্রকাশ করা হয়নি mysql_set_charset(), সুতরাং পূর্ববর্তী সংস্করণগুলিতে এটি প্রতিটি সম্ভাব্য কমান্ডের জন্য এই আক্রমণটিকে আটকাতে পারে না ! এটি এখন ডিএসএন প্যারামিটার হিসাবে উন্মুক্ত ।

সেভিং গ্রেস

যেমনটি আমরা শুরুতে বলেছি, এই আক্রমণটির জন্য ডাটাবেস সংযোগটি দুর্বল অক্ষর সেটটি ব্যবহার করে এনকোড করা আবশ্যক। utf8mb4হয় না প্রবন এখনো সমর্থন করতে পারে না এবং যে যাতে আপনি মাইএসকিউএল 5.5.3 থেকে উপলব্ধ পরিবর্তে-কিন্তু এটি শুধুমাত্র হয়েছে ব্যবহার করতে নির্বাচিত পারে: ইউনিকোড অক্ষর। একটি বিকল্প হ'ল utf8এটিও ঝুঁকিপূর্ণ নয় এবং পুরো ইউনিকোড বেসিক বহুভাষিক সমতলটিকে সমর্থন করতে পারে ।

বিকল্পভাবে, আপনি NO_BACKSLASH_ESCAPESএসকিউএল মোড সক্ষম করতে পারেন , যা (অন্যান্য জিনিসগুলির মধ্যে) এর ক্রিয়াকলাপকে পরিবর্তন করে mysql_real_escape_string()। এই মোডে সক্ষম থাকলে, 0x27সঙ্গে প্রতিস্থাপন করা হবে 0x2727বরং 0x5c27পলায়নের প্রক্রিয়া এবং এইভাবে করতে পারবে না প্রবন এনকোডিং যেখানে তারা পূর্বে উপস্থিত করেনি কোনো বৈধ অক্ষর তৈরি (যেমন 0xbf27এখনও 0xbf27ইত্যাদি।) - সার্ভার তাই এখনও অবৈধ হিসাবে স্ট্রিং প্রত্যাখ্যান করবে । তবে, এই এসকিউএল মোড ব্যবহার করে উত্থাপিত হতে পারে এমন একটি ভিন্ন দুর্বলতার জন্য @ eggyal এর উত্তর দেখুন

নিরাপদ উদাহরণ

নিম্নলিখিত উদাহরণগুলি নিরাপদ:

mysql_query('SET NAMES utf8');
$var = mysql_real_escape_string("\xbf\x27 OR 1=1 /*");
mysql_query("SELECT * FROM test WHERE name = '$var' LIMIT 1");

কারণ সার্ভারের প্রত্যাশা utf8...

mysql_set_charset('gbk');
$var = mysql_real_escape_string("\xbf\x27 OR 1=1 /*");
mysql_query("SELECT * FROM test WHERE name = '$var' LIMIT 1");

কারণ আমরা ঠিকমতো অক্ষর সেট করে রেখেছি তাই ক্লায়েন্ট এবং সার্ভারের মিল রয়েছে।

$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$pdo->query('SET NAMES gbk');
$stmt = $pdo->prepare('SELECT * FROM test WHERE name = ? LIMIT 1');
$stmt->execute(array("\xbf\x27 OR 1=1 /*"));

কারণ আমরা অনুকরণীয় প্রস্তুত বিবৃতি বন্ধ করেছি।

$pdo = new PDO('mysql:host=localhost;dbname=testdb;charset=gbk', $user, $password);
$stmt = $pdo->prepare('SELECT * FROM test WHERE name = ? LIMIT 1');
$stmt->execute(array("\xbf\x27 OR 1=1 /*"));

কারণ আমরা চরিত্রটি সঠিকভাবে সেট করেছি।

$mysqli->query('SET NAMES gbk');
$stmt = $mysqli->prepare('SELECT * FROM test WHERE name = ? LIMIT 1');
$param = "\xbf\x27 OR 1=1 /*";
$stmt->bind_param('s', $param);
$stmt->execute();

কারণ মাইএসকিউএলআই সমস্ত সময় সত্য প্রস্তুত বিবৃতি দেয়।

মোড়ক উম্মচন

আপনি যদি:

  • মাইএসকিউএল এর আধুনিক সংস্করণগুলি (5.1, 5.6, ইত্যাদির শেষের দিকে 5.1) এবং mysql_set_charset() / $mysqli->set_charset()/ পিডিওর ডিএসএন চরসেট প্যারামিটার (পিএইচপি ≥ 5.3.6 এ) ব্যবহার করুন

অথবা

  • সংযোগ এনকোডিংয়ের জন্য দুর্বল অক্ষর সেট ব্যবহার করবেন না (আপনি কেবল utf8/ latin1/ ascii/ ইত্যাদি ব্যবহার করেন )

আপনি 100% নিরাপদ

অন্যথায়, আপনি ব্যবহার করা সত্ত্বেও আপনিmysql_real_escape_string() দুর্বল হন ...


3
পিডিও এমসকিউএল-এর জন্য বিবৃতি প্রস্তুত করার অনুকরণ করছে, সত্যিই? ড্রাইভার এটি দেশীয়ভাবে সমর্থন করে যেহেতু এটি করার কোনও কারণ আমি দেখতে পাচ্ছি না। কোন?
নেটকোডার

16
এটা করে. তারা ডকুমেন্টেশনে বলে যে এটি হয় না। তবে সোর্স কোডে এটি স্পষ্টভাবে দৃশ্যমান এবং ঠিক করা সহজ। আমি এটি ডেভসদের অক্ষমতা পর্যন্ত চক করছি।
থিওডোর আর স্মিথ

5
@ থিওডোরআর.স্মিত: এটি ঠিক করা এত সহজ নয়। আমি ডিফল্ট পরিবর্তন করার জন্য কাজ করছি, তবে এটি স্যুইচ করা হলে পরীক্ষার একটি নৌকা বোঝা ব্যর্থ করে। সুতরাং এটি এটির চেয়ে বড় পরিবর্তন। আমি এখনও আশা করছি 5.5 ... এর মধ্যে এটি শেষ হয়ে গেছে ...
একারম্যাক্সেল

14
@ শাডিয়াক্স: না, নিবন্ধটি বর্ণিত দুর্বলতার বিষয়ে addslashes। আমি এই দুর্বলতাটিকে সেই ভিত্তিতে তৈরি করেছি । এটি নিজে চেষ্টা করো. মাইএসকিউএল 5.0 পান, এবং এই শোষণ চালান এবং নিজের জন্য দেখুন। এটিকে পুট / জিইটি / পোস্টে কীভাবে রাখা যায়, এটি আজীবন। ইনপুট ডেটা কেবল বাইট স্ট্রিম। char(0xBF)বাইট তৈরির কেবল পঠনযোগ্য উপায়। আমি একাধিক সম্মেলনের সামনে এই দুর্বলতাটিকে সরাসরি উপভোগ করেছি। আমার উপর এটি বিশ্বাস করুন ... তবে আপনি যদি তা না করেন তবে নিজে চেষ্টা করে দেখুন। এটি কাজ করে ...
ircmaxell

5
@ শ্যাডিয়াক্স: ?var=%BF%27+OR+1=1+%2F%2Aইউআরএল, $var = $_GET['var'];কোডে, এবং বব আপনার চাচায় G _GET ... তে এই মজাদার ঘটনাটি পাস করার জন্য ।
সিএইচও

183

টি এল; ডিআর

mysql_real_escape_string()যদি কোনও সুরক্ষা সরবরাহ না করে (এবং তদ্ব্যতীত আপনার ডেটাটি ছত্রভঙ্গ করতে পারে) যদি:

  • মাইএসকিউএল এর NO_BACKSLASH_ESCAPESএসকিউএল মোড সক্ষম করা হয়েছে (যা এটি হতে পারে, যতক্ষণ না আপনি স্পষ্টভাবে প্রতিবার সংযোগ করার সময় অন্য এসকিউএল মোড নির্বাচন করেন ); এবং

  • আপনার এসকিউএল স্ট্রিং লিটারেলগুলি ডাবল-উদ্ধৃতি "অক্ষর ব্যবহার করে উদ্ধৃত করা হয়েছে ।

এটি বাগ # 72458 হিসাবে দায়ের করা হয়েছিল এবং এটি মাইএসকিউএল v5.7.6 এ ঠিক করা হয়েছে ( নীচে " দ্য সেভিং গ্রেস " শীর্ষক বিভাগটি দেখুন)।

এটি আর একটি, (সম্ভবত কম?) অস্পষ্ট এজ এজ CASE !!!

@ আর্কম্যাক্সেলের দুর্দান্ত উত্তরে শ্রদ্ধা জানাতে (সত্যই, এটি চাটুকারিতা বলে মনে করা হয় এবং চুরির কথা নয়!), আমি তার ফর্ম্যাটটি গ্রহণ করব:

আক্রমণ

একটি বিক্ষোভ দিয়ে শুরু হচ্ছে ...

mysql_query('SET SQL_MODE="NO_BACKSLASH_ESCAPES"'); // could already be set
$var = mysql_real_escape_string('" OR 1=1 -- ');
mysql_query('SELECT * FROM test WHERE name = "'.$var.'" LIMIT 1');

এটি testটেবিল থেকে সমস্ত রেকর্ড ফিরিয়ে দেবে । একটি বিচ্ছেদ:

  1. একটি এসকিউএল মোড নির্বাচন করা হচ্ছে

    mysql_query('SET SQL_MODE="NO_BACKSLASH_ESCAPES"');

    স্ট্রিং লিটারালসের অধীনে নথিভুক্ত হিসাবে :

    স্ট্রিংয়ের মধ্যে উদ্ধৃতি অক্ষর অন্তর্ভুক্ত করার বিভিন্ন উপায় রয়েছে:

    • একটি " '" সাথে উদ্ধৃত একটি স্ট্রিংয়ের ভিতরে " '" হিসাবে লেখা যেতে পারে ''

    • একটি " "" সাথে উদ্ধৃত একটি স্ট্রিংয়ের ভিতরে " "" হিসাবে লেখা যেতে পারে ""

    • একটি অব্যাহতি অক্ষর দ্বারা উদ্ধৃতি অক্ষর আগে (" \")।

    • " '" দিয়ে উদ্ধৃত একটি স্ট্রিংয়ের ভিতরে একটি " "" বিশেষ চিকিত্সা প্রয়োজন এবং দ্বিগুণ বা পালাতে হবে না। একইভাবে, " "" দিয়ে উদ্ধৃত একটি স্ট্রিংয়ের অভ্যন্তরে 'কোনও বিশেষ চিকিত্সার প্রয়োজন নেই।

    যদি সার্ভারের এসকিউএল মোড অন্তর্ভুক্ত থাকে NO_BACKSLASH_ESCAPES, তবে এই বিকল্পগুলির মধ্যে তৃতীয়টি — যা সাধারণ পদ্ধতি অবলম্বন করে mysql_real_escape_string()—এটি উপলভ্য নয়: পরিবর্তে প্রথম দুটি বিকল্পের মধ্যে একটি ব্যবহার করা আবশ্যক। নোট করুন যে চতুর্থ বুলেটটির প্রভাবটি হ'ল যে কারও ডেটা মংগিং এড়ানোর জন্য আক্ষরিক উদ্ধৃতি হিসাবে ব্যবহৃত হবে এমন চরিত্রটি অবশ্যই জানা উচিত।

  2. পে লোড

    " OR 1=1 -- 

    পে-লোড "চরিত্রের সাথে এই ইনজেকশনটি বেশ আক্ষরিক অর্থে শুরু করে । কোনও নির্দিষ্ট এনকোডিং নেই। কোনও বিশেষ অক্ষর নেই। কোনও অদ্ভুত বাইট নেই।

  3. mysql_real_escape_string ()

    $var = mysql_real_escape_string('" OR 1=1 -- ');

    ভাগ্যক্রমে, mysql_real_escape_string()এসকিউএল মোডটি পরীক্ষা করে এবং সে অনুযায়ী তার আচরণটি সামঞ্জস্য করে। দেখুন libmysql.c:

    ulong STDCALL
    mysql_real_escape_string(MYSQL *mysql, char *to,const char *from,
                 ulong length)
    {
      if (mysql->server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES)
        return escape_quotes_for_mysql(mysql->charset, to, 0, from, length);
      return escape_string_for_mysql(mysql->charset, to, 0, from, length);
    }
    

    সুতরাং এসকিউএল মোড ব্যবহার escape_quotes_for_mysql()করা হয়, একটি ভিন্ন অন্তর্নিহিত ফাংশন,, ডাকে NO_BACKSLASH_ESCAPES। উপরে উল্লিখিত হিসাবে, এই জাতীয় ক্রিয়াকলাপটি এটি জানতে হবে যে অন্য বর্ণনামূলক অক্ষরকে আক্ষরিকভাবে পুনরাবৃত্তি না করেই পুনরুক্ত করতে কোন অক্ষরটি আক্ষরিক উদ্ধৃতিতে ব্যবহৃত হবে।

    তবে এই ফাংশনটি নির্বিচারে ধরে নিয়েছে যে একক-উদ্ধৃতি 'অক্ষর ব্যবহার করে স্ট্রিংটি উদ্ধৃত করা হবে । দেখুন charset.c:

    /*
      Escape apostrophes by doubling them up
    
    // [ deletia 839-845 ]
    
      DESCRIPTION
        This escapes the contents of a string by doubling up any apostrophes that
        it contains. This is used when the NO_BACKSLASH_ESCAPES SQL_MODE is in
        effect on the server.
    
    // [ deletia 852-858 ]
    */
    
    size_t escape_quotes_for_mysql(CHARSET_INFO *charset_info,
                                   char *to, size_t to_length,
                                   const char *from, size_t length)
    {
    // [ deletia 865-892 ]
    
        if (*from == '\'')
        {
          if (to + 2 > to_end)
          {
            overflow= TRUE;
            break;
          }
          *to++= '\'';
          *to++= '\'';
        }
    

    সুতরাং, এটি আক্ষরিক উদ্ধৃতিতে ব্যবহৃত প্রকৃত চরিত্র নির্বিশেষে ডাবল-কোট "অক্ষরগুলি (এবং সমস্ত একক-উদ্ধৃতি 'অক্ষরের দ্বিগুণ ) ছেড়ে দেয় ! আমাদের যদি $varদেহাবশেষ যুক্তি হল যে প্রদান করা হয় ঠিক একই mysql_real_escape_string()-এটা যেন কোন পলায়নের জায়গা নিয়েছে এ সব

  4. প্রশ্ন

    mysql_query('SELECT * FROM test WHERE name = "'.$var.'" LIMIT 1');

    আনুষ্ঠানিকতার কিছু, রেন্ডার্ড ক্যোয়ারীটি হ'ল:

    SELECT * FROM test WHERE name = "" OR 1=1 -- " LIMIT 1

আমার শিক্ষিত বন্ধু যেমনটি বলেছে: অভিনন্দন, আপনি কেবলমাত্র সফলভাবে একটি প্রোগ্রাম ব্যবহার করে আক্রমণ mysql_real_escape_string()...

খারাপ জন

mysql_set_charset()সাহায্য করতে পারে না, কারণ চরিত্রের সেটগুলির সাথে এর কোনও যোগসূত্র নেই; না পারে mysqli::real_escape_string(), যেহেতু এটি এই একই ফাংশনটির চারপাশে কেবল একটি আলাদা র‍্যাপার।

সমস্যাটি যদি ইতিমধ্যে সুস্পষ্ট না হয় তবে তা হ'ল আক্ষরিক অর্থে কোন চরিত্রটি উদ্ধৃত হবে mysql_real_escape_string() তা কলটি জানতে পারে না , কারণ এটি পরবর্তী সময়ে সিদ্ধান্ত নিতে বিকাশকারীকে রেখে গেছে left সুতরাং, NO_BACKSLASH_ESCAPESমোডে, আক্ষরিকভাবে কোনও উপায় নেই যে এই ফাংশনটি নিরাপদে উদ্ধৃতি দিয়ে ব্যবহারের জন্য প্রতিটি ইনপুট নিরাপদে রক্ষা করতে পারে (কমপক্ষে, দ্বিগুণ হওয়া অক্ষরগুলির দ্বিগুণ না করে এবং এইভাবে আপনার ডেটা মংগ করা ছাড়াই নয়)।

কুৎসিত

এটা খুব খারাপ হচ্ছে. NO_BACKSLASH_ESCAPESস্ট্যান্ডার্ড এসকিউএল এর সাথে সামঞ্জস্যের জন্য প্রয়োজনীয়তার প্রয়োজনীয়তার কারণে বন্যের মধ্যে এটি অসাধারণ কিছু নাও হতে পারে (যেমন এসকিউএল -২২ স্পেসিফিকেশনের অংশ 5.3 দেখুন , যথা <quote symbol> ::= <quote><quote>ব্যাকরণ উত্পাদন এবং ব্যাকস্ল্যাশকে দেওয়া কোনও বিশেষ অর্থের অভাব)। তদ্ব্যতীত, এর ব্যবহারটি স্পষ্টভাবে ওয়ার্কআউন্ড হিসাবে সুপারিশ করা হয়েছিল (দীর্ঘকাল থেকে স্থির) বাগ যা আইর্কমেক্সেলের পোস্ট বর্ণনা করে। কে জানে, কিছু ডিবিএ এমনকি ডিফল্টরূপে এটির মতো ভুল পালানোর পদ্ধতির ব্যবহারকে নিরুৎসাহিত করার জন্য কনফিগারও করতে পারে addslashes()

এছাড়াও, একটি নতুন সংযোগের এসকিউএল মোডটি সার্ভারের দ্বারা এটির কনফিগারেশন অনুসারে সেট করা হয়েছে (যা কোনও SUPERব্যবহারকারী যে কোনও সময় পরিবর্তন করতে পারে); সুতরাং, সার্ভারের আচরণ সম্পর্কে নিশ্চিত হওয়ার জন্য আপনাকে সংযুক্ত হওয়ার পরে সর্বদা স্পষ্টভাবে আপনার কাঙ্ক্ষিত মোডটি নির্দিষ্ট করতে হবে ।

সেভিং গ্রেস

এতক্ষণ আপনি যতক্ষণ না স্পষ্টভাবে এসকিউএল মোডটি অন্তর্ভুক্ত না করে NO_BACKSLASH_ESCAPESবা একক-উদ্ধৃতি অক্ষর ব্যবহার করে মাইএসকিউএল স্ট্রিং লিটারেলগুলি উদ্ধৃত করেন, এই বাগটি তার কুরুচিপূর্ণ মাথাটি পিছন করতে পারে না: যথাক্রমে escape_quotes_for_mysql()ব্যবহার করা হবে না, বা কোট অক্ষরের পুনরাবৃত্তি প্রয়োজন হবে এমন ধারণা সঠিক হতে

এই কারণে, আমি প্রস্তাব দিচ্ছি যে যে কেউ ব্যবহার করে NO_BACKSLASH_ESCAPESতা ANSI_QUOTESমোড সক্ষম করে, কারণ এটি একক-উদ্ধৃত স্ট্রিং লিটারালগুলির অভ্যাসগত ব্যবহারকে বাধ্য করবে। মনে রাখবেন যে ডাবল-কোটড লিটারেলগুলি ব্যবহৃত হওয়ার ঘটনায় এটি এসকিউএল ইঞ্জেকশনটিকে বাধা দেয় না — এটি কেবল ঘটনার সম্ভাবনা হ্রাস করে (কারণ স্বাভাবিক, দূষিত প্রশ্নগুলি ব্যর্থ হবে)।

পিডিওতে, এটির সমতুল্য কার্যকারিতা PDO::quote()এবং এর প্রস্তুত বিবৃতি এমুলেটর উভয়ই mysql_handle_quoter()- যা ঠিক এটি করে: এটি নিশ্চিত করে যে পালানো আক্ষরিকটি একক-কোটায় উদ্ধৃত হয়েছে, সুতরাং আপনি নিশ্চিত হতে পারেন যে পিডিও সর্বদা এই বাগ থেকে প্রতিরোধক থাকে।

মাইএসকিউএল ভি 5.7.6 হিসাবে, এই বাগটি ঠিক করা হয়েছে। পরিবর্তন লগ দেখুন :

কার্যকারিতা যুক্ত বা পরিবর্তিত

  • অসামঞ্জস্য পরিবর্তন: একটি নতুন সি এপিআই ফাংশন, এরmysql_real_escape_string_quote()প্রতিস্থাপন হিসাবে কার্যকর করা হয়েছেmysql_real_escape_string()কারণNO_BACKSLASH_ESCAPESএসকিউএল মোড সক্ষম থাকলেউত্তরোক্ত ফাংশনটি অক্ষরগুলিকে সঠিকভাবে এনকোড করতে ব্যর্থ হতে পারে। এই ক্ষেত্রে,mysql_real_escape_string()উদ্ধৃতি অক্ষরগুলি দ্বিগুণ না করে এড়াতে পারবেন না এবং এটি সঠিকভাবে করতে, অবশ্যই উদ্ধৃতি প্রসঙ্গে উপলব্ধের চেয়ে আরও তথ্য জানতে হবে। mysql_real_escape_string_quote()উদ্ধৃতি প্রসঙ্গে নির্দিষ্ট করার জন্য একটি অতিরিক্ত যুক্তি লাগে। ব্যবহারের বিশদগুলির জন্য, mysql_real_escape_string_quote () দেখুন

     বিঃদ্রঃ

    অ্যাপ্লিকেশনগুলির mysql_real_escape_string_quote()পরিবর্তে অ্যাপ্লিকেশনগুলি ব্যবহার করতে হবে , mysql_real_escape_string()যা এখন ব্যর্থ হয় এবং সক্ষম করা থাকলে একটি CR_INSECURE_API_ERRত্রুটি তৈরি করে NO_BACKSLASH_ESCAPES

    তথ্যসূত্র: বাগ # 19211994 এছাড়াও দেখুন।

নিরাপদ উদাহরণ

আইক্রিমেক্সেল দ্বারা ব্যাখ্যা করা বাগের সাথে একসাথে নেওয়া, নিম্নলিখিত উদাহরণগুলি সম্পূর্ণ নিরাপদ (ধরে নিলেন যে কেউ হয় 4.1.20, 5.0.22, 5.1.11 এর পরে মাইএসকিউএল ব্যবহার করছে; বা এটি কোনও জিবিকে / বিগ 5 সংযোগ এনকোডিং ব্যবহার করছে না) :

mysql_set_charset($charset);
mysql_query("SET SQL_MODE=''");
$var = mysql_real_escape_string('" OR 1=1 /*');
mysql_query('SELECT * FROM test WHERE name = "'.$var.'" LIMIT 1');

... কারণ আমরা স্পষ্টভাবে একটি এসকিউএল মোড নির্বাচন করেছি যা এতে অন্তর্ভুক্ত নয় NO_BACKSLASH_ESCAPES

mysql_set_charset($charset);
$var = mysql_real_escape_string("' OR 1=1 /*");
mysql_query("SELECT * FROM test WHERE name = '$var' LIMIT 1");

... কারণ আমরা একক উদ্ধৃতি দিয়ে আমাদের স্ট্রিংকে আক্ষরিক উদ্ধৃতি দিচ্ছি।

$stmt = $pdo->prepare('SELECT * FROM test WHERE name = ? LIMIT 1');
$stmt->execute(["' OR 1=1 /*"]);

... কারণ পিডিও-র তৈরি বিবৃতিগুলি এই দুর্বলতা থেকে রক্ষা পেয়েছে (এবং আইক্রিমেক্সেলেরও এটি সরবরাহ করা হয়েছে যে আপনি PHP≥5.3.6 ব্যবহার করছেন এবং অক্ষর সেটটি ডিএসএন-তে সঠিকভাবে সেট করা হয়েছে; বা প্রস্তুত বিবৃতি ইমুলেশন অক্ষম করা হয়েছে) ।

$var  = $pdo->quote("' OR 1=1 /*");
$stmt = $pdo->query("SELECT * FROM test WHERE name = $var LIMIT 1");

... কারণ PDO এর quote()কার্যকারিতা কেবল আক্ষরিক থেকে অব্যাহতি পায় না, তবে এটি উদ্ধৃত করে (একক-উদ্ধৃতি 'অক্ষরে); নোট করুন যে এক্ষেত্রে আর্কম্যাক্সেলের বাগ এড়াতে আপনার অবশ্যই পিএইচপি -5.3.6 ব্যবহার করা উচিত এবং ডিএসএন -তে অক্ষর সেটটি সঠিকভাবে সেট করা উচিত

$stmt = $mysqli->prepare('SELECT * FROM test WHERE name = ? LIMIT 1');
$param = "' OR 1=1 /*";
$stmt->bind_param('s', $param);
$stmt->execute();

... কারণ মাইএসকিউএলআই প্রস্তুত বিবৃতি নিরাপদ।

মোড়ক উম্মচন

আপনি যদি:

  • নেটিভ প্রস্তুত বিবৃতি ব্যবহার করুন

অথবা

  • MySQL v5.7.6 বা তার পরে ব্যবহার করুন use

অথবা

  • মধ্যে উপরন্তু অন্তত এক ircmaxell এর সংক্ষেপে বলা সমাধান এক, ব্যবহার নিযুক্ত করুন:

    • PDO;
    • একক-উদ্ধৃত স্ট্রিং আক্ষরিক; অথবা
    • একটি স্পষ্টভাবে সেট এসকিউএল মোড যা অন্তর্ভুক্ত নয় NO_BACKSLASH_ESCAPES

... তাহলে আপনার পুরোপুরি নিরাপদ হওয়া উচিত (স্ট্রিংয়ের পরিধি বাইরে দূরে থাকা দুর্বলতা)।


10
সুতরাং, টিএল; ডিআর এর মত হবে "এমন কোনও NO_BACKSLASH_ESCAPES মাইএসকিএল সার্ভার মোড রয়েছে যা যদি আপনি একক উদ্ধৃতি ব্যবহার না করেন তবে ইনজেকশন ঘটতে পারে
আপনার সাধারণ সংবেদন

আমি bugs.mysql.com/bug.php?id=72458 অ্যাক্সেস করতে পারছি না ; আমি কেবল একটি অ্যাক্সেস অস্বীকৃত পৃষ্ঠা পেয়েছি। সুরক্ষা সমস্যা হওয়ার কারণে এটি কি জনসাধারণের কাছ থেকে লুকানো হচ্ছে? এছাড়াও, আমি কি এই উত্তর থেকে সঠিকভাবে বুঝতে পারি যে আপনি দুর্বলতার আবিষ্কারক? যদি তাই হয়, অভিনন্দন।
মার্ক আমেরিকা

1
লোকেরা "প্রথমে স্ট্রিংয়ের জন্য ব্যবহার করা উচিত নয় । এসকিউএল এটি শনাক্তকারীদের জন্য বলে। তবে এঁই ... মাইএসকিউএল এর অন্য একটি উদাহরণ যা "স্ক্রু স্ট্যান্ডার্ডস, আমি যা চাই তা করব"। (সৌভাগ্যবসত, আপনি অন্তর্ভুক্ত করতে পারে ANSI_QUOTESমোডে উদ্ধৃত brokenness ফিক্স, মান খোলা উপেক্ষা যদিও, একটি বড় ইস্যু আরো গুরুতর ব্যবস্থা প্রয়োজন হতে পারে হয়।।)
Chao

2
@ ড্যান অ্যালেন: আমার উত্তরটি কিছুটা বিস্তৃত ছিল, যাতে আপনি পিডির কার্যক্রমে এই বিশেষ বাগটি এড়াতে পারবেন - তবে সাধারণত ইনজেকশন এড়াতে প্রস্তুত বিবৃতিগুলি আরও নিরাপদ এবং আরও উপযুক্ত উপায়। অবশ্যই, যদি আপনি সরাসরি আপনার এসকিউএল-এ অনস্কেপড ভেরিয়েবলগুলি কনটেনটেটেড করে থাকেন তবে আপনি পরে কোনও পদ্ধতি ব্যবহার না করেই আপনি অবশ্যই ইনজেকশনের ঝুঁকির মধ্যে পড়ে যাবেন। quote()
উদ্বিগ্ন

1
@ ইগজিএল: আমাদের সিস্টেম উপরের ২ য় নিরাপদ উদাহরণের উপর নির্ভর করে। ত্রুটি রয়েছে, যেখানে mysql_real_escape_string বাদ দেওয়া হয়েছে। জরুরী অবস্থার মধ্যে ফিক্সিং করা বুদ্ধিমানের পথ বলে মনে হয়, আশা করি আমরা সংশোধনের আগেই ডেকে আছি না। আমার যুক্তি প্রস্তুত বিবৃতিতে রূপান্তরিত করা অনেক দীর্ঘ প্রক্রিয়া হবে যা পরে আসতে হবে। প্রস্তুত বিবৃতি কি ত্রুটিগুলি দুর্বলতা তৈরি করে না এই বিষয়টি কি নিরাপদ? অন্য কথায়, উপরের ২ য় উদাহরণটি সঠিকভাবে প্রয়োগ করা হয়েছে কীভাবে প্রস্তুত বিবৃতি হিসাবে নিরাপদ?
ড্যানএলেন

18

ওয়েল, %ওয়াইল্ডকার্ড ব্যতীত এমন কিছু যা সত্যিকার অর্থেই পার হয়ে যায় । এটি LIKEআক্রমণাত্মক হতে পারে যদি আপনি আক্রমণাত্মক বক্তব্যটি ব্যবহার করছিলেন কারণ %আপনি যদি এটিকে ফিল্টার না করেন তবে কেবল লগইন করা যেতে পারে এবং আপনার ব্যবহারকারীর যে কোনও একটি পাসওয়ার্ডের জন্য কেবল আঘাতের প্রয়োজন হবে। লোকেরা প্রায়শই এটি 100% সুরক্ষিত করার জন্য প্রস্তুত বিবৃতি ব্যবহার করার পরামর্শ দেয় কারণ ডেটা সেইভাবে ক্যোয়ারিতে হস্তক্ষেপ করতে পারে না। তবে এই জাতীয় সাধারণ প্রশ্নের জন্য সম্ভবত এমন কিছু করা আরও দক্ষ হবে$login = preg_replace('/[^a-zA-Z0-9_]/', '', $login);


2
+1, তবে ওয়াইল্ডকার্ডগুলি সাধারণ সাম্যের জন্য নয়, লাইক ক্লজের জন্য।
ডোর

7
আপনি কোন পরিমাপের দ্বারা more efficientপ্রস্তুত বিবৃতি ব্যবহারের চেয়ে সাধারণ প্রতিস্থাপন বিবেচনা করেন ? (প্রস্তুত বিবৃতি সর্বদা কাজ করে, আক্রমণগুলির ক্ষেত্রে গ্রন্থাগারটি দ্রুত সংশোধন করা যায়, মানুষের ত্রুটিটি প্রকাশ করে না [যেমন সম্পূর্ণ প্রতিস্থাপনের স্ট্রিংটি ভুল টাইপ করে], এবং বিবৃতিটি পুনরায় ব্যবহার করা হলে উল্লেখযোগ্য পারফরম্যান্স সুবিধা রয়েছে।)
ম্যাটবাইলি

7
@ স্লাভা: আপনি কার্যকরভাবে ব্যবহারকারীর নাম এবং পাসওয়ার্ড কেবল শব্দচরিত্রে সীমাবদ্ধ করছেন। সুরক্ষা সম্পর্কে কিছু জানেন এমন বেশিরভাগ লোকেরা এটি একটি খারাপ ধারণা হিসাবে বিবেচনা করবেন, কারণ এটি অনুসন্ধানের স্থানটিকে যথেষ্ট সংকুচিত করে। কোর্সটি তারা ডেটাবেজে ক্লিয়ারটেক্সট পাসওয়ার্ডগুলি সংরক্ষণ করার পক্ষে একটি খারাপ ধারণাও মনে করবে, তবে আমাদের সমস্যাটি আরও বাড়ানোর দরকার নেই don't :)
সিএওও

2
@ সিএইচও, আমার পরামর্শটি কেবল লগইন নিয়ে উদ্বেগ প্রকাশ করে। স্পষ্টতই আপনার পাসওয়ার্ড ফিল্টার করার দরকার নেই, দুঃখিত এটি আমার উত্তরটিতে পরিষ্কারভাবে বলা হয়নি। তবে আসলে এটি ভাল ধারণা হতে পারে। "পাথর অজানা গাছের জায়গা" ব্যবহার করে হার্ড-টু-স্মরণ এবং প্রকারের "a4üua3! @V \" ä90; 8f "এর পরিবর্তে ব্রুটফোর্স করা আরও শক্ত হবে Even এমনকি একটি অভিধান ব্যবহার করেও আপনাকে 3000 শব্দের কথা বলুন, জানার জন্য আপনি ঠিক 4 টি শব্দ ব্যবহার করেছেন - এটি এখনও প্রায় 3.3 * 10 ^ 12 সংমিশ্রণ হতে পারে :) :)
স্লাভা

2
@ স্লাভা: আমি আগে এই ধারণাটি দেখেছি; দেখতে xkcd.com/936 । সমস্যাটি হচ্ছে, অঙ্কটি একে একে যথেষ্ট সহ্য করে না। আপনার উদাহরণের 17-চর পাসওয়ার্ডটিতে 96 ^ 17 টির মতো সম্ভাবনা থাকবে এবং আপনি যদি উমলাতকে ভুলে যান এবং নিজেকে মুদ্রণযোগ্য ASCII- এ সীমাবদ্ধ রাখেন। এটি প্রায় 4.5x10 ^ 33। আমরা আক্ষরিক অর্থে কথা বলছি একশো কোটি ট্রিলিয়ন গুণ বেশি কাজ করার জন্য নিষ্ঠুর শক্তি এমনকি একটি 8-চর ASCII পাসওয়ার্ডে 7.2x10 ^ 15 সম্ভাবনা থাকবে - 3 হাজার গুণ বেশি।
সিএইচও
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.