ปกป้องบัญชีผู้ใช้ด้วยการป้องกันแบบครอบคลุมหลายบริการ

หากแอปของคุณอนุญาตให้ผู้ใช้ลงชื่อเข้าใช้บัญชีโดยใช้ Google คุณสามารถ ความปลอดภัยของผู้ใช้ที่แชร์เหล่านี้ บัญชีต่างๆ ด้วยการฟังและตอบสนอง การแจ้งเตือนการดำเนินการด้านความปลอดภัยจากบริการการป้องกันแบบครอบคลุมหลายบริการ

การแจ้งเตือนเหล่านี้จะแจ้งให้คุณทราบถึงการเปลี่ยนแปลงสำคัญในบัญชี Google ของบัญชี ซึ่งมักจะมีผลกระทบด้านความปลอดภัยกับบัญชีของผู้ใช้ด้วย แอปของคุณ ตัวอย่างเช่น ถ้าบัญชี Google ของผู้ใช้ถูกลักลอบใช้ อาจนำไปสู่การบุกรุกบัญชีของผู้ใช้พร้อมแอปของคุณผ่านทางอีเมล หรือการใช้การลงชื่อเพียงครั้งเดียว

เพื่อช่วยคุณในการลดความเสี่ยงที่จะเกิดเหตุการณ์ดังกล่าว Google จะส่ง ออบเจ็กต์บริการที่เรียกว่าโทเค็นการดำเนินการด้านความปลอดภัย โทเค็นเหล่านี้เปิดเผยน้อยมาก ข้อมูลเฉพาะประเภทการดำเนินการด้านความปลอดภัย เวลาที่เกิดปัญหา และ ของผู้ใช้ที่ได้รับผลกระทบได้ แต่คุณสามารถ ใช้ข้อมูลนี้เพื่อ ดำเนินการที่เหมาะสมในการตอบกลับ เช่น หากบัญชี Google ของผู้ใช้ถูก คุณอาจปิดใช้ฟีเจอร์ลงชื่อเข้าใช้ด้วย Google ชั่วคราวสำหรับผู้ใช้รายนั้น ป้องกันไม่ให้ระบบส่งอีเมลการกู้คืนบัญชีไปยังที่อยู่ Gmail ของผู้ใช้

การป้องกันแบบครอบคลุมหลายบริการจะอิงตาม มาตรฐาน RISC ซึ่งพัฒนาขึ้นที่ รากฐานของ OpenID

ภาพรวม

หากต้องการใช้การป้องกันแบบครอบคลุมหลายบริการกับแอปหรือบริการ คุณต้องดําเนินการตาม งานต่อไปนี้:

  1. ตั้งค่าโปรเจ็กต์ใน API Console

  2. สร้างปลายทางตัวรับเหตุการณ์ซึ่ง Google จะส่งการดำเนินการด้านความปลอดภัยไปให้ โทเค็น ปลายทางนี้มีหน้าที่ตรวจสอบความถูกต้องของโทเค็นที่ได้รับ และตอบสนองต่อการดำเนินการด้านความปลอดภัยด้วยวิธีใดก็ตามที่คุณเลือก

  3. ลงทะเบียนปลายทางกับ Google เพื่อเริ่มรับโทเค็นการดำเนินการด้านความปลอดภัย

วิชาบังคับก่อน

คุณจะได้รับเฉพาะโทเค็นการดำเนินการด้านความปลอดภัยสําหรับผู้ใช้ Google ที่ให้สิทธิ์ สำหรับบริการเข้าถึงข้อมูลโปรไฟล์หรือที่อยู่อีเมล คุณ รับสิทธิ์นี้โดยขอขอบเขต profile หรือ email ใหม่ ลงชื่อเข้าใช้ด้วย Google หรือเวอร์ชันเดิม SDK ของ Google Sign-In จะขอขอบเขตเหล่านี้โดยค่าเริ่มต้น แต่ หากไม่ได้ใช้การตั้งค่าเริ่มต้น หรือหากคุณเข้าถึง OpenID ของ Google เชื่อมต่อปลายทางโดยตรง ตรวจสอบว่า คุณกำลังขอขอบเขตเหล่านี้อย่างน้อย 1 รายการ

ตั้งค่าโปรเจ็กต์ใน API Console

ก่อนจะเริ่มรับโทเค็นการดำเนินการด้านความปลอดภัย คุณต้องสร้างบริการ และเปิดใช้ RISC API ในบัญชี API Console โปรเจ็กต์ คุณต้องใช้ API Console โปรเจ็กต์ที่คุณใช้เข้าถึง บริการของ Google เช่น Google Sign-In ในแอป

วิธีสร้างบัญชีบริการ

  1. เปิดAPI Console Credentials page เมื่อมีข้อความแจ้ง ให้เลือก API Console โปรเจ็กต์ที่คุณใช้เพื่อเข้าถึงบริการของ Google ในแอป

  2. คลิกสร้างข้อมูลเข้าสู่ระบบ > บัญชีบริการ

  3. สร้างบัญชีบริการใหม่ที่มีบทบาทผู้ดูแลระบบการกำหนดค่า RISC (roles/riscconfigs.admin) โดยการติดตาม วิธีการเหล่านี้

  4. สร้างคีย์สำหรับบัญชีบริการที่สร้างใหม่ เลือกคีย์ JSON แล้วคลิกสร้าง เมื่อสร้างคีย์แล้ว คุณจะดาวน์โหลดไฟล์ JSON ที่มีบัญชีบริการของคุณ ข้อมูลเข้าสู่ระบบ เก็บไฟล์นี้ไว้ในที่ปลอดภัย แต่ อุปกรณ์รับเหตุการณ์

ขณะอยู่ในหน้าข้อมูลเข้าสู่ระบบของโปรเจ็กต์ ให้สังเกตไคลเอ็นต์ด้วย รหัสที่คุณใช้สําหรับฟีเจอร์ลงชื่อเข้าใช้ด้วย Google หรือ Google Sign-In (เดิม) โดยทั่วไป คุณจะมีรหัสไคลเอ็นต์สำหรับ แพลตฟอร์มที่รองรับของคุณ คุณจะต้องใช้รหัสไคลเอ็นต์เหล่านี้เพื่อตรวจสอบการดำเนินการด้านความปลอดภัย ตามที่อธิบายไว้ในส่วนถัดไป

วิธีเปิดใช้ RISC API

  1. เปิดหน้า RISC API ใน API Consoleตรวจสอบว่าโปรเจ็กต์ที่คุณใช้ ยังคงเลือกเพื่อเข้าถึงบริการของ Google

  2. อ่านข้อกำหนดของ RISC และตรวจสอบว่าคุณเข้าใจข้อกำหนดดังกล่าว

    หากคุณเปิดใช้ API สำหรับโปรเจ็กต์ขององค์กร โปรดตรวจสอบว่า คุณได้รับอนุญาตให้ผูกพันองค์กรของคุณกับข้อกำหนดของ RISC

  3. คลิกเปิดใช้ก็ต่อเมื่อคุณยอมรับข้อกำหนดของ RISC เท่านั้น

สร้างปลายทางตัวรับเหตุการณ์

หากต้องการรับการแจ้งเตือนการดำเนินการด้านความปลอดภัยจาก Google คุณต้องสร้างปลายทาง HTTPS ที่จัดการคำขอ HTTPS POST ได้ หลังจากลงทะเบียนอุปกรณ์ปลายทางนี้แล้ว (ดูด้านล่าง) Google จะเริ่มโพสต์สตริงที่เข้ารหัสแบบเข้ารหัสที่เรียกว่าการดำเนินการด้านความปลอดภัย โทเค็นไปยังปลายทาง โทเค็นการดำเนินการด้านความปลอดภัยคือ JWT ที่ลงนามแล้วที่มี ข้อมูลเกี่ยวกับเหตุการณ์ด้านความปลอดภัยรายการเดียว

สำหรับโทเค็นการดำเนินการด้านความปลอดภัยแต่ละรายการที่คุณได้รับที่ปลายทาง ให้ตรวจสอบและ ถอดรหัสโทเค็น แล้วจัดการการดำเนินการด้านความปลอดภัยตามความเหมาะสมสำหรับ service. คุณจําเป็นต้องตรวจสอบโทเค็นเหตุการณ์ก่อนถอดรหัสเพื่อป้องกัน การโจมตีที่เป็นอันตรายจากผู้ไม่ประสงค์ดี ส่วนต่อไปนี้จะอธิบายงานเหล่านี้

1. ถอดรหัสและตรวจสอบโทเค็นเหตุการณ์ด้านความปลอดภัย

เนื่องจากโทเค็นการดำเนินการด้านความปลอดภัยเป็น JWT ประเภทหนึ่ง คุณจึงใช้ ไลบรารี JWT เช่น ที่แสดงอยู่ใน jwt.io เพื่อถอดรหัสและ เพื่อทำการตรวจสอบ ไม่ว่าจะใช้ไลบรารีไหน โค้ดตรวจสอบโทเค็นของคุณก็จะมีหน้าที่ ดังต่อไปนี้:

  1. รับตัวระบุผู้ออกการป้องกันแบบครอบคลุมหลายบริการ (issuer) และคีย์การรับรอง URI ใบรับรอง (jwks_uri) จากเอกสารการกำหนดค่า RISC ของ Google ซึ่งอยู่ที่ https://accounts.google.com/.well-known/risc-configuration
  2. รับรหัสคีย์การลงชื่อจากส่วนหัวโดยใช้ไลบรารี JWT ที่คุณเลือก โทเค็นการดำเนินการด้านความปลอดภัย
  3. จากเอกสารใบรับรองคีย์การลงชื่อของ Google ให้ใช้คีย์สาธารณะที่มี รหัสคีย์ที่คุณได้รับในขั้นตอนก่อนหน้า หากเอกสารไม่มีคีย์ ด้วยรหัสที่คุณต้องการ อาจเป็นไปได้ว่าโทเค็นการดำเนินการด้านความปลอดภัย ไม่ถูกต้อง และปลายทางควรแสดงผลข้อผิดพลาด HTTP 400
  4. ตรวจสอบรายการต่อไปนี้โดยใช้ไลบรารี JWT ที่คุณเลือก
    • โทเค็นการดำเนินการด้านความปลอดภัยจะมีการลงชื่อโดยใช้คีย์สาธารณะที่คุณได้รับใน ขั้นตอนก่อนหน้า
    • การอ้างสิทธิ์ aud ของโทเค็นเป็นหนึ่งในแอปของคุณ Client-ID
    • การอ้างสิทธิ์ iss ของโทเค็นตรงกับตัวระบุผู้ออกบัตรที่คุณได้รับ เอกสารการค้นพบ RISC โปรดทราบว่าคุณไม่จำเป็นต้องยืนยันวันหมดอายุของโทเค็น (exp) เนื่องจาก โทเค็นเหตุการณ์ด้านความปลอดภัยแสดงถึงเหตุการณ์ในอดีต ดังนั้นจึงไม่มีวันหมดอายุ

เช่น

Java

การใช้ java-jwt และ jwks-rsa-java

public DecodedJWT validateSecurityEventToken(String token) {
    DecodedJWT jwt = null;
    try {
        // In a real implementation, get these values from
        // https://accounts.google.com/.well-known/risc-configuration
        String issuer = "accounts.google.com";
        String jwksUri = "https://www.googleapis.com/oauth2/v3/certs";

        // Get the ID of the key used to sign the token.
        DecodedJWT unverifiedJwt = JWT.decode(token);
        String keyId = unverifiedJwt.getKeyId();

        // Get the public key from Google.
        JwkProvider googleCerts = new UrlJwkProvider(new URL(jwksUri), null, null);
        PublicKey publicKey = googleCerts.get(keyId).getPublicKey();

        // Verify and decode the token.
        Algorithm rsa = Algorithm.RSA256((RSAPublicKey) publicKey, null);
        JWTVerifier verifier = JWT.require(rsa)
                .withIssuer(issuer)
                // Get your apps' client IDs from the API console:
                // https://console.developers.google.com/apis/credentials?project=_
                .withAudience("123456789-abcedfgh.apps.googleusercontent.com",
                              "123456789-ijklmnop.apps.googleusercontent.com",
                              "123456789-qrstuvwx.apps.googleusercontent.com")
                .acceptLeeway(Long.MAX_VALUE)  // Don't check for expiration.
                .build();
        jwt = verifier.verify(token);
    } catch (JwkException e) {
        // Key not found. Return HTTP 400.
    } catch (InvalidClaimException e) {

    } catch (JWTDecodeException exception) {
        // Malformed token. Return HTTP 400.
    } catch (MalformedURLException e) {
        // Invalid JWKS URI.
    }
    return jwt;
}

Python

import json
import jwt       # pip install pyjwt
import requests  # pip install requests

def validate_security_token(token, client_ids):
    # Get Google's RISC configuration.
    risc_config_uri = 'https://accounts.google.com/.well-known/risc-configuration'
    risc_config = requests.get(risc_config_uri).json()

    # Get the public key used to sign the token.
    google_certs = requests.get(risc_config['jwks_uri']).json()
    jwt_header = jwt.get_unverified_header(token)
    key_id = jwt_header['kid']
    public_key = None
    for key in google_certs['keys']:
        if key['kid'] == key_id:
            public_key = jwt.algorithms.RSAAlgorithm.from_jwk(json.dumps(key))
    if not public_key:
        raise Exception('Public key certificate not found.')
        # In this situation, return HTTP 400

    # Decode the token, validating its signature, audience, and issuer.
    try:
        token_data = jwt.decode(token, public_key, algorithms='RS256',
                                options={'verify_exp': False},
                                audience=client_ids, issuer=risc_config['issuer'])
    except:
        raise
        # Validation failed. Return HTTP 400.
    return token_data

# Get your apps' client IDs from the API console:
# https://console.developers.google.com/apis/credentials?project=_
client_ids = ['123456789-abcedfgh.apps.googleusercontent.com',
              '123456789-ijklmnop.apps.googleusercontent.com',
              '123456789-qrstuvwx.apps.googleusercontent.com']
token_data = validate_security_token(token, client_ids)

หากโทเค็นถูกต้องและถอดรหัสสำเร็จแล้ว ให้แสดงสถานะ HTTP 202 จากนั้น ให้จัดการการดำเนินการด้านความปลอดภัยที่ระบุโดยโทเค็น

2. จัดการการดำเนินการด้านความปลอดภัย

เมื่อถอดรหัสแล้ว โทเค็นการดำเนินการด้านความปลอดภัยจะมีลักษณะดังนี้

{
  "iss": "https://accounts.google.com/",
  "aud": "123456789-abcedfgh.apps.googleusercontent.com",
  "iat": 1508184845,
  "jti": "756E69717565206964656E746966696572",
  "events": {
    "https://schemas.openid.net/secevent/risc/event-type/account-disabled": {
      "subject": {
        "subject_type": "iss-sub",
        "iss": "https://accounts.google.com/",
        "sub": "7375626A656374"
      },
      "reason": "hijacking"
    }
  }
}

การอ้างสิทธิ์ iss และ aud ระบุผู้ออกโทเค็น (Google) และ ผู้รับโทเค็นที่ต้องการ (บริการของคุณ) คุณได้ยืนยันการอ้างสิทธิ์เหล่านี้ใน ขั้นตอนก่อนหน้า

การอ้างสิทธิ์ jti เป็นสตริงที่ระบุการดำเนินการด้านความปลอดภัยรายการเดียว และ ไปยังสตรีมนั้นโดยเฉพาะ คุณใช้ตัวระบุนี้เพื่อติดตามการดำเนินการด้านความปลอดภัยได้ ที่คุณได้รับ

การอ้างสิทธิ์ events มีข้อมูลเกี่ยวกับการดำเนินการด้านความปลอดภัยที่โทเค็น เป็นตัวแทน การอ้างสิทธิ์นี้เป็นการแมปจากตัวระบุประเภทเหตุการณ์กับ subject การอ้างสิทธิ์ ซึ่งระบุข้อกังวลถึงเหตุการณ์นี้ของผู้ใช้ รวมถึงข้อกังวลอื่นๆ รายละเอียดของกิจกรรมที่อาจใช้ได้

การอ้างสิทธิ์ subject ระบุผู้ใช้รายหนึ่งด้วย Google ที่ไม่ซ้ำกันของผู้ใช้ รหัสบัญชี (sub) รหัสบัญชี Google นี้เป็นตัวระบุเดียวกับ (sub) ที่มีอยู่ ในโทเค็นรหัส JWT ที่ออกโดยฟีเจอร์ลงชื่อเข้าใช้ด้วย Google รุ่นใหม่ (JavaScript , HTML) ไลบรารี Google Sign-in เดิม หรือ OpenID Connect เมื่อ subject_type ของ การอ้างสิทธิ์เป็น id_token_claims ยังอาจรวมช่อง email ที่มีฟิลด์ อีเมลของผู้ใช้

ใช้ข้อมูลในการอ้างสิทธิ์ events ในการดำเนินการที่เหมาะสมกับ ประเภทเหตุการณ์ในบัญชีผู้ใช้ที่ระบุ

ตัวระบุโทเค็น OAuth

สำหรับกิจกรรม OAuth เกี่ยวกับโทเค็นแต่ละรายการ ประเภทตัวระบุหัวเรื่องโทเค็นจะมีช่องต่อไปนี้

  • token_type: รองรับ refresh_token เท่านั้น

  • token_identifier_alg: ดูตารางด้านล่างสำหรับค่าที่เป็นไปได้

  • token: ดูตารางด้านล่าง

token_identifier_alg โทเค็น
prefix อักขระ 16 ตัวแรกของโทเค็น
hash_base64_sha512_sha512 แฮชคู่ของโทเค็นที่ใช้ SHA-512

หากผสานรวมกับเหตุการณ์เหล่านี้ ขอแนะนำให้จัดทำดัชนีโทเค็นตาม กับค่าที่เป็นไปได้เหล่านี้เพื่อให้แน่ใจว่าจะได้รับการจับคู่อย่างรวดเร็วเมื่อได้รับเหตุการณ์

ประเภทเหตุการณ์ที่รองรับ

การป้องกันแบบครอบคลุมหลายบริการรองรับการดำเนินการด้านความปลอดภัยในประเภทต่อไปนี้

ประเภทเหตุการณ์ แอตทริบิวต์ วิธีตอบกลับ
https://schemas.openid.net/secevent/risc/event-type/sessions-revoked จำเป็น: รักษาความปลอดภัยให้บัญชีผู้ใช้อีกครั้งโดยสิ้นสุดการใช้งานปัจจุบัน เซสชันแบบเปิด
https://schemas.openid.net/secevent/oauth/event-type/tokens-revoked

ต้องระบุ: หากโทเค็นมีไว้สำหรับ Google Sign-In ให้สิ้นสุด เซสชันที่เปิดอยู่ในขณะนี้ นอกจากนี้ คุณอาจต้องการแนะนำให้ผู้ใช้ ตั้งค่าวิธีการลงชื่อเข้าใช้แบบอื่น

แนะนำ: หากโทเค็นมีไว้สำหรับเข้าถึง API อื่นๆ ของ Google ให้ลบ โทเค็น OAuth ของผู้ใช้ที่คุณจัดเก็บไว้

https://schemas.openid.net/secevent/oauth/event-type/token-revoked โปรดดูส่วนตัวระบุโทเค็น OAuth สำหรับ ตัวระบุโทเค็น

ต้องระบุ: หากคุณจัดเก็บโทเค็นการรีเฟรชที่เกี่ยวข้องไว้ ให้ลบออก และขอให้ผู้ใช้ให้ความยินยอมอีกครั้งในครั้งต่อไปที่ต้องใช้โทเค็นเพื่อการเข้าถึง

https://schemas.openid.net/secevent/risc/event-type/account-disabled reason=hijacking,
reason=bulk-account

ต้องระบุ: หากเหตุผลที่บัญชีถูกปิดใช้คือ hijacking ปกป้องบัญชีของผู้ใช้ให้ปลอดภัยอีกครั้งโดยสิ้นสุดการใช้งาน เซสชันที่เปิดอยู่ในขณะนี้

แนะนำ: หากเหตุผลที่บัญชีถูกปิดใช้คือ bulk-account วิเคราะห์กิจกรรมของผู้ใช้ในบริการของคุณและ พิจารณาการดำเนินการติดตามผลที่เหมาะสม

แนะนำ: หากไม่ได้ให้เหตุผลไว้ ให้ปิด Google Sign-In สำหรับ และปิดใช้การกู้คืนบัญชีโดยใช้อีเมลที่เชื่อมโยงกับ บัญชี Google ของผู้ใช้ (แต่โดยทั่วไปจะไม่ใช่บัญชี Gmail เสมอไป) เสนอวิธีการลงชื่อเข้าใช้แบบอื่นให้แก่ผู้ใช้

https://schemas.openid.net/secevent/risc/event-type/account-enabled แนะนำ: เปิดใช้ Google Sign-In สำหรับผู้ใช้อีกครั้งแล้วเปิดใช้ใหม่ กู้คืนบัญชีด้วยอีเมลบัญชี Google ของผู้ใช้
https://schemas.openid.net/secevent/risc/event-type/account-credential-change-required แนะนำ: มองหากิจกรรมที่น่าสงสัยในบริการของคุณและใช้เวลา การดำเนินการที่เหมาะสม
https://schemas.openid.net/secevent/risc/event-type/verification state=state แนะนำ: บันทึกว่าได้รับโทเค็นทดสอบแล้ว

กิจกรรมที่ซ้ำและพลาด

การป้องกันแบบครอบคลุมหลายบริการจะพยายามส่งเหตุการณ์ที่เชื่อว่ามี ยังไม่ได้จัดส่ง ดังนั้น บางครั้งคุณอาจได้รับเหตุการณ์เดียวกัน หลายครั้ง หากการทำเช่นนี้อาจทำให้เกิดการดำเนินการซ้ำๆ ซึ่งทำให้ลูกค้า ให้พิจารณาใช้การอ้างสิทธิ์ jti (ซึ่งเป็นตัวระบุที่ไม่ซ้ำสำหรับ เหตุการณ์) เพื่อยกเลิกการทำซ้ำเหตุการณ์ มีเครื่องมือภายนอก เช่น Google Cloud Dataflow ที่อาจช่วยให้คุณดำเนินการ สำหรับขจัดการซ้ำซ้อน

โปรดทราบว่าระบบจะส่งกิจกรรมโดยลองใหม่แบบจำกัด ดังนั้นหากผู้รับของคุณไม่ทำงาน คุณอาจพลาดบางกิจกรรมไปอย่างถาวรเป็นระยะเวลาหนึ่ง

ลงทะเบียนผู้รับ

หากต้องการเริ่มรับการดำเนินการด้านความปลอดภัย ให้ลงทะเบียนอุปกรณ์ปลายทางโดยใช้ RISC API การเรียกใช้ RISC API ต้องมีโทเค็นการให้สิทธิ์

คุณจะได้รับการดำเนินการด้านความปลอดภัยสำหรับผู้ใช้แอปเท่านั้น คุณจึงต้องกำหนดค่าหน้าจอขอความยินยอม OAuth ในโปรเจ็กต์ GCP เป็นข้อกำหนดเบื้องต้นสำหรับขั้นตอนที่อธิบายไว้ด้านล่าง

1. สร้างโทเค็นการให้สิทธิ์

ในการสร้างโทเค็นการให้สิทธิ์สำหรับ RISC API ให้สร้าง JWT ที่มีพารามิเตอร์ การอ้างสิทธิ์ต่อไปนี้

{
  "iss": SERVICE_ACCOUNT_EMAIL,
  "sub": SERVICE_ACCOUNT_EMAIL,
  "aud": "https://risc.googleapis.com/google.identity.risc.v1beta.RiscManagementService",
  "iat": CURRENT_TIME,
  "exp": CURRENT_TIME + 3600
}

ลงชื่อ JWT โดยใช้คีย์ส่วนตัวของบัญชีบริการ ซึ่งพบได้ใน ไฟล์ JSON ที่คุณดาวน์โหลดเมื่อสร้างคีย์บัญชีบริการ

เช่น

Java

การใช้ java-jwt และ ไลบรารีการตรวจสอบสิทธิ์ของ Google:

public static String makeBearerToken() {
    String token = null;
    try {
        // Get signing key and client email address.
        FileInputStream is = new FileInputStream("your-service-account-credentials.json");
        ServiceAccountCredentials credentials =
               (ServiceAccountCredentials) GoogleCredentials.fromStream(is);
        PrivateKey privateKey = credentials.getPrivateKey();
        String keyId = credentials.getPrivateKeyId();
        String clientEmail = credentials.getClientEmail();

        // Token must expire in exactly one hour.
        Date issuedAt = new Date();
        Date expiresAt = new Date(issuedAt.getTime() + 3600000);

        // Create signed token.
        Algorithm rsaKey = Algorithm.RSA256(null, (RSAPrivateKey) privateKey);
        token = JWT.create()
                .withIssuer(clientEmail)
                .withSubject(clientEmail)
                .withAudience("https://risc.googleapis.com/google.identity.risc.v1beta.RiscManagementService")
                .withIssuedAt(issuedAt)
                .withExpiresAt(expiresAt)
                .withKeyId(keyId)
                .sign(rsaKey);
    } catch (ClassCastException e) {
        // Credentials file doesn't contain a service account key.
    } catch (IOException e) {
        // Credentials file couldn't be loaded.
    }
    return token;
}

Python

import json
import time

import jwt  # pip install pyjwt

def make_bearer_token(credentials_file):
    with open(credentials_file) as service_json:
        service_account = json.load(service_json)
        issuer = service_account['client_email']
        subject = service_account['client_email']
        private_key_id = service_account['private_key_id']
        private_key = service_account['private_key']
    issued_at = int(time.time())
    expires_at = issued_at + 3600
    payload = {'iss': issuer,
               'sub': subject,
               'aud': 'https://risc.googleapis.com/google.identity.risc.v1beta.RiscManagementService',
               'iat': issued_at,
               'exp': expires_at}
    encoded = jwt.encode(payload, private_key, algorithm='RS256',
                         headers={'kid': private_key_id})
    return encoded

auth_token = make_bearer_token('your-service-account-credentials.json')

โทเค็นการให้สิทธิ์นี้สามารถใช้เพื่อเรียกใช้ API ของ RISC เป็นเวลา 1 ชั่วโมง วันและเวลา โทเค็นหมดอายุ ให้สร้างโทเค็นใหม่เพื่อเรียก RISC API ต่อไป

2. เรียกใช้ API การกำหนดค่าสตรีม RISC

เมื่อคุณมีโทเค็นการให้สิทธิ์แล้ว คุณสามารถใช้ RISC API เพื่อกำหนดค่า สตรีมการดำเนินการด้านความปลอดภัยของโปรเจ็กต์ รวมถึงการลงทะเบียนผู้รับ ปลายทาง

โดยส่งคำขอ HTTPS POST ไปยัง https://risc.googleapis.com/v1beta/stream:update การระบุอุปกรณ์รับปลายทางและประเภทของการรักษาความปลอดภัย กิจกรรมที่คุณสนใจ

POST /v1beta/stream:update HTTP/1.1
Host: risc.googleapis.com
Authorization: Bearer AUTH_TOKEN

{
  "delivery": {
    "delivery_method":
      "https://schemas.openid.net/secevent/risc/delivery-method/push",
    "url": RECEIVER_ENDPOINT
  },
  "events_requested": [
    SECURITY_EVENT_TYPES
  ]
}

เช่น

Java

public static void configureEventStream(final String receiverEndpoint,
                                        final List<String> eventsRequested,
                                        String authToken) throws IOException {
    ObjectMapper jsonMapper = new ObjectMapper();
    String streamConfig = jsonMapper.writeValueAsString(new Object() {
        public Object delivery = new Object() {
            public String delivery_method =
                    "https://schemas.openid.net/secevent/risc/delivery-method/push";
            public String url = receiverEndpoint;
        };
        public List<String> events_requested = eventsRequested;
    });

    HttpPost updateRequest = new HttpPost("https://risc.googleapis.com/v1beta/stream:update");
    updateRequest.addHeader("Content-Type", "application/json");
    updateRequest.addHeader("Authorization", "Bearer " + authToken);
    updateRequest.setEntity(new StringEntity(streamConfig));

    HttpResponse updateResponse = new DefaultHttpClient().execute(updateRequest);
    Header[] responseContentTypeHeaders = updateResponse.getHeaders("Content-Type");
    StatusLine responseStatus = updateResponse.getStatusLine();
    int statusCode = responseStatus.getStatusCode();
    HttpEntity entity = updateResponse.getEntity();
    // Now handle response
}

// ...

configureEventStream(
        "https://your-service.example.com/security-event-receiver",
        Arrays.asList(
                "https://schemas.openid.net/secevent/risc/event-type/account-credential-change-required",
                "https://schemas.openid.net/secevent/risc/event-type/account-disabled"),
        authToken);

Python

import requests

def configure_event_stream(auth_token, receiver_endpoint, events_requested):
    stream_update_endpoint = 'https://risc.googleapis.com/v1beta/stream:update'
    headers = {'Authorization': 'Bearer {}'.format(auth_token)}
    stream_cfg = {'delivery': {'delivery_method': 'https://schemas.openid.net/secevent/risc/delivery-method/push',
                               'url': receiver_endpoint},
                  'events_requested': events_requested}
    response = requests.post(stream_update_endpoint, json=stream_cfg, headers=headers)
    response.raise_for_status()  # Raise exception for unsuccessful requests

configure_event_stream(auth_token, 'https://your-service.example.com/security-event-receiver',
                       ['https://schemas.openid.net/secevent/risc/event-type/account-credential-change-required',
                        'https://schemas.openid.net/secevent/risc/event-type/account-disabled'])

หากคำขอแสดงผล HTTP 200 แสดงว่ากำหนดค่าสตรีมเหตุการณ์สำเร็จแล้ว และปลายทางของตัวรับควรเริ่มได้รับโทเค็นการดำเนินการด้านความปลอดภัย ส่วนถัดไปจะอธิบายถึงวิธีทดสอบการกำหนดค่าสตรีมและปลายทาง เพื่อยืนยันว่าทุกอย่าง ทำงานด้วยกันอย่างถูกต้อง

รับและอัปเดตการกำหนดค่าสตรีมปัจจุบัน

หากคุณต้องการแก้ไขการกำหนดค่าสตรีม ในอนาคต คุณสามารถทำได้ ดังนั้นโดยการส่งคำขอ GET ที่ได้รับอนุญาตไปยัง https://risc.googleapis.com/v1beta/stream เพื่อรับ การกำหนดค่าสตรีมปัจจุบัน โดยแก้ไขเนื้อหาการตอบสนอง แล้ว POST แก้ไขการกำหนดค่ากลับไปเป็น https://risc.googleapis.com/v1beta/stream:update ตามที่อธิบายไว้ข้างต้นแล้ว

หยุดและสตรีมเหตุการณ์ต่อ

หากต้องการหยุดสตรีมเหตุการณ์จาก Google ให้สร้าง POST ที่ได้รับอนุญาต คำขอไปยัง https://risc.googleapis.com/v1beta/stream/status:update ด้วย { "status": "disabled" } ในเนื้อหาคำขอ ขณะปิดใช้งานสตรีม Google จะไม่ส่งเหตุการณ์ ไปยังปลายทางของคุณ และจะไม่บัฟเฟอร์การดำเนินการด้านความปลอดภัยเมื่อเกิดเหตุการณ์ดังกล่าวขึ้น ถึง เปิดใช้สตรีมเหตุการณ์อีกครั้ง โพสต์ { "status": "enabled" } ไปยังปลายทางเดียวกัน

3. ไม่บังคับ: ทดสอบการกำหนดค่าสตรีม

คุณสามารถยืนยันได้ว่าการกำหนดค่าสตรีมและปลายทางผู้รับทำงานอยู่ อย่างถูกต้องโดยส่งโทเค็นการยืนยันผ่านสตรีมเหตุการณ์ โทเค็นนี้สามารถประกอบด้วยสตริงเฉพาะที่คุณสามารถใช้เพื่อยืนยันว่า ได้รับโทเค็นที่ปลายทางของคุณ หากต้องการใช้ขั้นตอนนี้ โปรด ติดตาม https://schemas.openid.net/secevent/risc/event-type/verification ประเภทเหตุการณ์เมื่อลงทะเบียนเครื่องรับ

หากต้องการขอโทเค็นการยืนยัน ให้ส่งคำขอ HTTPS POST ที่ได้รับอนุญาตไปยัง https://risc.googleapis.com/v1beta/stream:verify ในส่วนเนื้อหาของคําขอ ให้ระบุ สตริงการระบุ:

{
  "state": "ANYTHING"
}

เช่น

Java

public static void testEventStream(final String stateString,
                                   String authToken) throws IOException {
    ObjectMapper jsonMapper = new ObjectMapper();
    String json = jsonMapper.writeValueAsString(new Object() {
        public String state = stateString;
    });

    HttpPost updateRequest = new HttpPost("https://risc.googleapis.com/v1beta/stream:verify");
    updateRequest.addHeader("Content-Type", "application/json");
    updateRequest.addHeader("Authorization", "Bearer " + authToken);
    updateRequest.setEntity(new StringEntity(json));

    HttpResponse updateResponse = new DefaultHttpClient().execute(updateRequest);
    Header[] responseContentTypeHeaders = updateResponse.getHeaders("Content-Type");
    StatusLine responseStatus = updateResponse.getStatusLine();
    int statusCode = responseStatus.getStatusCode();
    HttpEntity entity = updateResponse.getEntity();
    // Now handle response
}

// ...

testEventStream("Test token requested at " + new Date().toString(), authToken);

Python

import requests
import time

def test_event_stream(auth_token, nonce):
    stream_verify_endpoint = 'https://risc.googleapis.com/v1beta/stream:verify'
    headers = {'Authorization': 'Bearer {}'.format(auth_token)}
    state = {'state': nonce}
    response = requests.post(stream_verify_endpoint, json=state, headers=headers)
    response.raise_for_status()  # Raise exception for unsuccessful requests

test_event_stream(auth_token, 'Test token requested at {}'.format(time.ctime()))

หากคำขอสำเร็จ ระบบจะส่งโทเค็นการยืนยันไปยังปลายทางที่คุณ ที่ลงทะเบียนแล้ว ตัวอย่างเช่น หากปลายทางจัดการโทเค็นการยืนยันโดย เมื่อบันทึกแล้ว คุณจะสามารถตรวจสอบบันทึกเพื่อยืนยันว่าโทเค็น ได้รับ

ข้อมูลอ้างอิงรหัสข้อผิดพลาด

RISC API อาจแสดงข้อผิดพลาดต่อไปนี้

รหัสข้อผิดพลาด ข้อความแสดงข้อผิดพลาด การดำเนินการที่แนะนำ
32 การกำหนดค่าสตรีมต้องมีช่อง $fieldname คำขอที่ส่งไปยังปลายทาง https://risc.googleapis.com/v1beta/stream:update ไม่ถูกต้องหรือไม่สามารถ แยกวิเคราะห์แล้ว โปรดระบุ $fieldname ในคำขอ
422 ไม่ได้รับอนุญาต การให้สิทธิ์ล้มเหลว อย่าลืมแนบ โทเค็นการให้สิทธิ์ พร้อมคำขอและโทเค็นถูกต้อง แต่ยังไม่หมดอายุ
32 ปลายทางการส่งต้องเป็น HTTPS URL ปลายทางการนำส่ง (เช่น ปลายทางที่คุณคาดว่าเหตุการณ์ RISC จะเป็น ไปยัง) ต้องเป็น HTTPS เราไม่ส่งเหตุการณ์ RISC ไปยัง HTTP URL
32 การกำหนดค่าสตรีมที่มีอยู่ไม่มีการนำส่งที่เป็นไปตามข้อกำหนด สำหรับ RISC โปรเจ็กต์ Google Cloud ของคุณต้องมีการกำหนดค่า RISC อยู่แล้ว ถ้า คุณใช้ Firebase และเปิดใช้ Google Sign-In อยู่ Firebase จะ จัดการ RISC สำหรับโปรเจ็กต์ของคุณ คุณจะไม่สามารถสร้างการกำหนดค่า การกำหนดค่า หากไม่ได้ใช้ Google Sign-In สําหรับโปรเจ็กต์ Firebase โปรดปิดใช้งาน แล้วลองอัปเดตอีกครั้งหลังจากผ่านไป 1 ชั่วโมง
32 ไม่พบโปรเจ็กต์ ตรวจสอบว่าคุณใช้บัญชีบริการที่ถูกต้องสำหรับ คุณอาจใช้บัญชีบริการที่เชื่อมโยงกับบัญชีที่ถูกลบ ดูข้อมูล วิธีดูบัญชีบริการทั้งหมดที่เชื่อมโยงกับโปรเจ็กต์
32 บัญชีบริการต้องการสิทธิ์เข้าถึง RISC การกำหนดค่า ไปที่โปรเจ็กต์ของคุณ API Console และ มอบหมาย "ผู้ดูแลระบบการกำหนดค่า RISC" บทบาท (roles/riscconfigs.admin) ไปยังบัญชีบริการที่เรียกใช้โปรเจ็กต์ของคุณโดย กำลังติดตาม วิธีการเหล่านี้
32 ควรเรียกใช้ API การจัดการสตรีมโดยบัญชีบริการเท่านั้น ดูข้อมูลเพิ่มเติมเกี่ยวกับ วิธีเรียกใช้ Google APIs ด้วยบัญชีบริการ
32 ปลายทางการนำส่งไม่ได้อยู่ในโดเมนใดๆ ของโปรเจ็กต์ ทุกโปรเจ็กต์จะมีชุดของ โดเมนที่ได้รับอนุญาต หากปลายทางการนำส่ง (นั่นคือปลายทางที่คาดหวังให้เหตุการณ์ RISC เกิดขึ้น ) ไม่ได้โฮสต์อยู่บนหนึ่งในนั้น คุณจำเป็นต้องเพิ่ม โดเมนของปลายทางไปยังชุดนั้น
32 หากต้องการใช้ API นี้ โปรเจ็กต์ของคุณต้องกำหนดค่าไคลเอ็นต์ OAuth อย่างน้อย 1 รายการ RISC จะใช้งานได้ก็ต่อเมื่อคุณสร้างแอปที่รองรับ Google Sign In การเชื่อมต่อนี้ต้องใช้ไคลเอ็นต์ OAuth หากโปรเจ็กต์ไม่มี OAuth ก็มีแนวโน้มที่ RISC จะไม่เป็นประโยชน์สำหรับคุณ ดูข้อมูลเพิ่มเติม เกี่ยวกับการใช้ OAuth ของ Google สำหรับ API ของเรา
32

สถานะที่ไม่รองรับ

สถานะไม่ถูกต้อง

เรารองรับเฉพาะสถานะสตรีม "enabled" และ "disabled" ในขณะนี้
404

โปรเจ็กต์ไม่มีการกำหนดค่า RISC

โปรเจ็กต์ไม่มีการกำหนดค่า RISC อยู่แล้ว ไม่สามารถอัปเดตสถานะ

เรียกใช้ปลายทาง https://risc.googleapis.com/v1beta/stream:update เพื่อสร้างการกำหนดค่าสตรีมใหม่
4XX/5XX อัปเดตสถานะไม่ได้ โปรดตรวจสอบข้อความแสดงข้อผิดพลาดโดยละเอียดเพื่อดูข้อมูลเพิ่มเติม

ขอบเขตโทเค็นเพื่อการเข้าถึง

หากคุณตัดสินใจใช้โทเค็นเพื่อการเข้าถึงในการตรวจสอบสิทธิ์กับ RISC API โทเค็นเหล่านี้ เป็นขอบเขตที่แอปพลิเคชันต้องขอ ได้แก่

ปลายทาง ขอบเขต
https://risc.googleapis.com/v1beta/stream/status https://www.googleapis.com/auth/risc.status.readonly หรือ https://www.googleapis.com/auth/risc.status.readwrite
https://risc.googleapis.com/v1beta/stream/status:update https://www.googleapis.com/auth/risc.status.readwrite
https://risc.googleapis.com/v1beta/stream https://www.googleapis.com/auth/risc.configuration.readonly หรือ https://www.googleapis.com/auth/risc.configuration.readwrite
https://risc.googleapis.com/v1beta/stream:update https://www.googleapis.com/auth/risc.configuration.readwrite
https://risc.googleapis.com/v1beta/stream:verify https://www.googleapis.com/auth/risc.verify

หากต้องการความช่วยเหลือ

ก่อนอื่น ให้ดูที่ส่วนข้อมูลอ้างอิงรหัสข้อผิดพลาด หากคุณยังคง หากมีข้อสงสัย ให้โพสต์ไว้ใน Stack Overflow โดยใช้ #SecEvents แท็ก