লগ ইনফো ডিসক্লোজার

OWASP বিভাগ: MASVS-STORAGE: স্টোরেজ

সংক্ষিপ্ত বিবরণ

লগ ইনফো ডিসক্লোজার হলো এক ধরনের দুর্বলতা, যেখানে অ্যাপগুলো ডিভাইসের লগে সংবেদনশীল ডেটা প্রিন্ট করে। ক্ষতিকারক পক্ষের কাছে ফাঁস হয়ে গেলে, এই সংবেদনশীল তথ্য সরাসরি মূল্যবান হতে পারে – যেমন ব্যবহারকারীর ক্রেডেনশিয়াল বা ব্যক্তিগতভাবে শনাক্তযোগ্য তথ্য (PII) – অথবা এটি আরও আক্রমণের সুযোগ করে দিতে পারে।

এই সমস্যাটি নিম্নলিখিত যেকোনো পরিস্থিতিতে ঘটতে পারে:

  • অ্যাপ-উৎপাদিত লগ:
    • লগগুলো ইচ্ছাকৃতভাবে অননুমোদিত ব্যক্তিদের প্রবেশাধিকার দেয়, অথচ সেগুলোতে ভুলবশত সংবেদনশীল তথ্য রয়েছে।
    • লগগুলোতে ইচ্ছাকৃতভাবে সংবেদনশীল তথ্য অন্তর্ভুক্ত করা হয়, কিন্তু অনিচ্ছাকৃতভাবে সেগুলো অননুমোদিত ব্যক্তিদের কাছে সহজলভ্য হয়ে যায়।
    • সাধারণ ত্রুটি লগ, যা প্রদর্শিত ত্রুটি বার্তার উপর নির্ভর করে মাঝে মাঝে সংবেদনশীল তথ্যও প্রিন্ট করতে পারে।
  • বাহ্যিকভাবে তৈরি লগ:
    • বাহ্যিক উপাদানগুলো সংবেদনশীল তথ্যসহ লগ প্রিন্ট করার জন্য দায়ী।

অ্যান্ড্রয়েড Log.* স্টেটমেন্টগুলো কমন মেমোরি বাফার logcat এ লেখে। অ্যান্ড্রয়েড ৪.১ (এপিআই লেভেল ১৬) থেকে, শুধুমাত্র বিশেষাধিকারপ্রাপ্ত সিস্টেম অ্যাপগুলোকেই READ_LOGS পারমিশন ঘোষণা করার মাধ্যমে logcat পড়ার অ্যাক্সেস দেওয়া যেতে পারে। তবে, অ্যান্ড্রয়েড অত্যন্ত বৈচিত্র্যময় ডিভাইস সমর্থন করে, যেগুলোর প্রি-লোডেড অ্যাপ্লিকেশনগুলো কখনও কখনও READ_LOGS প্রিভিলেজ ঘোষণা করে রাখে। ফলস্বরূপ, সরাসরি logcat এ লগিং করাকে নিরুৎসাহিত করা হয়, কারণ এতে ডেটা ফাঁসের ঝুঁকি বেশি থাকে।

আপনার অ্যাপ্লিকেশনের নন-ডিবাগ সংস্করণগুলিতে logcat -এ সমস্ত লগিং স্যানিটাইজ করা নিশ্চিত করুন। সম্ভাব্য সংবেদনশীল হতে পারে এমন যেকোনো ডেটা সরিয়ে ফেলুন। অতিরিক্ত সতর্কতা হিসেবে, ওয়ার্নিং এবং এরর ছাড়া বাকি সব লগ লেভেল মুছে ফেলার জন্য R8-এর মতো টুল ব্যবহার করুন। আপনার যদি আরও বিস্তারিত লগের প্রয়োজন হয়, তবে সিস্টেম লগ ব্যবহার না করে অভ্যন্তরীণ স্টোরেজ ব্যবহার করুন এবং সরাসরি আপনার নিজের লগগুলি পরিচালনা করুন।

প্রভাব

প্রেক্ষাপট এবং সংবেদনশীল তথ্যের ধরনের ওপর নির্ভর করে লগ ইনফো ডিসক্লোজার ভালনারেবিলিটি ক্লাসের তীব্রতা ভিন্ন হতে পারে। সামগ্রিকভাবে, এই ভালনারেবিলিটি ক্লাসের প্রভাব হলো ব্যক্তিগত শনাক্তকরণ তথ্য (PII) এবং ক্রেডেনশিয়ালের মতো সম্ভাব্য গুরুত্বপূর্ণ তথ্যের গোপনীয়তা নষ্ট হওয়া।

প্রশমন

সাধারণ

ডিজাইন এবং বাস্তবায়নের সময় একটি সাধারণ পূর্ব সতর্কতামূলক ব্যবস্থা হিসেবে, সর্বনিম্ন বিশেষাধিকারের নীতি অনুসারে বিশ্বাসের সীমানা নির্ধারণ করুন। আদর্শগতভাবে, সংবেদনশীল ডেটা কোনো বিশ্বস্ত এলাকার বাইরে যাওয়া বা পৌঁছানো উচিত নয়। এটি বিশেষাধিকারের পৃথকীকরণকে আরও শক্তিশালী করে।

সংবেদনশীল ডেটা লগ করবেন না। যখনই সম্ভব, শুধুমাত্র কম্পাইল-টাইম কনস্ট্যান্ট লগ করুন। কম্পাইল-টাইম কনস্ট্যান্ট অ্যানোটেশনের জন্য আপনি ErrorProne টুলটি ব্যবহার করতে পারেন।

এমন লগ পরিহার করুন যা ত্রুটির ধরনের ওপর নির্ভর করে সংবেদনশীল তথ্যসহ অপ্রত্যাশিত বিবরণ প্রকাশ করে। যতটা সম্ভব, লগ এবং এরর লগে প্রকাশিত তথ্যে কেবল পূর্বানুমানযোগ্য তথ্যই থাকা উচিত।

logcat এ লগিং করা থেকে বিরত থাকুন। এর কারণ হলো, READ_LOGS পারমিশন থাকা অ্যাপগুলোর জন্য logcat এ লগিং করা একটি গোপনীয়তার সমস্যা হয়ে উঠতে পারে। এটি অকার্যকরও, কারণ এর মাধ্যমে অ্যালার্ট ট্রিগার করা যায় না বা এটি থেকে তথ্য কোয়েরি করা যায় না। আমরা সুপারিশ করি যে অ্যাপ্লিকেশনগুলো শুধুমাত্র ডেভেলপার বিল্ডের জন্য logcat ব্যাকএন্ড কনফিগার করবে।

বেশিরভাগ লগ ম্যানেজমেন্ট লাইব্রেরি লগ লেভেল নির্ধারণ করার সুযোগ দেয়, যার মাধ্যমে ডিবাগ এবং প্রোডাকশন লগের মধ্যে বিভিন্ন পরিমাণ তথ্য লগ করা যায়। প্রোডাক্ট টেস্টিং শেষ হওয়ার সাথে সাথেই লগ লেভেলটি "ডিবাগ" থেকে ভিন্ন করে দিন।

প্রোডাকশন থেকে যতটা সম্ভব লগ লেভেল সরিয়ে ফেলুন। যদি প্রোডাকশনে লগ রাখা এড়ানো সম্ভব না হয়, তবে লগ স্টেটমেন্টগুলো থেকে নন-কনস্ট্যান্ট ভ্যারিয়েবলগুলো সরিয়ে দিন। নিম্নলিখিত পরিস্থিতিগুলো ঘটতে পারে:

  • আপনি প্রোডাকশন থেকে সমস্ত লগ মুছে ফেলতে পারবেন।
  • প্রোডাকশনে সতর্কীকরণ এবং ত্রুটি লগ রাখতে হবে।

এই উভয় ক্ষেত্রেই, R8-এর মতো লাইব্রেরি ব্যবহার করে স্বয়ংক্রিয়ভাবে লগ মুছে ফেলুন। ম্যানুয়ালি লগ মুছে ফেলার যেকোনো প্রচেষ্টায় ত্রুটি হওয়ার সম্ভাবনা থাকে। কোড অপটিমাইজেশনের অংশ হিসেবে, R8-কে এমনভাবে সেট করা যেতে পারে যাতে এটি ডিবাগিংয়ের জন্য রাখা লগ লেভেলগুলো নিরাপদে মুছে ফেলে, কিন্তু প্রোডাকশনে সেগুলোকে পুরোপুরি বাদ দিয়ে দেয়।

আপনি যদি প্রোডাকশনে লগ করতে যান, তবে এমন ফ্ল্যাগ প্রস্তুত রাখুন যা কোনো ঘটনার ক্ষেত্রে শর্তসাপেক্ষে লগিং বন্ধ করতে ব্যবহার করা যাবে। ইনসিডেন্ট রেসপন্স ফ্ল্যাগগুলোর অগ্রাধিকার হওয়া উচিত: ডেপ্লয়মেন্টের নিরাপত্তা; ডেপ্লয়মেন্টের গতি ও সহজলভ্যতা, লগ সম্পাদনার পুঙ্খানুপুঙ্খতা, মেমরি ব্যবহার এবং প্রতিটি লগ মেসেজ স্ক্যান করার পারফরম্যান্স খরচ।

R8 ব্যবহার করে প্রোডাকশন বিল্ড থেকে লগক্যাটে লগগুলো আলাদা করুন।

অ্যান্ড্রয়েড স্টুডিও ৩.৪ অথবা অ্যান্ড্রয়েড গ্রেডল প্লাগইন ৩.৪.০ এবং এর পরবর্তী সংস্করণগুলোতে, কোড অপটিমাইজেশন ও সঙ্কুচিত করার জন্য R8 হলো ডিফল্ট কম্পাইলার। তবে, আপনাকে R8 সক্রিয় করতে হবে।

R8, ProGuard-কে প্রতিস্থাপন করেছে, কিন্তু প্রোজেক্টের রুট ফোল্ডারের রুলস ফাইলটির নাম এখনও proguard-rules.pro । নিচের কোড স্নিপেটটিতে একটি নমুনা proguard-rules.pro ফাইল দেখানো হয়েছে, যা ওয়ার্নিং এবং এরর ছাড়া প্রোডাকশন থেকে বাকি সব লগ মুছে ফেলে:

-assumenosideeffects class android.util.Log {
    private static final String TAG = "MyTAG";
    public static boolean isLoggable(java.lang.String, int);
    public static int v(TAG, "My log as verbose");
    public static int d(TAG, "My log as debug");
    public static int i(TAG, "My log as information");
}

নিম্নলিখিত নমুনা proguard-rules.pro ফাইলটি প্রোডাকশন থেকে সমস্ত লগ মুছে ফেলে:

-assumenosideeffects class android.util.Log {
    private static final String TAG = "MyTAG";
    public static boolean isLoggable(java.lang.String, int);
    public static int v(TAG, "My log as verbose");
    public static int d(TAG, "My log as debug");
    public static int i(TAG, "My log as information");
    public static int w(TAG, "My log as warning");
    public static int e(TAG, "My log as error");
}

উল্লেখ্য যে, R8 অ্যাপ-সংকোচন এবং লগ-স্ট্রিপিং কার্যকারিতা প্রদান করে। আপনি যদি শুধুমাত্র এর লগ-স্ট্রিপিং কার্যকারিতার জন্য R8 ব্যবহার করতে চান, তাহলে আপনার proguard-rules.pro ফাইলে নিম্নলিখিতটি যোগ করুন:

-dontwarn **
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontpreverify
-verbose

-optimizations !code/simplification/arithmetic,!code/allocation/variable
-keep class **
-keepclassmembers class *{*;}
-keepattributes *

প্রোডাকশনে থাকা সংবেদনশীল ডেটা সম্বলিত যেকোনো সম্ভাব্য লগ স্যানিটাইজ করুন।

সংবেদনশীল তথ্য ফাঁস হওয়া এড়ানোর জন্য, আপনার অ্যাপ্লিকেশনের নন-ডিবাগ সংস্করণগুলিতে logcat -এ হওয়া সমস্ত লগিং পরিমার্জিত করা নিশ্চিত করুন। সম্ভাব্য সংবেদনশীল হতে পারে এমন যেকোনো ডেটা মুছে ফেলুন।

উদাহরণ:

কোটলিন

data class Credential<T>(val data: String) {
  /** Returns a redacted value to avoid accidental inclusion in logs. */
  override fun toString() = "Credential XX"
}

fun checkNoMatches(list: List<Any>) {
    if (!list.isEmpty()) {
          Log.e(TAG, "Expected empty list, but was %s", list)
    }
}

জাভা

public class Credential<T> {
  private T t;
  /** Returns a redacted value to avoid accidental inclusion in logs. */
  public String toString(){
         return "Credential XX";
  }
}

private void checkNoMatches(List<E> list) {
   if (!list.isEmpty()) {
          Log.e(TAG, "Expected empty list, but was %s", list);
   }
}

লগ থেকে সংবেদনশীল তথ্য গোপন করুন।

আপনার লগে যদি সংবেদনশীল তথ্য অন্তর্ভুক্ত করতেই হয়, তাহলে আমরা প্রিন্ট করার আগে লগগুলো স্যানিটাইজ করার পরামর্শ দিই, যাতে সংবেদনশীল তথ্য মুছে ফেলা বা অস্পষ্ট করা যায়। এটি করার জন্য, নিম্নলিখিত পদ্ধতিগুলোর মধ্যে একটি ব্যবহার করুন:

  • টোকেনাইজেশন। যদি কোনো ভল্টে সংবেদনশীল ডেটা সংরক্ষিত থাকে, যেমন একটি এনক্রিপশন ম্যানেজমেন্ট সিস্টেম যেখান থেকে টোকেনের মাধ্যমে গোপনীয় তথ্য অ্যাক্সেস করা যায়, তাহলে সংবেদনশীল ডেটার পরিবর্তে টোকেনটি লগ করুন।
  • ডেটা মাস্কিং। ডেটা মাস্কিং একটি একমুখী এবং অপরিবর্তনীয় প্রক্রিয়া। এটি সংবেদনশীল ডেটার এমন একটি সংস্করণ তৈরি করে যা গঠনগতভাবে মূল ডেটার মতোই দেখতে হয়, কিন্তু কোনো ফিল্ডের মধ্যে থাকা সবচেয়ে সংবেদনশীল তথ্য গোপন করে। উদাহরণ: ক্রেডিট কার্ড নম্বর 1234-5678-9012-3456 XXXX-XXXX-XXXX-1313 দিয়ে প্রতিস্থাপন করা। আপনার অ্যাপটি প্রোডাকশনে রিলিজ করার আগে, আমরা আপনাকে ডেটা মাস্কিং-এর ব্যবহার পুঙ্খানুপুঙ্খভাবে পরীক্ষা করার জন্য একটি নিরাপত্তা পর্যালোচনা প্রক্রিয়া সম্পন্ন করার পরামর্শ দিই। সতর্কতা: এমন ক্ষেত্রে ডেটা মাস্কিং ব্যবহার করবেন না যেখানে সংবেদনশীল ডেটার সামান্য অংশ প্রকাশ করাও নিরাপত্তার উপর মারাত্মক প্রভাব ফেলতে পারে, যেমন পাসওয়ার্ড পরিচালনার ক্ষেত্রে।
  • গোপনীয়তা অপসারণ। গোপনীয়তা অপসারণ মাস্কিং-এর মতোই, তবে এটি কোনো ফিল্ডের ভেতরের সমস্ত তথ্য গোপন করে। উদাহরণ: ক্রেডিট কার্ড নম্বর 1234-5678-9012-3456 XXXX-XXXX-XXXX-XXXX দিয়ে প্রতিস্থাপন করা।
  • ফিল্টারিং। লগ স্টেটমেন্টে পরিবর্তনশীল মান পরিবর্তন সহজ করার জন্য, আপনার পছন্দের লগিং লাইব্রেরিতে ফরম্যাট স্ট্রিং যোগ করুন, যদি তা আগে থেকে না থাকে।

লগ প্রিন্টিং শুধুমাত্র একটি “লগ স্যানিটাইজার” কম্পোনেন্টের মাধ্যমেই করা উচিত, যা প্রিন্ট করার আগে সমস্ত লগ স্যানিটাইজ করা নিশ্চিত করে, যেমনটি নিম্নলিখিত কোড স্নিপেটে দেখানো হয়েছে।

কোটলিন

data class ToMask<T>(private val data: T) {
  // Prevents accidental logging when an error is encountered.
  override fun toString() = "XX"

  // Makes it more difficult for developers to invoke sensitive data
  // and facilitates sensitive data usage tracking.
  fun getDataToMask(): T = data
}

data class Person(
  val email: ToMask<String>,
  val username: String
)

fun main() {
    val person = Person(
        ToMask("name@gmail.com"), 
        "myname"
    )
    println(person)
    println(person.email.getDataToMask())
}

জাভা

public class ToMask<T> {
  // Prevents accidental logging when an error is encountered.
  public String toString(){
         return "XX";
  }

  // Makes it more difficult for developers to invoke sensitive data 
  // and facilitates sensitive data usage tracking.
  public T  getDataToMask() {
    return this;
  }
}

public class Person {
  private ToMask<String> email;
  private String username;

  public Person(ToMask<String> email, String username) {
    this.email = email;
    this.username = username;
  }
}

public static void main(String[] args) {
    Person person = new Person(
        ToMask("name@gmail.com"), 
        "myname"
    );
    System.out.println(person);
    System.out.println(person.email.getDataToMask());
}