หากแอปของคุณอนุญาตให้ผู้ใช้ลงชื่อเข้าใช้บัญชีด้วย Google คุณสามารถปรับปรุงความปลอดภัยของบัญชีผู้ใช้ที่แชร์เหล่านี้ได้โดยการฟังและตอบสนองต่อการแจ้งเตือนเกี่ยวกับเหตุการณ์ด้านความปลอดภัยที่มาจากบริการการป้องกันแบบครอบคลุมหลายบริการ
การแจ้งเตือนเหล่านี้จะแจ้งเตือนคุณเกี่ยวกับการเปลี่ยนแปลงที่สําคัญในบัญชี Google ของผู้ใช้ ซึ่งมักจะส่งผลต่อความปลอดภัยในบัญชีของแอปด้วย เช่น การที่บัญชี Google ของผู้ใช้ถูกลักลอบใช้อาจทําให้บัญชีถูกบุกรุกจากผู้ใช้ผ่านการกู้คืนบัญชีหรือการใช้การลงชื่อเพียงครั้งเดียว
Google จะส่งออบเจ็กต์บริการที่เรียกว่าโทเค็นการรักษาความปลอดภัยเพื่อช่วยลดความเสี่ยงจากเหตุการณ์ดังกล่าว โทเค็นเหล่านี้จะเปิดเผยข้อมูลเพียงเล็กน้อยเท่านั้น ซึ่งก็คือประเภทของการดําเนินการด้านความปลอดภัยและเวลาที่เกิดปัญหา และตัวระบุของผู้ใช้ที่ได้รับผลกระทบ แต่คุณจะสามารถใช้โทเค็นเหล่านี้ในการดําเนินการที่เหมาะสมได้ เช่น ถ้าบัญชี Google ของผู้ใช้ถูกบุกรุก คุณสามารถปิดใช้ฟีเจอร์ลงชื่อเข้าใช้ด้วย Google ของผู้ใช้คนนั้นชั่วคราว และป้องกันไม่ให้ระบบส่งอีเมลการกู้คืนบัญชีไปยังที่อยู่ Gmail ของผู้ใช้
การป้องกันแบบครอบคลุมหลายบริการจะอิงตามมาตรฐาน RISC ซึ่งพัฒนาที่มูลนิธิ OpenID
ภาพรวม
หากต้องการใช้การป้องกันแบบครอบคลุมหลายบริการด้วยแอปหรือบริการ คุณจะต้องทํางานต่อไปนี้ให้เสร็จสมบูรณ์
ตั้งค่าโปรเจ็กต์ใน API Console
สร้างปลายทางเครื่องรับเหตุการณ์ที่ Google จะส่งโทเค็นการรักษาความปลอดภัย ปลายทางนี้จะรับผิดชอบในการตรวจสอบโทเค็นที่รับ จากนั้นจะตอบสนองต่อเหตุการณ์ด้านความปลอดภัยตามวิธีที่คุณเลือก
ลงทะเบียนปลายทางของคุณกับ Google เพื่อเริ่มรับโทเค็นของกิจกรรมด้านความปลอดภัย
วิชาบังคับก่อน
คุณจะได้รับโทเค็นกิจกรรมด้านความปลอดภัยสําหรับผู้ใช้ Google ที่ให้สิทธิ์แก่บริการในการเข้าถึงข้อมูลโปรไฟล์หรือที่อยู่อีเมลของตนเท่านั้น คุณได้รับสิทธิ์นี้โดยการส่งคําขอขอบเขต profile
หรือ email
SDK สําหรับ Sign In with Google หรือ Google Sign-In แบบเดิมจะขอขอบเขตเหล่านี้โดยค่าเริ่มต้น แต่หากคุณไม่ได้ใช้การตั้งค่าเริ่มต้น หรือหากคุณเข้าถึงปลายทาง OpenID Connect ของ Google โดยตรง โปรดตรวจสอบว่าคุณส่งคําขอขอบเขตเหล่านี้อย่างน้อย 1 รายการ
ตั้งค่าโครงการใน API Console
คุณต้องสร้างบัญชีบริการและเปิดใช้ RISC API ในโปรเจ็กต์API Console ก่อน จึงจะรับโทเค็นการดําเนินการด้านความปลอดภัยได้ คุณต้องใช้โปรเจ็กต์API Console เดียวกันกับที่ใช้เพื่อเข้าถึงบริการของ Google เช่น Google Sign-In ในแอป
วิธีสร้างบัญชีบริการ
เปิดAPI Console Credentials page เมื่อระบบแจ้ง ให้เลือกโปรเจ็กต์API Consoleที่คุณใช้เพื่อเข้าถึงบริการของ Google ในแอป
คลิกสร้างข้อมูลรับรอง > บัญชีบริการ
สร้างบัญชีบริการใหม่ด้วยบทบาทผู้ดูแลระบบการกําหนดค่า RISC (
roles/riscconfigs.admin
) โดยทําตาม วิธีการเหล่านี้สร้างคีย์สําหรับบัญชีบริการที่สร้างขึ้นใหม่ เลือกประเภทคีย์ JSON แล้วคลิก Create (สร้าง) เมื่อสร้างคีย์แล้ว คุณจะต้องดาวน์โหลดไฟล์ JSON ที่มีข้อมูลรับรองของบัญชีบริการ เก็บไฟล์นี้ไว้ในที่ที่ปลอดภัยแต่ยังเข้าถึงปลายทางผู้รับเหตุการณ์ได้ด้วย
ในหน้าข้อมูลรับรองของโปรเจ็กต์ โปรดจดรหัสไคลเอ็นต์ที่ใช้สําหรับลงชื่อเข้าใช้ด้วย Google หรือ Google Sign-In (เดิม) ด้วย โดยปกติแล้ว คุณจะมีรหัสไคลเอ็นต์สําหรับแต่ละแพลตฟอร์มที่คุณรองรับ คุณจะต้องใช้รหัสไคลเอ็นต์เหล่านี้ในการตรวจสอบโทเค็นการรักษาความปลอดภัย ดังที่อธิบายไว้ในส่วนถัดไป
วิธีเปิดใช้ RISC API
เปิดหน้า RISC API ในAPI Consoleตรวจสอบว่าโปรเจ็กต์ที่คุณใช้เพื่อเข้าถึงบริการของ 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 ที่ต้องการเพื่อรับรหัสคีย์การลงนามจากส่วนหัวของโทเค็นความปลอดภัย
- จากเอกสารใบรับรองคีย์การลงนามของ 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 ID ที่ออกโดยไลบรารีการลงชื่อเข้าใช้ด้วย 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 ให้สิ้นสุดเซสชันที่เปิดอยู่ในขณะนี้ นอกจากนี้ คุณอาจต้องการแนะนําให้ผู้ใช้ตั้งค่าวิธีลงชื่อเข้าใช้สํารองด้วย แนะนํา: หากโทเค็นนี้มีไว้เพื่อเข้าถึง 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 สําหรับผู้ใช้และปิดใช้การกู้คืนบัญชีโดยใช้อีเมลที่เชื่อมโยงกับบัญชี 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-purged |
แนะนํา: ลบบัญชีของผู้ใช้หรือมอบวิธีลงชื่อเข้าใช้แบบอื่นให้ผู้ใช้ | |
https://schemas.openid.net/secevent/risc/event-type/account-credential-change-required |
แนะนํา: เฝ้าระวังกิจกรรมที่น่าสงสัยในบริการและดําเนินการตามความเหมาะสม | |
https://schemas.openid.net/secevent/risc/event-type/verification |
สถานะ=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')
โทเค็นการให้สิทธิ์นี้สามารถใช้เพื่อเรียก RISC API เป็นเวลาหนึ่งชั่วโมง เมื่อโทเค็นหมดอายุ ให้สร้างโทเค็นใหม่เพื่อโทรออก RISC API ต่อไป
2. เรียก RISC Stream Configuration API
เมื่อมีโทเค็นการให้สิทธิ์แล้ว คุณจะใช้ 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
ตามที่อธิบายไว้ข้างต้น
หยุดสตรีมกิจกรรมต่อ
หากต้องการหยุดสตรีมกิจกรรมจาก 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 สามารถส่งกลับข้อผิดพลาดต่อไปนี้
รหัสข้อผิดพลาด | ข้อความแสดงข้อผิดพลาด | การดําเนินการที่แนะนํา |
---|---|---|
4,000 | การกําหนดค่าสตรีมต้องมีช่อง $fieldname | คําขอที่ส่งไปยังปลายทาง https://risc.googleapis.com/v1beta/stream:update ไม่ถูกต้องหรือแยกวิเคราะห์ไม่ได้ โปรดระบุ $fieldname ในคําขอ |
401 | ไม่ได้รับอนุญาต | การให้สิทธิ์ล้มเหลว โปรดตรวจสอบว่าคุณได้แนบ โทเค็นการให้สิทธิ์กับคําขอแล้วและโทเค็นถูกต้องและยังไม่หมดอายุ |
403 | ปลายทางการส่งต้องเป็น URL แบบ HTTPS | ปลายทางการส่ง (นั่นคือ ปลายทางที่คุณคาดว่าจะมีเหตุการณ์ 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 Console ของโครงการและมอบหมายบทบาท "ผู้ดูแลระบบการกําหนดค่า RISC" (roles/riscconfigs.admin ) ให้กับบัญชีบริการที่กําลังเรียกใช้โปรเจ็กต์โดยทําตามวิธีการเหล่านี้
|
403 | บัญชีบริการควรเรียกใช้ API การจัดการสตรีมเท่านั้น | ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีเรียก Google API ด้วยบัญชีบริการ |
403 | ปลายทางการส่งไม่ได้อยู่ในโดเมนของโครงการคุณ | ทุกโปรเจ็กต์จะมีชุดโดเมนที่ได้รับอนุญาต หากปลายทางการจัดส่ง (นั่นคือ ปลายทางที่คุณคาดว่าจะมีกิจกรรมของ RISC) ไม่ได้โฮสต์อยู่บนปลายทางใดโดเมนหนึ่ง เรากําหนดให้คุณต้องเพิ่มโดเมนของปลายทางในชุดดังกล่าว |
403 | หากต้องการใช้ API นี้ โปรเจ็กต์ของคุณต้องมีการกําหนดค่าไคลเอ็นต์ OAuth อย่างน้อย 1 รายการ | RISC จะใช้งานได้ก็ต่อเมื่อคุณสร้างแอปที่รองรับ Google Sign-In การเชื่อมต่อนี้ต้องใช้ไคลเอ็นต์ OAuth หากโปรเจ็กต์ไม่มีไคลเอ็นต์ OAuth ก็เป็นไปได้ว่า RISC จะไม่เป็นประโยชน์สําหรับคุณ ดูข้อมูลเพิ่มเติมเกี่ยวกับการใช้ OAuth ของ Google สําหรับ API ของเรา |
403 |
สถานะที่ไม่สนับสนุน สถานะไม่ถูกต้อง |
ขณะนี้เรารองรับเฉพาะสถานะสตรีม "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