Chrome वेरिफ़ाइड ऐक्सेस डेवलपर की गाइड

इस गाइड के बारे में जानकारी

Chrome वेरिफ़ाइड ऐक्सेस एपीआई, वीपीएन, इंट्रानेट पेज वगैरह जैसी नेटवर्क सेवाओं को अनुमति देता है. इसकी मदद से, वे क्रिप्टोग्राफ़िक तरीके से यह पुष्टि कर पाते हैं कि उनके क्लाइंट सही हैं और कॉर्पोरेट नीति का पालन करते हैं. ज़्यादातर बड़े एंटरप्राइज़ को अपने WPA2 EA-TLS नेटवर्क पर, सिर्फ़ एंटरप्राइज़ से मैनेज किए जाने वाले डिवाइसों को अनुमति देना ज़रूरी है. इसके अलावा, वीपीएन में हाई-टीयर ऐक्सेस और म्युचुअल-TLS इंट्रानेट पेजों पर भी यह अनुमति दी जाती है. कई मौजूदा समाधान, उसी क्लाइंट पर किए गए अनुमानों के आधार पर जांच करते हैं जिससे शायद छेड़छाड़ की गई हो. इससे यह चुनौती सामने आती है कि डिवाइस की वैध स्थिति की पुष्टि करने के लिए जिन सिग्नल पर भरोसा किया जा रहा है, हो सकता है वे गलत हो गए हों. यह गाइड हार्डवेयर-आधारित क्रिप्टोग्राफ़िक गारंटी के साथ डिवाइस की पहचान की जानकारी देती है. साथ ही, यह भी बताती है कि डिवाइस को चालू करते समय, उसकी स्थिति में कोई बदलाव नहीं किया गया था और वह नीति का पालन करता था. इसे वेरिफ़ाइड ऐक्सेस कहा जाता है.

प्राइमरी ऑडियंस एंटरप्राइज़ आईटी डोमेन एडमिन
तकनीकी कॉम्पोनेंट ChromeOS, Google वेरिफ़ाइड ऐक्सेस एपीआई

पुष्टि किए गए ऐक्सेस की ज़रूरी शर्तें

'पुष्टि किए गए ऐक्सेस' प्रोसेस को लागू करने से पहले, नीचे दिया गया सेट अप पूरा करें.

एपीआई चालू करें

Google API कंसोल प्रोजेक्ट सेटअप करें और API को चालू करें:

  1. Google API कंसोल में कोई प्रोजेक्ट बनाएं या पहले से मौजूद प्रोजेक्ट का इस्तेमाल करें.
  2. चालू एपीआई और सेवाएं पेज पर जाएं.
  3. Chrome वेरिफ़ाइड ऐक्सेस एपीआई को चालू करें.
  4. Google Cloud API दस्तावेज़ में दिए गए निर्देशों का पालन करके, अपने ऐप्लिकेशन के लिए एपीआई पासकोड बनाएं.

सेवा खाता बनाना

नेटवर्क सेवा, आपके चैलेंज के जवाब की पुष्टि करने के लिए, Chrome वेरिफ़ाइड ऐक्सेस एपीआई को ऐक्सेस कर सके, इसके लिए सेवा खाता और सेवा खाते की कुंजी बनाएं (आपको कोई नया Cloud प्रोजेक्ट बनाने की ज़रूरत नहीं है. आप दोनों का ही इस्तेमाल कर सकते हैं).

सेवा खाता कुंजी बनाने के बाद, सेवा खाते की निजी कुंजी फ़ाइल डाउनलोड हो जाएगी. निजी कुंजी की अकेली कॉपी है, इसलिए इसे सुरक्षित तरीके से सेव करें.

मैनेज किए जा रहे Chromebook डिवाइस को रजिस्टर करें

'पुष्टि किए गए ऐक्सेस' के लिए आपके Chrome एक्सटेंशन के साथ सही तरीके से मैनेज किए गए Chromebook डिवाइस को सेटअप करना ज़रूरी है.

  1. Chromebook डिवाइस, एंटरप्राइज़ या एजुकेशन मैनेजमेंट के लिए रजिस्टर होना चाहिए.
  2. डिवाइस का उपयोगकर्ता, उसी डोमेन का रजिस्टर्ड उपयोगकर्ता होना चाहिए.
  3. 'पुष्टि किए गए ऐक्सेस' का Chrome एक्सटेंशन डिवाइस पर इंस्टॉल होना चाहिए.
  4. नीतियों को 'पुष्टि किया गया ऐक्सेस' चालू करने, Chrome एक्सटेंशन को अनुमति देने, और नेटवर्क सेवा से जुड़े सेवा खाते के लिए एपीआई को ऐक्सेस देने के लिए कॉन्फ़िगर किया गया है (Google Admin console सहायता दस्तावेज़ देखें).

उपयोगकर्ता और डिवाइस की पुष्टि करें

डेवलपर, उपयोगकर्ता या डिवाइस की पुष्टि के लिए 'पुष्टि किए गए ऐक्सेस' का इस्तेमाल कर सकते हैं या ज़्यादा सुरक्षा के लिए, दोनों का इस्तेमाल कर सकते हैं:

  • डिवाइस की पुष्टि—अगर सफल होता है, तो डिवाइस की पुष्टि से इस बात की गारंटी मिलती है कि Chrome डिवाइस को मैनेज किए जा रहे डोमेन में रजिस्टर किया गया है. साथ ही, यह डोमेन एडमिन की ओर से तय की गई, पुष्टि किए गए बूट मोड डिवाइस से जुड़ी नीति का पालन करता है. अगर नेटवर्क सेवा को डिवाइस की पहचान देखने की अनुमति दी गई है (Google Admin console के सहायता दस्तावेज़ देखें), तो उसे एक डिवाइस आईडी भी मिलता है. इसका इस्तेमाल ऑडिटिंग, ट्रैकिंग या डायरेक्ट्री एपीआई को कॉल करने के लिए किया जा सकता है.

  • उपयोगकर्ता की पुष्टि—अगर पुष्टि हो जाती है, तो उपयोगकर्ता की पुष्टि इस बात की गारंटी देती है कि साइन इन किया हुआ Chrome उपयोगकर्ता, मैनेज किया जा रहा उपयोगकर्ता है और वह रजिस्टर किए गए डिवाइस का इस्तेमाल कर रहा है. साथ ही, पुष्टि किए गए बूट मोड की उपयोगकर्ता नीति के मुताबिक है, जैसा कि डोमेन एडमिन ने तय किया है. अगर नेटवर्क सेवा को उपयोगकर्ता का अतिरिक्त डेटा पाने की अनुमति दी जाती है, तो उसे उपयोगकर्ता से जारी किया गया, हस्ताक्षर करने का सर्टिफ़िकेट भी मिलेगा (sign-public-key-and-Challenge के रूप में सीएसआर या SPKAC, जिसे कीजेन फ़ॉर्मैट भी कहा जाता है).

उपयोगकर्ता और डिवाइस की पुष्टि करने का तरीका

  1. चुनौती पाएं—डिवाइस पर मौजूद Chrome एक्सटेंशन, चैलेंज पाने के लिए वेरिफ़ाइड ऐक्सेस एपीआई से संपर्क करता है. यह चैलेंज एक ओपेक डेटा स्ट्रक्चर (Google की ओर से हस्ताक्षर किया गया ब्लॉब) है, जो एक मिनट तक अच्छा काम करता है. इसका मतलब है कि अगर किसी पुराने चैलेंज का इस्तेमाल किया जाए, तो चैलेंज-रिस्पॉन्स की पुष्टि (तीसरा चरण) पूरी नहीं हो पाती.

    सबसे आसान इस्तेमाल में, उपयोगकर्ता इस फ़्लो की शुरुआत, एक्सटेंशन से जनरेट होने वाले बटन पर क्लिक करके करता है (Google के दिए गए सैंपल एक्सटेंशन को भी यही करता है).

    var apiKey = 'YOUR_API_KEY_HERE';
    var challengeUrlString =
      'https://verifiedaccess.googleapis.com/v2/challenge:generate?key=' + apiKey;
    
    // Request challenge from URL
    var xmlhttp = new XMLHttpRequest();
    xmlhttp.open('POST', challengeUrlString, true);
    xmlhttp.send();
    xmlhttp.onreadystatechange = function() {
      if (xmlhttp.readyState == 4) {
        var challenge = xmlhttp.responseText;
        console.log('challenge: ' + challenge);
        // v2 of the API returns an encoded challenge so no further challenge processing is needed
      }
    };
    

    चैलेंज को कोड में बदलने के लिए हेल्पर कोड—अगर एपीआई के v1 का इस्तेमाल किया जा रहा है, तो चुनौती को कोड में बदलना होगा.

    // This can be replaced by using a third-party library such as
    // [https://github.com/dcodeIO/ProtoBuf.js/wiki](https://github.com/dcodeIO/ProtoBuf.js/wiki)
    /**
     * encodeChallenge convert JSON challenge into base64 encoded byte array
     * @param {string} challenge JSON encoded challenge protobuf
     * @return {string} base64 encoded challenge protobuf
     */
    var encodeChallenge = function(challenge) {
      var jsonChallenge = JSON.parse(challenge);
      var challengeData = jsonChallenge.challenge.data;
      var challengeSignature = jsonChallenge.challenge.signature;
    
      var protobufBinary = protoEncodeChallenge(
          window.atob(challengeData), window.atob(challengeSignature));
    
      return window.btoa(protobufBinary);
    };
    
    /**
     * protoEncodeChallenge produce binary encoding of the challenge protobuf
     * @param {string} dataBinary binary data field
     * @param {string} signatureBinary binary signature field
     * @return {string} binary encoded challenge protobuf
     */
    var protoEncodeChallenge = function(dataBinary, signatureBinary) {
      var protoEncoded = '';
    
      // See https://developers.google.com/protocol-buffers/docs/encoding
      // for encoding details.
    
      // 0x0A (00001 010, field number 1, wire type 2 [length-delimited])
      protoEncoded += '\u000A';
    
      // encode length of the data
      protoEncoded += varintEncode(dataBinary.length);
      // add data
      protoEncoded += dataBinary;
    
      // 0x12 (00010 010, field number 2, wire type 2 [length-delimited])
      protoEncoded += '\u0012';
      // encode length of the signature
      protoEncoded += varintEncode(signatureBinary.length);
      // add signature
      protoEncoded += signatureBinary;
    
      return protoEncoded;
    };
    
    /**
     * varintEncode produce binary encoding of the integer number
     * @param {number} number integer number
     * @return {string} binary varint-encoded number
     */
    var varintEncode = function(number) {
      // This only works correctly for numbers 0 through 16383 (0x3FFF)
      if (number <= 127) {
        return String.fromCharCode(number);
      } else {
        return String.fromCharCode(128 + (number & 0x7f), number >>> 7);
      }
    };
    
  2. चुनौती का रिस्पॉन्स जनरेट करें—Chrome एक्सटेंशन, पहले चरण में मिलने वाली चुनौती का इस्तेमाल करता है. इस चुनौती से Enterprise.platformKeys Chrome API को कॉल किया जाता है. इससे, साइन और एन्क्रिप्ट (सुरक्षित) किया गया चैलेंज रिस्पॉन्स जनरेट होता है. इसे एक्सटेंशन, नेटवर्क सेवा को भेजे गए ऐक्सेस अनुरोध में शामिल करता है.

    इस चरण में, ऐसा प्रोटोकॉल तय करने की कोशिश नहीं की जाती जिसका इस्तेमाल एक्सटेंशन और नेटवर्क सेवा, बातचीत करने के लिए करती है. ये दोनों इकाइयां बाहरी डेवलपर लागू करते हैं और यह तय नहीं होता कि वे एक-दूसरे से कैसे बात करें. इसका एक उदाहरण है, (यूआरएल के हिसाब से कोड में बदला गया) चैलेंज रिस्पॉन्स को, क्वेरी स्ट्रिंग पैरामीटर के तौर पर, एचटीटीपी पोस्ट का इस्तेमाल करके या खास एचटीटीपी हेडर का इस्तेमाल करके.

    चैलेंज का जवाब जनरेट करने के लिए, यहां एक सैंपल कोड दिया गया है:

    चैलेंज का जवाब जनरेट करें

      // Generate challenge response
      var encodedChallenge; // obtained by generate challenge API call
      try {
        if (isDeviceVerification) { // isDeviceVerification set by external logic
          chrome.enterprise.platformKeys.challengeKey(
              {
                scope: 'MACHINE',
                challenge: decodestr2ab(encodedChallenge),
              },
              ChallengeCallback);
        } else {
          chrome.enterprise.platformKeys.challengeKey(
              {
                scope: 'USER',
                challenge: decodestr2ab(encodedChallenge),
                registerKey: { 'RSA' }, // can also specify 'ECDSA'
              },
              ChallengeCallback);
        }
      } catch (error) {
        console.log('ERROR: ' + error);
      }
    

    चैलेंज कॉलबैक फ़ंक्शन

      var ChallengeCallback = function(response) {
        if (chrome.runtime.lastError) {
          console.log(chrome.runtime.lastError.message);
        } else {
          var responseAsString = ab2base64str(response);
          console.log('resp: ' + responseAsString);
        ... // send on to network service
       };
      }
    

    ArrayBuffer कन्वर्ज़न के लिए हेल्पर कोड

      /**
       * ab2base64str convert an ArrayBuffer to base64 string
       * @param {ArrayBuffer} buf ArrayBuffer instance
       * @return {string} base64 encoded string representation
       * of the ArrayBuffer
       */
      var ab2base64str = function(buf) {
        var binary = '';
        var bytes = new Uint8Array(buf);
        var len = bytes.byteLength;
        for (var i = 0; i < len; i++) {
          binary += String.fromCharCode(bytes[i]);
        }
        return window.btoa(binary);
      }
    
      /**
       * decodestr2ab convert a base64 encoded string to ArrayBuffer
       * @param {string} str string instance
       * @return {ArrayBuffer} ArrayBuffer representation of the string
       */
      var decodestr2ab = function(str) {
        var binary_string =  window.atob(str);
        var len = binary_string.length;
        var bytes = new Uint8Array(len);
        for (var i = 0; i < len; i++)        {
            bytes[i] = binary_string.charCodeAt(i);
        }
        return bytes.buffer;
      }
    
  3. चैलेंज रिस्पॉन्स की पुष्टि करें—किसी डिवाइस से चैलेंज रिस्पॉन्स मिलने पर, नेटवर्क सेवा को पुष्टि करने वाले मौजूदा प्रोटोकॉल के एक्सटेंशन के तौर पर, डिवाइस की पहचान और नीति की स्थिति की पुष्टि करने के लिए वेरिफ़ाइड ऐक्सेस एपीआई को कॉल करना चाहिए (नीचे दिया गया उदाहरण कोड देखें). स्पूफ़िंग (झूठे नाम से मेल भेजना) से निपटने के लिए, हमारा सुझाव है कि नेटवर्क सेवा, उस क्लाइंट की पहचान करे जिससे वह बात कर रहा है. साथ ही, अनुरोध में क्लाइंट की अनुमानित पहचान भी शामिल की जानी चाहिए:

    • डिवाइस की पुष्टि के लिए, अनुमानित डिवाइस डोमेन दिया जाना चाहिए . कई मामलों में यह हार्ड कोड की गई वैल्यू हो सकती है, क्योंकि नेटवर्क सेवा किसी खास डोमेन के संसाधनों की सुरक्षा करती है. अगर इस बारे में पहले से पता नहीं, तो उपयोगकर्ता की पहचान से इसका पता लगाया जा सकता है.
    • उपयोगकर्ता की पुष्टि के लिए, उपयोगकर्ता का ईमेल पता दिया जाना चाहिए. हम उम्मीद करते हैं कि नेटवर्क सेवा को उसके उपयोगकर्ताओं के बारे में जानकारी होगी (आम तौर पर, इसके लिए उपयोगकर्ताओं को साइन इन करना होगा).

    Google API को कॉल करने पर, यह कई तरह की जांच करता है, जैसे:

    • पुष्टि करें कि चैलेंज का रिस्पॉन्स, ChromeOS ने बनाया है और ट्रांसफ़र के दौरान इसमें कोई बदलाव नहीं किया गया हो
    • पुष्टि करें कि डिवाइस या उपयोगकर्ता को एंटरप्राइज़ मैनेज करता है.
    • इस बात की पुष्टि करें कि डिवाइस/उपयोगकर्ता की पहचान, अनुमानित पहचान से मेल खाती हो (अगर पहचान वाली जानकारी बाद में दी गई हो).
    • पुष्टि करें कि जिस चुनौती का जवाब दिया जा रहा है वह नई है (एक मिनट से ज़्यादा पुराना नहीं हो).
    • पुष्टि करें कि डिवाइस या उपयोगकर्ता, डोमेन एडमिन की बताई गई नीति का पालन करता हो.
    • पुष्टि करें कि कॉलर (नेटवर्क सेवा) को एपीआई को कॉल करने की अनुमति दी गई है.
    • अगर कॉलर को डिवाइस या उपयोगकर्ता का अन्य डेटा लेने की अनुमति दी जाती है, तो जवाब में डिवाइस आईडी या उपयोगकर्ता के सर्टिफ़िकेट पर हस्ताक्षर करने के अनुरोध (सीएसआर) को शामिल करें.

    इस उदाहरण में, gRPC लाइब्रेरी का इस्तेमाल किया गया है

    import com.google.auth.oauth2.GoogleCredentials;
    import com.google.auth.oauth2.ServiceAccountCredentials;
    import com.google.chrome.verifiedaccess.v2.VerifiedAccessGrpc;
    import com.google.chrome.verifiedaccess.v2.VerifyChallengeResponseRequest;
    import com.google.chrome.verifiedaccess.v2.VerifyChallengeResponseResult;
    import com.google.protobuf.ByteString;
    
    import io.grpc.ClientInterceptor;
    import io.grpc.ClientInterceptors;
    import io.grpc.ManagedChannel;
    import io.grpc.auth.ClientAuthInterceptor;
    import io.grpc.netty.GrpcSslContexts;
    import io.grpc.netty.NettyChannelBuilder;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.util.Arrays;
    import java.util.concurrent.Executors;
    
    // https://cloud.google.com/storage/docs/authentication#generating-a-private-key
    private final String clientSecretFile = "PATH_TO_GENERATED_JSON_SECRET_FILE";
    
    private ManagedChannel channel;
    private VerifiedAccessGrpc.VerifiedAccessBlockingStub client;
    
    void setup() {
    
       channel = NettyChannelBuilder.forAddress("verifiedaccess.googleapis.com", 443)
          .sslContext(GrpcSslContexts.forClient().ciphers(null).build())
          .build();
    
       List<ClientInterceptor> interceptors = Lists.newArrayList();
       // Attach a credential for my service account and scope it for the API.
       GoogleCredentials credentials =
           ServiceAccountCredentials.class.cast(
               GoogleCredentials.fromStream(
                   new FileInputStream(new File(clientSecretFile))));
      credentials = credentials.createScoped(
          Arrays.<String>asList("https://www.googleapis.com/auth/verifiedaccess"));
      interceptors.add(
           new ClientAuthInterceptor(credentials, Executors.newSingleThreadExecutor()));
    
      // Create a stub bound to the channel with the interceptors applied
      client = VerifiedAccessGrpc.newBlockingStub(
          ClientInterceptors.intercept(channel, interceptors));
    }
    
    /**
     * Invokes the synchronous RPC call that verifies the device response.
     * Returns the result protobuf as a string.
     *
     * @param signedData base64 encoded signedData blob (this is a response from device)
     * @param expectedIdentity expected identity (domain name or user email)
     * @return the verification result protobuf as string
     */
    public String verifyChallengeResponse(String signedData, String expectedIdentity)
      throws IOException, io.grpc.StatusRuntimeException {
      VerifyChallengeResponseResult result =
        client.verifyChallengeResponse(newVerificationRequest(signedData,
            expectedIdentity)); // will throw StatusRuntimeException on error.
    
      return result.toString();
    }
    
    private VerifyChallengeResponseRequest newVerificationRequest(
      String signedData, String expectedIdentity) throws IOException {
      return VerifyChallengeResponseRequest.newBuilder()
        .setChallengeResponse(
            ByteString.copyFrom(BaseEncoding.base64().decode(signedData)))
        .setExpectedIdentity(expectedIdentity == null ? "" : expectedIdentity)
        .build();
    }
    
  4. ऐक्सेस देना—यह चरण भी नेटवर्क-सेवा के लिए खास है. इस तरीके को लागू करने का सुझाव दिया गया है (बता नहीं गया है). ये कार्रवाइयां की जा सकती हैं:

    • सेशन कुकी बनाना
    • उपयोगकर्ता या डिवाइस को सर्टिफ़िकेट जारी करना. उपयोगकर्ता की पुष्टि हो जाने और यह मान लेने पर कि नेटवर्क सेवा को दूसरे उपयोगकर्ता डेटा का ऐक्सेस (Google Admin console नीति के ज़रिए) दिया गया है, तो उसे उपयोगकर्ता का हस्ताक्षर किया हुआ सीएसआर मिलता है, जिसका इस्तेमाल सर्टिफ़िकेट देने वाली संस्था या निकाय से असली सर्टिफ़िकेट पाने के लिए किया जा सकता है. Microsoft CA के साथ इंटिग्रेट करते समय, नेटवर्क सेवा मध्यवर्ती की तरह काम कर सकती है और ICertRequest इंटरफ़ेस का इस्तेमाल कर सकती है.

'पुष्टि किए गए ऐक्सेस' के साथ क्लाइंट सर्टिफ़िकेट का इस्तेमाल करना

'पुष्टि किए गए ऐक्सेस' के साथ क्लाइंट सर्टिफ़िकेट का इस्तेमाल करना.

एक बड़े संगठन में, ऐसी कई नेटवर्क सेवाएं (वीपीएन सर्वर, वाई-फ़ाई ऐक्सेस पॉइंट, फ़ायरवॉल, और कई इंट्रानेट साइटें) हो सकती हैं जिन्हें 'पुष्टि किए गए ऐक्सेस' से फ़ायदा हो सकता है. हालांकि, इन नेटवर्क सेवाओं में से हर एक के लिए, दूसरे से चौथे चरण (ऊपर दिए गए सेक्शन में) का लॉजिक बनाना व्यावहारिक न हो. अक्सर, इनमें से कई नेटवर्क सेवाओं में पहले से ही अपनी पुष्टि करने के लिए क्लाइंट सर्टिफ़िकेट की ज़रूरत होती है (उदाहरण के लिए, ईएपी-टीएलएस या म्युचुअल TLS इंट्रानेट पेज). इसलिए, अगर एंटरप्राइज़ सर्टिफ़िकेट इन क्लाइंट सर्टिफ़िकेट को जारी करने वाली संस्था, दो से चौथे चरण लागू कर सकती है और चैलेंज रिस्पॉन्स पुष्टि के लिए क्लाइंट सर्टिफ़िकेट जारी कर सकती है, तो सर्टिफ़िकेट अपने पास होने से इस बात का सबूत मिल सकता है कि क्लाइंट असली है और कॉर्पोरेट नीति का पालन करता है. इसके बाद, हर वाई-फ़ाई ऐक्सेस पॉइंट, वीपीएन सर्वर वगैरह से इस क्लाइंट सर्टिफ़िकेट की जांच की जा सकती है. इसके लिए, दूसरे से चौथे चरण का पालन करने की ज़रूरत नहीं होती.

दूसरे शब्दों में, यहां CA (जो एंटरप्राइज़ डिवाइसों को क्लाइंट सर्टिफ़िकेट जारी करता है) पहली इमेज में नेटवर्क सर्विस की भूमिका निभाता है. उसे वेरिफ़ाइड ऐक्सेस एपीआई को शुरू करना होगा. चैलेंज पूरा होने पर ही, क्लाइंट को सर्टिफ़िकेट देगा. क्लाइंट को सर्टिफ़िकेट देना, चौथे चरण के बराबर है - पहली इमेज में, ऐक्सेस दें.

Chromebook पर सुरक्षित तरीके से क्लाइंट सर्टिफ़िकेट पाने की प्रक्रिया के बारे में इस लेख में बताया गया है. अगर इस पैराग्राफ़ में बताए गए डिज़ाइन का पालन किया जाता है, तो वेरिफ़ाइड ऐक्सेस एक्सटेंशन और क्लाइंट सर्टिफ़िकेट को शामिल करने वाले एक्सटेंशन को एक साथ जोड़ा जा सकता है. क्लाइंट सर्टिफ़िकेट ऑनबोर्डिंग एक्सटेंशन लिखने के तरीके के बारे में ज़्यादा जानें.