OWASP বিভাগ: MASVS-CODE: কোড গুণমান
ওভারভিউ
এসকিউএল ইনজেকশন তাদের ইচ্ছাকৃতভাবে প্রকাশ করা ইন্টারফেসের বাইরে অন্তর্নিহিত ডাটাবেস অ্যাক্সেস করতে এসকিউএল স্টেটমেন্টে কোড ঢোকানোর মাধ্যমে দুর্বল অ্যাপ্লিকেশনগুলিকে শোষণ করে। আক্রমণটি ব্যক্তিগত ডেটা, দুর্নীতিগ্রস্ত ডাটাবেস বিষয়বস্তু এবং এমনকি ব্যাকএন্ড অবকাঠামোর সাথে আপস করতে পারে।
এসকিউএল এক্সিকিউশনের আগে ব্যবহারকারীর ইনপুট সংযুক্ত করে গতিশীলভাবে তৈরি করা প্রশ্নের মাধ্যমে ইনজেকশনের জন্য ঝুঁকিপূর্ণ হতে পারে। ওয়েব, মোবাইল এবং যেকোনো এসকিউএল ডাটাবেস অ্যাপ্লিকেশনকে লক্ষ্য করে, এসকিউএল ইনজেকশন সাধারণত OWASP শীর্ষ দশের ওয়েব দুর্বলতার মধ্যে থাকে। আক্রমণকারীরা বেশ কয়েকটি হাই-প্রোফাইল লঙ্ঘনে এই কৌশলটি ব্যবহার করেছিল।
এই মৌলিক উদাহরণে, একটি অর্ডার নম্বর বক্সে একজন ব্যবহারকারীর দ্বারা একটি আনস্কেপড ইনপুট SQL স্ট্রিং-এ ঢোকানো যেতে পারে এবং নিম্নলিখিত ক্যোয়ারী হিসাবে ব্যাখ্যা করা যেতে পারে:
SELECT * FROM users WHERE email = 'example@example.com' AND order_number = '251542'' LIMIT 1
এই ধরনের কোড একটি ওয়েব কনসোলে একটি ডাটাবেস সিনট্যাক্স ত্রুটি তৈরি করবে, যা দেখায় যে অ্যাপ্লিকেশনটি SQL ইনজেকশনের জন্য দুর্বল হতে পারে। 'OR 1=1–
দিয়ে অর্ডার নম্বর প্রতিস্থাপন করার অর্থ হল প্রমাণীকরণ অর্জন করা যেতে পারে যেহেতু ডাটাবেস বিবৃতিটিকে True
তে মূল্যায়ন করে, কারণ একটি সর্বদা একটির সমান।
একইভাবে, এই ক্যোয়ারীটি একটি টেবিল থেকে সমস্ত সারি ফেরত দেয়:
SELECT * FROM purchases WHERE email='admin@app.com' OR 1=1;
বিষয়বস্তু প্রদানকারী
বিষয়বস্তু প্রদানকারীরা একটি স্ট্রাকচার্ড স্টোরেজ মেকানিজম অফার করে যা একটি অ্যাপ্লিকেশনের মধ্যে সীমাবদ্ধ বা অন্য অ্যাপের সাথে শেয়ার করার জন্য এক্সপোর্ট করা যেতে পারে। অনুমতি ন্যূনতম বিশেষাধিকার নীতির উপর ভিত্তি করে সেট করা উচিত; একটি রপ্তানিকৃত ContentProvider
পড়া এবং লেখার জন্য একটি নির্দিষ্ট অনুমতি থাকতে পারে।
এটা লক্ষণীয় যে সমস্ত SQL ইনজেকশন শোষণের দিকে পরিচালিত করে না। কিছু বিষয়বস্তু প্রদানকারী ইতিমধ্যেই পাঠকদের SQLite ডাটাবেসে সম্পূর্ণ অ্যাক্সেস প্রদান করে; নির্বিচারে প্রশ্নগুলি সম্পাদন করতে সক্ষম হওয়া সামান্য সুবিধা দেয়। একটি নিরাপত্তা সমস্যা প্রতিনিধিত্ব করতে পারে যে নিদর্শন অন্তর্ভুক্ত:
- একাধিক বিষয়বস্তু প্রদানকারী একটি একক SQLite ডাটাবেস ফাইল ভাগ করে।
- এই ক্ষেত্রে, প্রতিটি টেবিল একটি অনন্য সামগ্রী প্রদানকারীর উদ্দেশ্যে হতে পারে। একটি বিষয়বস্তু প্রদানকারীর একটি সফল এসকিউএল ইনজেকশন অন্য কোনো টেবিলে অ্যাক্সেস মঞ্জুর করবে।
- একটি বিষয়বস্তু প্রদানকারীর একই ডাটাবেসের মধ্যে সামগ্রীর জন্য একাধিক অনুমতি রয়েছে।
- একটি একক বিষয়বস্তু প্রদানকারীর মধ্যে SQL ইনজেকশন যা বিভিন্ন অনুমতি স্তরের সাথে অ্যাক্সেস মঞ্জুর করে তা নিরাপত্তা বা গোপনীয়তা সেটিংসের স্থানীয় বাইপাস হতে পারে।
প্রভাব
এসকিউএল ইনজেকশন সংবেদনশীল ব্যবহারকারী বা অ্যাপ্লিকেশন ডেটা প্রকাশ করতে পারে, প্রমাণীকরণ এবং অনুমোদনের সীমাবদ্ধতাগুলি অতিক্রম করতে পারে এবং ডেটাবেসগুলিকে দুর্নীতি বা মুছে ফেলার জন্য ঝুঁকিপূর্ণ রাখতে পারে। প্রভাবের মধ্যে এমন ব্যবহারকারীদের জন্য বিপজ্জনক এবং দীর্ঘস্থায়ী প্রভাব থাকতে পারে যাদের ব্যক্তিগত ডেটা প্রকাশ করা হয়েছে। অ্যাপ এবং পরিষেবা প্রদানকারীরা মেধা সম্পত্তি বা ব্যবহারকারীর বিশ্বাস হারানোর ঝুঁকি নেয়।
প্রশমন
প্রতিস্থাপনযোগ্য পরামিতি
ব্যবহার করছেন ?
সিলেকশন ক্লজ এবং সিলেকশন আর্গুমেন্টের একটি পৃথক অ্যারে একটি পরিবর্তনযোগ্য প্যারামিটার হিসেবে ব্যবহারকারীর ইনপুটকে SQL স্টেটমেন্টের অংশ হিসেবে ব্যাখ্যা করার পরিবর্তে সরাসরি ক্যোয়ারীতে আবদ্ধ করে।
কোটলিন
// Constructs a selection clause with a replaceable parameter.
val selectionClause = "var = ?"
// Sets up an array of arguments.
val selectionArgs: Array<String> = arrayOf("")
// Adds values to the selection arguments array.
selectionArgs[0] = userInput
জাভা
// Constructs a selection clause with a replaceable parameter.
String selectionClause = "var = ?";
// Sets up an array of arguments.
String[] selectionArgs = {""};
// Adds values to the selection arguments array.
selectionArgs[0] = userInput;
কোড ইনজেকশন প্রতিরোধ করে, এসকিউএল হিসাবে বিবেচিত না হয়ে ব্যবহারকারীর ইনপুট সরাসরি প্রশ্নের সাথে আবদ্ধ।
প্রতিস্থাপনযোগ্য পরামিতি সহ ক্রয়ের বিশদ পুনরুদ্ধার করতে একটি শপিং অ্যাপের ক্যোয়ারী দেখানো আরও বিস্তৃত উদাহরণ এখানে রয়েছে:
কোটলিন
fun validateOrderDetails(email: String, orderNumber: String): Boolean {
val cursor = db.rawQuery(
"select * from purchases where EMAIL = ? and ORDER_NUMBER = ?",
arrayOf(email, orderNumber)
)
val bool = cursor?.moveToFirst() ?: false
cursor?.close()
return bool
}
জাভা
public boolean validateOrderDetails(String email, String orderNumber) {
boolean bool = false;
Cursor cursor = db.rawQuery(
"select * from purchases where EMAIL = ? and ORDER_NUMBER = ?",
new String[]{email, orderNumber});
if (cursor != null) {
if (cursor.moveToFirst()) {
bool = true;
}
cursor.close();
}
return bool;
}
PreparedStatement অবজেক্ট ব্যবহার করুন
PreparedStatement
ইন্টারফেস SQL স্টেটমেন্টকে একটি অবজেক্ট হিসেবে প্রি-কম্পাইল করে যা পরবর্তীতে একাধিকবার দক্ষতার সাথে চালানো যেতে পারে। PreparedStatement ব্যবহার করে ?
পরামিতিগুলির জন্য একটি স্থানধারক হিসাবে, যা নিম্নলিখিত সংকলিত ইনজেকশন প্রচেষ্টাকে অকার্যকর করে তুলবে:
WHERE id=295094 OR 1=1;
এই ক্ষেত্রে, 295094 OR 1=1
বিবৃতিটি ID-এর মান হিসাবে পড়া হয়, সম্ভবত কোনও ফলাফল পাওয়া যায় না, যেখানে একটি কাঁচা ক্যোয়ারী OR 1=1
বিবৃতিটিকে WHERE
ক্লজের আরেকটি অংশ হিসাবে ব্যাখ্যা করবে। নীচের উদাহরণটি একটি প্যারামেট্রাইজড ক্যোয়ারী দেখায়:
কোটলিন
val pstmt: PreparedStatement = con.prepareStatement(
"UPDATE EMPLOYEES SET ROLE = ? WHERE ID = ?").apply {
setString(1, "Barista")
setInt(2, 295094)
}
জাভা
PreparedStatement pstmt = con.prepareStatement(
"UPDATE EMPLOYEES SET ROLE = ? WHERE ID = ?");
pstmt.setString(1, "Barista")
pstmt.setInt(2, 295094)
ক্যোয়ারী পদ্ধতি ব্যবহার করুন
এই দীর্ঘ উদাহরণে, query()
পদ্ধতির selection
এবং selectionArgs
একত্রিত করে একটি WHERE
ক্লজ তৈরি করা হয়েছে। যেহেতু আর্গুমেন্টগুলি আলাদাভাবে প্রদান করা হয়েছে, সেগুলি তাদের সংমিশ্রণের আগে পালিয়ে যায়, এসকিউএল ইনজেকশন প্রতিরোধ করে।
কোটলিন
val db: SQLiteDatabase = dbHelper.getReadableDatabase()
// Defines a projection that specifies which columns from the database
// should be selected.
val projection = arrayOf(
BaseColumns._ID,
FeedEntry.COLUMN_NAME_TITLE,
FeedEntry.COLUMN_NAME_SUBTITLE
)
// Filters results WHERE "title" = 'My Title'.
val selection: String = FeedEntry.COLUMN_NAME_TITLE.toString() + " = ?"
val selectionArgs = arrayOf("My Title")
// Specifies how to sort the results in the returned Cursor object.
val sortOrder: String = FeedEntry.COLUMN_NAME_SUBTITLE.toString() + " DESC"
val cursor = db.query(
FeedEntry.TABLE_NAME, // The table to query
projection, // The array of columns to return
// (pass null to get all)
selection, // The columns for the WHERE clause
selectionArgs, // The values for the WHERE clause
null, // Don't group the rows
null, // Don't filter by row groups
sortOrder // The sort order
).use {
// Perform operations on the query result here.
it.moveToFirst()
}
জাভা
SQLiteDatabase db = dbHelper.getReadableDatabase();
// Defines a projection that specifies which columns from the database
// should be selected.
String[] projection = {
BaseColumns._ID,
FeedEntry.COLUMN_NAME_TITLE,
FeedEntry.COLUMN_NAME_SUBTITLE
};
// Filters results WHERE "title" = 'My Title'.
String selection = FeedEntry.COLUMN_NAME_TITLE + " = ?";
String[] selectionArgs = { "My Title" };
// Specifies how to sort the results in the returned Cursor object.
String sortOrder =
FeedEntry.COLUMN_NAME_SUBTITLE + " DESC";
Cursor cursor = db.query(
FeedEntry.TABLE_NAME, // The table to query
projection, // The array of columns to return (pass null to get all)
selection, // The columns for the WHERE clause
selectionArgs, // The values for the WHERE clause
null, // don't group the rows
null, // don't filter by row groups
sortOrder // The sort order
);
সঠিকভাবে কনফিগার করা SQLiteQueryBuilder ব্যবহার করুন
বিকাশকারীরা SQLiteQueryBuilder
ব্যবহার করে অ্যাপ্লিকেশনগুলিকে আরও সুরক্ষিত করতে পারে, একটি ক্লাস যা SQLiteDatabase
অবজেক্টে পাঠানোর জন্য প্রশ্ন তৈরি করতে সহায়তা করে। প্রস্তাবিত কনফিগারেশন অন্তর্ভুক্ত:
- ক্যোয়ারী যাচাইকরণের জন্য
setStrict()
মোড। -
setStrictColumns()
যে কলামগুলি সেটপ্রজেকশনম্যাপে অনুমোদিত তালিকাভুক্ত তা যাচাই করতে। - সাবকোয়ারি সীমিত করতে
setStrictGrammar()
।
রুম লাইব্রেরি ব্যবহার করুন
android.database.sqlite
প্যাকেজ অ্যান্ড্রয়েডে ডেটাবেস ব্যবহারের জন্য প্রয়োজনীয় API সরবরাহ করে। যাইহোক, এই পদ্ধতির জন্য নিম্ন-স্তরের কোড লেখার প্রয়োজন এবং কাঁচা SQL প্রশ্নের কম্পাইল-টাইম যাচাইকরণের অভাব রয়েছে। ডেটা গ্রাফ পরিবর্তিত হওয়ার সাথে সাথে প্রভাবিত এসকিউএল কোয়েরিগুলিকে ম্যানুয়ালি আপডেট করতে হবে - একটি সময়সাপেক্ষ এবং ত্রুটি-প্রবণ প্রক্রিয়া।
একটি উচ্চ-স্তরের সমাধান হল SQLite ডাটাবেসের জন্য রুম পারসিস্টেন্স লাইব্রেরি একটি বিমূর্ত স্তর হিসাবে ব্যবহার করা। রুমের বৈশিষ্ট্যগুলির মধ্যে রয়েছে:
- একটি ডাটাবেস ক্লাস যা অ্যাপের স্থায়ী ডেটার সাথে সংযোগ করার জন্য প্রধান অ্যাক্সেস পয়েন্ট হিসাবে কাজ করে।
- ডেটাবেসের টেবিলের প্রতিনিধিত্বকারী ডেটা সত্তা।
- ডেটা অ্যাক্সেস অবজেক্ট (DAOs), যা অ্যাপটি ডেটা অনুসন্ধান, আপডেট, সন্নিবেশ এবং মুছতে ব্যবহার করতে পারে এমন পদ্ধতিগুলি প্রদান করে।
রুমের সুবিধার মধ্যে রয়েছে:
- এসকিউএল কোয়েরির কম্পাইল-টাইম যাচাইকরণ।
- ত্রুটি-প্রবণ বয়লারপ্লেট কোড হ্রাস।
- স্ট্রীমলাইনড ডাটাবেস মাইগ্রেশন।
সর্বোত্তম অনুশীলন
এসকিউএল ইনজেকশন একটি শক্তিশালী আক্রমণ যার বিরুদ্ধে এটি সম্পূর্ণরূপে স্থিতিস্থাপক হওয়া কঠিন হতে পারে, বিশেষ করে বড় এবং জটিল অ্যাপ্লিকেশনগুলির সাথে। ডেটা ইন্টারফেসে সম্ভাব্য ত্রুটিগুলির তীব্রতা সীমিত করার জন্য অতিরিক্ত নিরাপত্তা বিবেচনা করা উচিত, যার মধ্যে রয়েছে:
- পাসওয়ার্ড এনক্রিপ্ট করতে শক্তিশালী, একমুখী এবং লবণাক্ত হ্যাশ:
- বাণিজ্যিক অ্যাপ্লিকেশনের জন্য 256-বিট AES।
- উপবৃত্তাকার বক্ররেখা ক্রিপ্টোগ্রাফির জন্য 224- বা 256-বিট পাবলিক কী মাপ।
- সীমিত অনুমতি.
- সঠিকভাবে ডেটা ফরম্যাট গঠন করা এবং ডেটা প্রত্যাশিত ফর্ম্যাটের সাথে সামঞ্জস্যপূর্ণ কিনা তা যাচাই করা।
- যেখানে সম্ভব ব্যক্তিগত বা সংবেদনশীল ব্যবহারকারীর ডেটা সংরক্ষণ করা এড়িয়ে চলুন (উদাহরণস্বরূপ, ডেটা প্রেরণ বা সংরক্ষণ করার পরিবর্তে হ্যাশিংয়ের মাধ্যমে অ্যাপ্লিকেশন লজিক প্রয়োগ করা)।
- সংবেদনশীল ডেটা অ্যাক্সেস করে এমন API এবং তৃতীয় পক্ষের অ্যাপ্লিকেশনগুলিকে ছোট করা।