প্রবেশাধিকার নিয়ন্ত্রণ

Tink এর একটি লক্ষ্য হল খারাপ অভ্যাস নিরুৎসাহিত করা। এই বিভাগে বিশেষ আগ্রহের দুটি পয়েন্ট হল:

  1. Tink ব্যবহারকে এমনভাবে উৎসাহিত করে যাতে ব্যবহারকারীরা গোপন মূল উপাদান অ্যাক্সেস করতে না পারে। পরিবর্তে, Tink এই ধরনের সিস্টেমগুলিকে সমর্থন করে এমন পূর্বনির্ধারিত উপায়গুলির মধ্যে একটি ব্যবহার করে যখনই সম্ভব গোপন কীগুলি একটি KMS- এ সংরক্ষণ করা উচিত।
  2. Tink ব্যবহারকারীদের কীগুলির অংশগুলি অ্যাক্সেস করতে নিরুৎসাহিত করে, কারণ এটি করার ফলে প্রায়শই সামঞ্জস্যপূর্ণ বাগ হয়।

অনুশীলনে, অবশ্যই এই উভয় নীতি মাঝে মাঝে লঙ্ঘন করতে হবে। এই জন্য, Tink বিভিন্ন প্রক্রিয়া প্রদান করে.

গোপন কী অ্যাক্সেস টোকেন

গোপন কী উপাদান অ্যাক্সেস করার জন্য, ব্যবহারকারীদের একটি টোকেন থাকতে হবে (যা সাধারণত কোনো কার্যকারিতা ছাড়াই কোনো কোনো শ্রেণীর একটি বস্তু)। টোকেনটি সাধারণত একটি পদ্ধতি দ্বারা প্রদান করা হয় যেমন InsecureSecretKeyAccess.get() । Google-এর মধ্যে, ব্যাজেল বিল্ড ভিজিবিলিটি ব্যবহার করে ব্যবহারকারীদের এই ফাংশনটি ব্যবহার করতে বাধা দেওয়া হয়। Google এর বাইরে, নিরাপত্তা পর্যালোচকরা এই ফাংশনের ব্যবহারের জন্য তাদের কোডবেস অনুসন্ধান করতে পারেন।

এই টোকেনগুলির একটি দরকারী বৈশিষ্ট্য হ'ল এগুলি প্রেরণ করা যেতে পারে। উদাহরণস্বরূপ, ধরুন আপনার কাছে একটি ফাংশন রয়েছে যা একটি নির্বিচারে টিঙ্ক কীকে সিরিয়ালাইজ করে:

String serializeKey(Key key, @Nullable SecretKeyAccess secretKeyAccess);

গোপন কী উপাদান আছে এমন কীগুলির জন্য, এই ফাংশনের জন্য secretKeyAccess অবজেক্টটিকে নন-নাল হতে হবে এবং একটি প্রকৃত SecretKeyAccess টোকেন সংরক্ষণ করতে হবে। কোন গোপন উপাদান নেই এমন কীগুলির জন্য, secretKeyAccess উপেক্ষা করা হয়।

এই ধরনের একটি ফাংশন দেওয়া হলে, একটি ফাংশন লেখা সম্ভব যা একটি সম্পূর্ণ কীসেটকে সিরিয়ালাইজ করে: স্ট্রিং serializeKeyset(KeysetHandle keyset, @Nullable SecretKeyAccess secretKeyAccess);

এই ফাংশনটি অভ্যন্তরীণভাবে কীসেটের প্রতিটি কী-এর জন্য serializeKey কল করে এবং অন্তর্নিহিত ফাংশনে প্রদত্ত secretKeyAccess পাস করে। ব্যবহারকারীরা যারা গোপন কী উপাদান সিরিয়ালাইজ করার প্রয়োজন ছাড়াই serializeKeyset কল করে তারা দ্বিতীয় যুক্তি হিসাবে null ব্যবহার করতে পারে। যে ব্যবহারকারীদের গোপন কী উপাদান সিরিয়ালাইজ করার প্রয়োজন আছে তাদের InsecureSecretKeyAccess.get() ব্যবহার করতে হবে।

একটি চাবির অংশ অ্যাক্সেস

একটি অপেক্ষাকৃত সাধারণ নিরাপত্তা বাগ হল "কী পুনঃব্যবহারের আক্রমণ"। এটি ঘটতে পারে যখন ব্যবহারকারীরা দুটি ভিন্ন সেটিংসে (যেমন, স্বাক্ষর এবং এনক্রিপশন গণনা করতে) 1 মডুলাস n এবং এক্সপোনেন্ট d এবং e একটি RSA কী-এর পুনঃব্যবহার করে।

ক্রিপ্টোগ্রাফিক কীগুলির সাথে কাজ করার সময় আরেকটি তুলনামূলকভাবে সাধারণ ভুল হল কীটির অংশ নির্দিষ্ট করা এবং তারপরে মেটাডেটা "অনুমান" করা। উদাহরণস্বরূপ, ধরুন একজন ব্যবহারকারী একটি ভিন্ন লাইব্রেরির সাথে ব্যবহারের জন্য Tink থেকে একটি RSASSA-PSS পাবলিক কী রপ্তানি করতে চায়। টিঙ্কে, এই কীগুলির নিম্নলিখিত অংশ রয়েছে:

  • মডুলাস n
  • পাবলিক এক্সপোনেন্ট e
  • অভ্যন্তরীণভাবে ব্যবহৃত দুটি হ্যাশ ফাংশনের স্পেসিফিকেশন
  • অ্যালগরিদমে অভ্যন্তরীণভাবে ব্যবহৃত লবণের দৈর্ঘ্য।

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

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

এই ক্ষেত্রে, কী রপ্তানি করা ফাংশনটি ব্যর্থ হওয়া উচিত যদি হ্যাশ ফাংশনটি অন্য লাইব্রেরির প্রত্যাশার সাথে মেলে না: অন্যথায়, রপ্তানি করা কীটি অকেজো কারণ এটি অসঙ্গত সাইফারটেক্সট বা স্বাক্ষর তৈরি করে।

এই ধরনের ভুলগুলি প্রতিরোধ করার জন্য, Tink ফাংশনগুলিকে সীমাবদ্ধ করে যা মূল উপাদানগুলিতে অ্যাক্সেস দেয় যা শুধুমাত্র আংশিক, কিন্তু সম্পূর্ণ কী হিসাবে ভুল হতে পারে। উদাহরণস্বরূপ, Java Tink এর জন্য RestrictedApi ব্যবহার করে।

যখন একজন ব্যবহারকারী এই ধরনের একটি টীকা ব্যবহার করেন, তখন তারা মূল পুনঃব্যবহারের আক্রমণ এবং অসঙ্গতি উভয়ই প্রতিরোধের জন্য দায়ী।

সর্বোত্তম অনুশীলন: কী আমদানিতে যত তাড়াতাড়ি সম্ভব টিঙ্ক বস্তু ব্যবহার করুন

টিঙ্ক থেকে কী রপ্তানি বা কী আমদানি করার সময় আপনি সাধারণত "আংশিক কী অ্যাক্সেস" এর সাথে সীমাবদ্ধ পদ্ধতিগুলির মুখোমুখি হন।

এটি কী বিভ্রান্তির আক্রমণের ঝুঁকি কমিয়ে দেয়, কারণ টিঙ্ক কী অবজেক্টটি সঠিক অ্যালগরিদম সম্পূর্ণরূপে নির্দিষ্ট করে এবং মূল উপাদানের সাথে সমস্ত মেটাডেটা একত্রে সংরক্ষণ করে।

নিম্নলিখিত উদাহরণ বিবেচনা করুন:

অ-টাইপ ব্যবহার:

void verifyEcdsaSignature(ECPoint ecPoint, byte[] signature, byte[] message)
        throws Exception {
    EcdsaParameters parameters =
        EcdsaParameters.builder()
            .setSignatureEncoding(EcdsaParameters.SignatureEncoding.IEEE_P1363)
            .setCurveType(EcdsaParameters.CurveType.NIST_P256)
            .setHashType(EcdsaParameters.HashType.SHA256)
            .setVariant(EcdsaParameters.Variant.NO_PREFIX)
            .build();
    EcdsaPublicKey key =
        EcdsaPublicKey.builder()
            .setParameters(parameters)
            .setPublicPoint(ecPoint)
            .build();
    KeysetHandle handle = KeysetHandle.newBuilder()
       .addEntry(KeysetHandle.importKey(key).withFixedId(1).makePrimary())
       .build();
    PublicKeyVerify publicKeyVerify = handle.getPrimitive(PublicKeyVerify.class);
    publicKeyVerify.verify(signature, message);
}

এটি ত্রুটি প্রবণ: কল সাইটে এটি ভুলে যাওয়া খুব সহজ যে আপনি অন্য অ্যালগরিদমের সাথে একই ecPoint ব্যবহার করবেন না। উদাহরণস্বরূপ, যদি encryptWithECHybridEncrypt নামে একটি অনুরূপ ফাংশন বিদ্যমান থাকে, তাহলে কলকারী একটি বার্তা এনক্রিপ্ট করতে একই কার্ভ পয়েন্ট ব্যবহার করতে পারে, যা সহজেই দুর্বলতার দিকে নিয়ে যেতে পারে।

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

পূর্ববর্তী কোডটি আরও উন্নত করা যেতে পারে। EcdsaPublicKey এ পাস করার পরিবর্তে, একটি KeysetHandle এ পাস করা ভাল। এটি কোন অতিরিক্ত কাজ ছাড়াই কী রোটেশনের জন্য কোড প্রস্তুত করে। তাই এই পছন্দ করা উচিত.

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

সুপারিশ: যখন প্রথমবার ডিস্ক বা নেটওয়ার্ক থেকে মূল উপাদান পড়া হয়, যত তাড়াতাড়ি সম্ভব সংশ্লিষ্ট টিঙ্ক বস্তু তৈরি করুন।

টাইপ করা ব্যবহার:

KeysetHandle readEcdsaKeyFromFile(Path fileWithEcdsaKey) throws Exception {
    byte[] content = Files.readAllBytes(fileWithEcdsaKey);
    BigInteger x = new BigInteger(1, Arrays.copyOfRange(content, 0, 32));
    BigInteger y = new BigInteger(1, Arrays.copyOfRange(content, 32, 64));
    ECPoint point = new ECPoint(x, y);
    EcdsaParameters parameters =
        EcdsaParameters.builder()
            .setSignatureEncoding(EcdsaParameters.SignatureEncoding.IEEE_P1363)
            .setCurveType(EcdsaParameters.CurveType.NIST_P256)
            .setHashType(EcdsaParameters.HashType.SHA256)
            .setVariant(EcdsaParameters.Variant.NO_PREFIX)
            .build();
    EcdsaPublicKey key =
        EcdsaPublicKey.builder()
            .setParameters(parameters)
            .setPublicPoint(ecPoint)
            .build();
    return KeysetHandle.newBuilder()
       .addEntry(KeysetHandle.importKey(key).withFixedId(1).makePrimary())
       .build();
}

এই ধরনের কোড ব্যবহার করে, আমরা বাইট-অ্যারেটি পড়ার সাথে সাথে একটি Tink অবজেক্টে রূপান্তর করি এবং আমরা সম্পূর্ণরূপে নির্দিষ্ট করি যে কোন অ্যালগরিদম ব্যবহার করা উচিত। এই পদ্ধতিটি মূল বিভ্রান্তির আক্রমণের সম্ভাবনা কমিয়ে দেয়।

সর্বোত্তম অনুশীলন: কী রপ্তানির সমস্ত পরামিতি যাচাই করুন

উদাহরণস্বরূপ, যদি আপনি একটি ফাংশন লেখেন যা একটি HPKE পাবলিক কী রপ্তানি করে:

একটি সর্বজনীন কী রপ্তানি করার খারাপ উপায়:

/** Provide the key to our users which do not have Tink. */
byte[] exportTinkHpkeKey(HpkePublicKey key) {
    return key.getPublicKeyBytes().toByteArray();
}

এই সমস্যাযুক্ত. চাবিটি পাওয়ার পর, এটি ব্যবহারকারী তৃতীয় পক্ষ কীটির পরামিতিগুলির উপর কিছু অনুমান করে: উদাহরণস্বরূপ, এটি অনুমান করবে যে এই কী 256-বিটের জন্য ব্যবহৃত HPKE AEAD অ্যালগরিদমটি AES-GCM ছিল এবং আরও অনেক কিছু।

সুপারিশ: কী রপ্তানির ক্ষেত্রে আপনি যা আশা করেন তা যাচাই করুন।

একটি সর্বজনীন কী রপ্তানি করার আরও ভাল উপায়:

/** Provide the key to our users which do not have Tink. */
byte[] exportTinkHpkeKeyForOurUsers(HpkePublicKey key) {
    // Our users assume we use KEM_P256_HKDF_SHA256 for the KEM.
    if (!key.getParameters().getKemId().equals(HpkeParameters.KemId.KEM_P256_HKDF_SHA256)) {
        throw new IllegalArgumentException("Bad parameters");
    }
    // Our users assume we use HKDF SHA256 to create the key material.
    if (!key.getParameters().getKdfId().equals(HpkeParameters.KdfId.HKDF_SHA256)) {
        throw new IllegalArgumentException("Bad parameters");
    }
    // Our users assume that we use AES GCM with 256 bit keys.
    if (!key.getParameters().getAeadId().equals(HpkeParameters.AeadId.AES_256_GCM)) {
        throw new IllegalArgumentException("Bad parameters");
    }
    // Our users assume we follow the standard and do not add a Tink style prefix
    if (!key.getParameters().getVariant().equals(HpkeParameters.Variant.NO_PREFIX)) {
        throw new IllegalArgumentException("Bad parameters");
    }
    return key.getPublicKeyBytes().toByteArray();
}