หากแอปของคุณอนุญาตให้ผู้ใช้ลงชื่อเข้าใช้บัญชีโดยใช้ Google คุณสามารถเพิ่มความปลอดภัยของบัญชีผู้ใช้ที่แชร์เหล่านี้ได้โดยการฟังและตอบสนองต่อการแจ้งเตือนเหตุการณ์ด้านความปลอดภัยที่ให้บริการโดยบริการการป้องกันแบบครอบคลุมหลายบริการ
การแจ้งเตือนเหล่านี้จะแจ้งให้คุณทราบถึงการเปลี่ยนแปลงครั้งใหญ่ในบัญชี Google ของผู้ใช้ ซึ่งมักจะส่งผลต่อความปลอดภัยของบัญชีของผู้ใช้ในแอปของคุณด้วย ตัวอย่างเช่น หากบัญชี Google ของผู้ใช้ถูกลักลอบใช้ ก็อาจทำให้บัญชีของผู้ใช้ในแอปของคุณถูกบุกรุกผ่านการกู้คืนบัญชีอีเมลหรือการใช้การลงชื่อเพียงครั้งเดียว
Google จะส่งออบเจ็กต์บริการที่เรียกว่าโทเค็นการดำเนินการด้านความปลอดภัยให้คุณเพื่อช่วยลดความเสี่ยงที่อาจเกิดขึ้นจากเหตุการณ์ดังกล่าว โทเค็นเหล่านี้จะแสดงข้อมูลเพียงเล็กน้อยเท่านั้น ซึ่งได้แก่ ประเภทของการดำเนินการด้านความปลอดภัยและเวลาที่เกิดเหตุการณ์ รวมถึงตัวระบุของผู้ใช้ที่ได้รับผลกระทบ แต่คุณสามารถใช้โทเค็นเหล่านี้เพื่อดำเนินการตอบสนองที่เหมาะสมได้ ตัวอย่างเช่น หากบัญชี Google ของผู้ใช้ถูกบุกรุก คุณสามารถปิดใช้ฟีเจอร์ลงชื่อเข้าใช้ด้วย Google สำหรับผู้ใช้รายนั้นชั่วคราว และป้องกันไม่ให้ระบบส่งอีเมลสำหรับการกู้คืนบัญชีไปยังอีเมล Gmail ของผู้ใช้
การป้องกันแบบครอบคลุมหลายบริการอิงตามมาตรฐาน RISC ซึ่งพัฒนาขึ้นที่มูลนิธิ OpenID
ภาพรวม
หากต้องการใช้การป้องกันแบบครอบคลุมหลายบริการกับแอปหรือบริการ คุณต้องดำเนินการต่อไปนี้ให้เสร็จสมบูรณ์
ตั้งค่าโปรเจ็กต์ในคอนโซล API
สร้างปลายทางของผู้รับเหตุการณ์ที่ Google จะส่งโทเค็นการดำเนินการด้านความปลอดภัยไปให้ ปลายทางนี้มีหน้าที่ตรวจสอบโทเค็นที่ได้รับ แล้วตอบสนองต่อการดำเนินการด้านความปลอดภัยในแบบที่คุณเลือก
ลงทะเบียนปลายทางกับ Google เพื่อเริ่มรับโทเค็นการดำเนินการด้านความปลอดภัย
วิชาบังคับก่อน
คุณจะได้รับโทเค็นการดำเนินการด้านความปลอดภัยสำหรับผู้ใช้ Google ที่ให้สิทธิ์บริการของคุณเข้าถึงข้อมูลโปรไฟล์หรืออีเมลเท่านั้น คุณจะได้รับสิทธิ์นี้โดยการขอขอบเขต profile หรือ email SDK ลงชื่อเข้าใช้ด้วย Google เวอร์ชันใหม่กว่าหรือ Google Sign-In เวอร์ชันเดิมจะขอขอบเขตเหล่านี้โดยค่าเริ่มต้น แต่หากคุณไม่ได้ใช้การตั้งค่าเริ่มต้น หรือหากคุณเข้าถึงปลายทาง OpenID Connect ของ Google โดยตรง โปรดตรวจสอบว่าคุณขอขอบเขตเหล่านี้อย่างน้อย 1 ขอบเขต
ตั้งค่าโปรเจ็กต์ในคอนโซล API
ก่อนที่จะเริ่มรับโทเค็นการดำเนินการด้านความปลอดภัย คุณต้องสร้างบัญชีบริการและเปิดใช้ RISC API ในโปรเจ็กต์คอนโซล API คุณต้องใช้โปรเจ็กต์คอนโซล API เดียวกันกับที่ใช้เข้าถึงบริการของ Google เช่น Google Sign-In ในแอป
วิธีสร้างบัญชีบริการมีดังนี้
เปิดหน้าข้อมูลเข้าสู่ระบบของคอนโซล API เมื่อได้รับข้อความแจ้ง ให้เลือกโปรเจ็กต์คอนโซล API ที่คุณใช้เพื่อเข้าถึงบริการของ Google ในแอป
คลิกสร้างข้อมูลเข้าสู่ระบบ > บัญชีบริการ
สร้างบัญชีบริการใหม่ที่มีบทบาทผู้ดูแลระบบการกำหนดค่า RISC (
roles/riscconfigs.admin) โดยทำตามวิธีการเหล่านี้(ไม่บังคับ) หากองค์กร Google Cloud ของคุณอนุญาตให้สร้างคีย์บัญชีบริการและคุณวางแผนที่จะลงชื่อ JWT ในเครื่อง ให้สร้างคีย์สำหรับบัญชีบริการที่สร้างขึ้นใหม่ เลือกประเภทคีย์ JSON แล้วคลิกสร้าง เมื่อสร้างคีย์แล้ว คุณจะดาวน์โหลดไฟล์ JSON ที่มีข้อมูลเข้าสู่ระบบของบัญชีบริการ เก็บไฟล์นี้ไว้ในที่ปลอดภัย แต่ก็ต้องเข้าถึงได้จากปลายทางตัวรับเหตุการณ์ด้วย
ขณะอยู่ในหน้าข้อมูลเข้าสู่ระบบของโปรเจ็กต์ ให้จดบันทึกรหัสไคลเอ็นต์ที่คุณใช้สําหรับฟีเจอร์ลงชื่อเข้าใช้ด้วย Google หรือ Google Sign-In (เดิม) ด้วย โดยปกติแล้ว คุณจะมีรหัสไคลเอ็นต์สำหรับแต่ละแพลตฟอร์มที่รองรับ คุณจะต้องใช้รหัสไคลเอ็นต์เหล่านี้เพื่อตรวจสอบโทเค็นการดำเนินการด้านความปลอดภัยตามที่อธิบายไว้ในส่วนถัดไป
วิธีเปิดใช้ RISC API
เปิดหน้า RISC API ในคอนโซล API ตรวจสอบว่ายังคงเลือกโปรเจ็กต์ที่คุณใช้เพื่อเข้าถึงบริการของ Google อยู่
อ่านข้อกำหนดของ RISC และทำความเข้าใจข้อกำหนด
หากคุณเปิดใช้ API สำหรับโปรเจ็กต์ที่องค์กรเป็นเจ้าของ โปรดตรวจสอบว่าคุณได้รับอนุญาตให้ผูกองค์กรกับข้อกำหนดของ RISC
คลิกเปิดใช้เฉพาะในกรณีที่คุณยินยอมตามข้อกำหนดของ RISC
สร้างปลายทางของตัวรับเหตุการณ์
หากต้องการรับการแจ้งเตือนการดำเนินการด้านความปลอดภัยจาก Google คุณต้องสร้างปลายทาง HTTPS ที่จัดการคำขอ HTTPS POST หลังจากลงทะเบียนปลายทางนี้ (ดูด้านล่าง) Google จะเริ่มโพสต์สตริงที่ลงนามด้วยการเข้ารหัสลับซึ่งเรียกว่าโทเค็นการดำเนินการด้านความปลอดภัยไปยังปลายทาง โทเค็นการดำเนินการด้านความปลอดภัยคือ JWT ที่ลงชื่อแล้วซึ่งมีข้อมูลเกี่ยวกับการดำเนินการด้านความปลอดภัยรายการเดียว
สำหรับโทเค็นการดำเนินการด้านความปลอดภัยแต่ละรายการที่คุณได้รับที่ปลายทาง ให้ตรวจสอบและถอดรหัสโทเค็นก่อน จากนั้นจึงจัดการการดำเนินการด้านความปลอดภัยตามความเหมาะสมสำหรับบริการของคุณ คุณจำเป็นต้องตรวจสอบโทเค็นเหตุการณ์ก่อนถอดรหัสเพื่อป้องกันการโจมตีที่เป็นอันตรายจากผู้ไม่ประสงค์ดี ส่วนต่อไปนี้จะอธิบายงานเหล่านี้
1. ถอดรหัสและตรวจสอบโทเค็นการดำเนินการด้านความปลอดภัย
เนื่องจากโทเค็นการดำเนินการด้านความปลอดภัยเป็น JWT ประเภทหนึ่ง คุณจึงใช้ไลบรารี JWT ใดก็ได้ เช่น ไลบรารีที่แสดงใน jwt.io เพื่อถอดรหัสและตรวจสอบโทเค็น ไม่ว่าคุณจะใช้ไลบรารีใด โค้ดการตรวจสอบโทเค็นต้องทำสิ่งต่อไปนี้
- รับตัวระบุผู้ออกการป้องกันแบบครอบคลุมหลายบริการ (
issuer) และ URI ใบรับรองคีย์การรับรอง (jwks_uri) จากเอกสารการกำหนดค่า RISC ของ Google ซึ่งดูได้ที่https://accounts.google.com/.well-known/risc-configuration - ใช้ไลบรารี JWT ที่คุณเลือกเพื่อรับรหัสคีย์การลงนามจากส่วนหัวของโทเค็นการดำเนินการด้านความปลอดภัย
- จากเอกสารใบรับรองคีย์ Signing ของ Google ให้รับคีย์สาธารณะที่มีรหัสคีย์ที่คุณได้รับในขั้นตอนก่อนหน้า หากเอกสารไม่มีคีย์ที่มีรหัสที่คุณต้องการ เป็นไปได้ว่าโทเค็นการดำเนินการด้านความปลอดภัยไม่ถูกต้อง และปลายทางควรแสดงข้อผิดพลาดของ HTTP 400
- ใช้ไลบรารี JWT ที่คุณเลือกเพื่อยืนยันสิ่งต่อไปนี้
- โทเค็นการดำเนินการด้านความปลอดภัยจะได้รับการลงนามโดยใช้คีย์สาธารณะที่คุณได้รับในขั้นตอนก่อนหน้า
- การอ้างสิทธิ์
audของโทเค็นเป็นรหัสไคลเอ็นต์ของแอปรายการใดรายการหนึ่งของคุณ - การอ้างสิทธิ์
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 เดิม หรือ OpenID Connect เมื่อ subject_type ของการอ้างสิทธิ์เป็น id_token_claims ก็อาจมีช่อง email ที่มีอีเมลของผู้ใช้ด้วย
ใช้ข้อมูลในการอ้างสิทธิ์ events เพื่อดำเนินการที่เหมาะสมสำหรับประเภทเหตุการณ์ในบัญชีของผู้ใช้ที่ระบุ
ตัวระบุโทเค็น OAuth
สำหรับเหตุการณ์ OAuth เกี่ยวกับโทเค็นแต่ละรายการ ประเภทตัวระบุเรื่องของโทเค็นจะมีฟิลด์ต่อไปนี้
token_type: รองรับrefresh_tokenเท่านั้นtoken_identifier_alg: ดูค่าที่เป็นไปได้ในตารางด้านล่างtoken: ดูตารางด้านล่าง
| token_identifier_alg | token |
|---|---|
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 ให้สิ้นสุดเซสชันที่เปิดอยู่ นอกจากนี้ คุณอาจต้องแนะนำให้ผู้ใช้ตั้งค่าวิธีการลงชื่อเข้าใช้สำรอง แนะนำ: หากโทเค็นมีไว้เพื่อเข้าถึง Google API อื่นๆ ให้ลบโทเค็น 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 |
จำเป็น: หากสาเหตุที่ปิดใช้บัญชีคือ แนะนำ: หากสาเหตุที่ปิดใช้บัญชีคือ แนะนำ: หากไม่มีการระบุเหตุผล ให้ปิดใช้ 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 ที่อาจช่วยคุณดำเนินการ Dataflow ที่กรองข้อมูลที่ซ้ำกันออกได้
โปรดทราบว่าระบบจะส่งเหตุการณ์โดยมีการลองใหม่แบบจำกัด ดังนั้นหากตัวรับสัญญาณหยุดทำงานเป็นเวลานาน คุณอาจพลาดบางเหตุการณ์อย่างถาวร
ลงทะเบียนเครื่องรับ
หากต้องการเริ่มรับการดำเนินการด้านความปลอดภัย ให้ลงทะเบียนปลายทางของผู้รับโดยใช้ RISC API การเรียกใช้ RISC API ต้องมาพร้อมกับโทเค็นการให้สิทธิ์
คุณจะได้รับการดำเนินการด้านความปลอดภัยสำหรับผู้ใช้แอปเท่านั้น ดังนั้นคุณจึงต้องกำหนดค่าหน้าจอขอความยินยอม OAuth ในโปรเจ็กต์ GCP เป็นข้อกำหนดเบื้องต้นสำหรับขั้นตอนที่อธิบายไว้ด้านล่าง
1. สร้างโทเค็นการให้สิทธิ์
คุณสามารถสร้างโทเค็นการให้สิทธิ์สำหรับ RISC API ได้โดยใช้ Google Cloud CLI (gcloud) ที่มีการแอบอ้างเป็นบัญชีบริการ (แนะนำเมื่อมีการบังคับใช้ iam.disableServiceAccountKeyCreation หรือสำหรับการตั้งค่า CLI แบบครั้งเดียว) หรือโดยการลงนาม JWT ในเครื่องด้วยคีย์ส่วนตัวของบัญชีบริการ
ตัวเลือก ก: สร้างโทเค็นเพื่อการเข้าถึงที่มีอายุสั้นโดยใช้ gcloud (ไม่ต้องใช้คีย์ JSON)
หากบัญชีผู้ใช้มีบทบาทผู้สร้างโทเค็นบัญชีบริการ (roles/iam.serviceAccountTokenCreator) ในบัญชีบริการ คุณสามารถสร้างโทเค็นเพื่อการเข้าถึง OAuth 2.0 ที่มีอายุสั้นซึ่งมีขอบเขตการกำหนดค่า RISC ที่จำเป็นได้โดยตรงจากเทอร์มินัล ดังนี้
AUTH_TOKEN=$(gcloud auth print-access-token \
--impersonate-service-account=SERVICE_ACCOUNT_EMAIL \
--scopes=https://www.googleapis.com/auth/risc.configuration.readwrite,https://www.googleapis.com/auth/risc.verify,https://www.googleapis.com/auth/risc.status.readwrite)
ดูรายละเอียดเพิ่มเติมเกี่ยวกับขอบเขต OAuth 2.0 ที่ใช้ได้สำหรับ RISC API ได้ที่ขอบเขตของโทเค็นเพื่อการเข้าถึง
ตัวเลือก ข: สร้าง JWT ที่รับรองด้วยตนเองโดยใช้คีย์บัญชีบริการ
หรือหากต้องการสร้างโทเค็นการให้สิทธิ์ในเครื่องโดยไม่มีการส่งข้อมูลไปกลับในเครือข่าย ให้สร้าง 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')
โทเค็นการให้สิทธิ์นี้สามารถใช้เพื่อเรียก RISC API ได้เป็นเวลา 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 เพื่อรับการกำหนดค่าสตรีม
ปัจจุบัน แก้ไขเนื้อหาการตอบกลับ แล้วส่งการกำหนดค่าที่
แก้ไขกลับไปยัง https://risc.googleapis.com/v1beta/stream:update โดยใช้ POST ตามที่อธิบายไว้ข้างต้น
หยุดและกลับมาสตรีมเหตุการณ์ต่อ
หากต้องการหยุดสตรีมเหตุการณ์จาก Google ให้ส่งคำขอ POST ที่ได้รับอนุญาตไปยัง https://risc.googleapis.com/v1beta/stream/status:update โดยมี { "status": "disabled" } ในเนื้อหาคำขอ ขณะที่สตรีมปิดใช้งานอยู่ Google จะไม่ส่งเหตุการณ์ไปยังปลายทางของคุณและจะไม่บัฟเฟอร์การดำเนินการด้านความปลอดภัยเมื่อเกิดขึ้น หากต้องการเปิดใช้สตรีมเหตุการณ์อีกครั้ง ให้ส่ง POST { "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 อาจแสดงข้อผิดพลาดต่อไปนี้
| รหัสข้อผิดพลาด | ข้อความแสดงข้อผิดพลาด | การดำเนินการที่แนะนำ |
|---|---|---|
| 400 | การกำหนดค่าสตรีมต้องมีช่อง $fieldname | คำขอของคุณไปยังปลายทาง https://risc.googleapis.com/v1beta/stream:update ไม่ถูกต้องหรือแยกวิเคราะห์ไม่ได้ โปรดระบุ $fieldname ในคำขอ |
| 401 | ไม่ได้รับอนุญาต | การให้สิทธิ์ล้มเหลว ตรวจสอบว่าคุณได้แนบ โทเค็นการให้สิทธิ์มากับคำขอ และโทเค็นนั้นถูกต้องและยังไม่หมดอายุ |
| 403 | ปลายทางการนำส่งต้องเป็น HTTPS URL | ปลายทางการนำส่ง (เช่น ปลายทางที่คุณคาดว่าจะมีการนำส่งเหตุการณ์ RISC) ต้องเป็น HTTPS เราจะไม่ส่งเหตุการณ์ RISC ไปยัง HTTP URL |
| 403 | การกำหนดค่าสตรีมที่มีอยู่ไม่มีวิธีการนำส่งที่สอดคล้องกับข้อกำหนดสำหรับ RISC | โปรเจ็กต์ที่อยู่ในระบบคลาวด์ของ Google Cloud ของคุณต้องมีการกำหนดค่า RISC อยู่แล้ว หากคุณใช้ Firebase และเปิดใช้ Google Sign-In ไว้ Firebase จะจัดการ RISC สำหรับโปรเจ็กต์ของคุณ คุณจะสร้างการกำหนดค่าที่กำหนดเองไม่ได้ หากคุณไม่ได้ใช้ Google Sign-In สำหรับโปรเจ็กต์ Firebase โปรดปิดใช้ แล้วลองอัปเดตอีกครั้งหลังจากผ่านไป 1 ชั่วโมง |
| 403 | ไม่พบโปรเจ็กต์ | ตรวจสอบว่าคุณใช้บัญชีบริการที่ถูกต้องสำหรับโปรเจ็กต์ที่ถูกต้อง คุณอาจใช้บัญชีบริการที่เชื่อมโยงกับโปรเจ็กต์ที่ถูกลบ ดู วิธีดูบัญชีบริการทั้งหมดที่เชื่อมโยงกับโปรเจ็กต์ |
| 403 | บัญชีบริการต้องได้รับสิทธิ์เข้าถึงการกำหนดค่า RISC ของคุณ | ไปที่คอนโซล API ของโปรเจ็กต์และมอบหมายบทบาท "ผู้ดูแลระบบการกำหนดค่า RISC" (roles/riscconfigs.admin) ให้กับบัญชีบริการที่ทำการเรียกไปยังโปรเจ็กต์โดยทำตามวิธีการเหล่านี้
|
| 403 | ควรเรียกใช้ Management API ของสตรีมโดยบัญชีบริการเท่านั้น | ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีเรียกใช้ Google APIs ด้วยบัญชีบริการ |
| 403 | ปลายทางการนำส่งไม่ได้อยู่ในโดเมนใดๆ ของโปรเจ็กต์ | ทุกโปรเจ็กต์มีชุดโดเมนที่ได้รับอนุญาต หากปลายทางการนำส่ง (เช่น ปลายทางที่คุณคาดหวังให้นำส่งเหตุการณ์ RISC) ไม่ได้โฮสต์อยู่ในโดเมนใดโดเมนหนึ่ง คุณจะต้องเพิ่มโดเมนของปลายทางลงในชุดโดเมนดังกล่าว |
| 403 | หากต้องการใช้ API นี้ โปรเจ็กต์ของคุณต้องมีการกำหนดค่าไคลเอ็นต์ OAuth อย่างน้อย 1 รายการ | RISC จะทำงานก็ต่อเมื่อคุณสร้างแอปที่รองรับฟีเจอร์ลงชื่อเข้าใช้ด้วย Google การเชื่อมต่อนี้ต้องใช้ไคลเอ็นต์ OAuth หากโปรเจ็กต์ไม่มีไคลเอ็นต์ OAuth ก็เป็นไปได้ว่า RISC จะไม่มีประโยชน์สำหรับคุณ ดูข้อมูลเพิ่มเติมเกี่ยวกับการใช้ OAuth ของ Google สำหรับ API ของเรา |
| 403 |
สถานะที่ไม่รองรับ สถานะไม่ถูกต้อง |
ขณะนี้เรารองรับเฉพาะสถานะสตรีม "enabled" และ "disabled" เท่านั้น |
| 404 |
โปรเจ็กต์ไม่มีการกำหนดค่า RISC โปรเจ็กต์ไม่มีการกำหนดค่า RISC อยู่ จึงอัปเดตสถานะไม่ได้ |
เรียกใช้ปลายทาง https://risc.googleapis.com/v1beta/stream:update เพื่อสร้างการกำหนดค่าสตรีมใหม่ |
| 4XX/5XX | อัปเดตสถานะไม่ได้ | โปรดดูข้อมูลเพิ่มเติมในข้อความแสดงข้อผิดพลาดโดยละเอียด |
ขอบเขตโทเค็นเพื่อการเข้าถึง
หากคุณตัดสินใจใช้โทเค็นเพื่อการเข้าถึงเพื่อตรวจสอบสิทธิ์กับ RISC API ขอบเขตที่แอปพลิเคชันของคุณต้องขอมีดังนี้
| Endpoint | ขอบเขต |
|---|---|
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