or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

account-security-analysis.mdassessment-operations.mdfirewall-policies.mdindex.mdip-override-management.mdkey-management.mdmetrics-analytics.md

account-security-analysis.mddocs/

0

# Account Security Analysis

1

2

Advanced account protection features including related account group analysis, membership tracking, and search capabilities for detecting coordinated fraud attempts and abuse patterns. These capabilities help identify and mitigate sophisticated attacks that involve multiple related accounts.

3

4

## Capabilities

5

6

### List Related Account Groups

7

8

Retrieves related account groups that represent clusters of accounts with suspicious relationships, helping identify coordinated fraud attempts.

9

10

```python { .api }

11

def list_related_account_groups(

12

request: ListRelatedAccountGroupsRequest = None,

13

*,

14

parent: str = None,

15

retry: Union[retries.Retry, gapic_v1.method._MethodDefault] = _MethodDefault._DEFAULT_VALUE,

16

timeout: Union[float, object] = _MethodDefault._DEFAULT_VALUE,

17

metadata: Sequence[Tuple[str, str]] = ()

18

) -> ListRelatedAccountGroupsResponse:

19

"""

20

List groups of related accounts in a project.

21

22

Args:

23

request: The request object for listing related account groups

24

parent: Required. The name of the project in format 'projects/{project}'

25

retry: Retry configuration for the request

26

timeout: Timeout for the request in seconds

27

metadata: Additional metadata for the request

28

29

Returns:

30

ListRelatedAccountGroupsResponse: List of related account groups

31

32

Raises:

33

google.api_core.exceptions.PermissionDenied: If insufficient permissions

34

google.api_core.exceptions.InvalidArgument: If parent format is invalid

35

"""

36

```

37

38

#### Usage Example

39

40

```python

41

from google.cloud import recaptchaenterprise

42

43

client = recaptchaenterprise.RecaptchaEnterpriseServiceClient()

44

45

# List related account groups

46

request = recaptchaenterprise.ListRelatedAccountGroupsRequest(

47

parent="projects/your-project-id"

48

)

49

50

response = client.list_related_account_groups(request=request)

51

52

print("Related account groups:")

53

for group in response.related_account_groups:

54

print(f"Group: {group.name}")

55

print(f" Accounts in group: {len(group.memberships) if group.memberships else 'Unknown'}")

56

```

57

58

### List Related Account Group Memberships

59

60

Retrieves the memberships within a specific related account group, showing which accounts are connected.

61

62

```python { .api }

63

def list_related_account_group_memberships(

64

request: ListRelatedAccountGroupMembershipsRequest = None,

65

*,

66

parent: str = None,

67

retry: Union[retries.Retry, gapic_v1.method._MethodDefault] = _MethodDefault._DEFAULT_VALUE,

68

timeout: Union[float, object] = _MethodDefault._DEFAULT_VALUE,

69

metadata: Sequence[Tuple[str, str]] = ()

70

) -> ListRelatedAccountGroupMembershipsResponse:

71

"""

72

Get memberships in a related account group.

73

74

Args:

75

request: The request object for listing memberships

76

parent: Required. The group name in format 'projects/{project}/relatedaccountgroups/{group}'

77

retry: Retry configuration for the request

78

timeout: Timeout for the request in seconds

79

metadata: Additional metadata for the request

80

81

Returns:

82

ListRelatedAccountGroupMembershipsResponse: List of account memberships

83

84

Raises:

85

google.api_core.exceptions.NotFound: If the group doesn't exist

86

google.api_core.exceptions.PermissionDenied: If insufficient permissions

87

"""

88

```

89

90

### Search Related Account Group Memberships

91

92

Searches for account group memberships based on hashed account identifiers, enabling investigation of specific accounts.

93

94

```python { .api }

95

def search_related_account_group_memberships(

96

request: SearchRelatedAccountGroupMembershipsRequest = None,

97

*,

98

parent: str = None,

99

hashed_account_id: bytes = None,

100

retry: Union[retries.Retry, gapic_v1.method._MethodDefault] = _MethodDefault._DEFAULT_VALUE,

101

timeout: Union[float, object] = _MethodDefault._DEFAULT_VALUE,

102

metadata: Sequence[Tuple[str, str]] = ()

103

) -> SearchRelatedAccountGroupMembershipsResponse:

104

"""

105

Search for memberships in a related account group.

106

107

Args:

108

request: The request object for searching memberships

109

parent: Required. The project name in format 'projects/{project}'

110

hashed_account_id: Required. Hashed account identifier to search for

111

retry: Retry configuration for the request

112

timeout: Timeout for the request in seconds

113

metadata: Additional metadata for the request

114

115

Returns:

116

SearchRelatedAccountGroupMembershipsResponse: Search results

117

118

Raises:

119

google.api_core.exceptions.InvalidArgument: If search parameters are invalid

120

google.api_core.exceptions.PermissionDenied: If insufficient permissions

121

"""

122

```

123

124

#### Usage Example

125

126

```python

127

import hashlib

128

129

# Hash account identifier for search

130

account_id = "user123@example.com"

131

hashed_account_id = hashlib.sha256(account_id.encode()).digest()

132

133

# Search for related accounts

134

search_request = recaptchaenterprise.SearchRelatedAccountGroupMembershipsRequest(

135

parent="projects/your-project-id",

136

hashed_account_id=hashed_account_id

137

)

138

139

search_response = client.search_related_account_group_memberships(request=search_request)

140

141

print(f"Found {len(search_response.related_account_group_memberships)} related accounts")

142

for membership in search_response.related_account_group_memberships:

143

print(f"Group: {membership.name}")

144

print(f"Account: {membership.hashed_account_id.hex()}")

145

```

146

147

## Request and Response Types

148

149

### RelatedAccountGroup

150

151

```python { .api }

152

class RelatedAccountGroup:

153

"""Group of related user accounts."""

154

name: str # Output only. Resource name

155

memberships: List[RelatedAccountGroupMembership] # Account memberships in group

156

```

157

158

### RelatedAccountGroupMembership

159

160

```python { .api }

161

class RelatedAccountGroupMembership:

162

"""Membership in a related account group."""

163

name: str # Output only. Resource name

164

hashed_account_id: bytes # Hashed account identifier

165

account_id: str # Output only. Account identifier (if available)

166

```

167

168

### Request Types

169

170

```python { .api }

171

class ListRelatedAccountGroupsRequest:

172

"""Request message for listing related account groups."""

173

parent: str # Required. Project name in format 'projects/{project}'

174

page_size: int # Optional. Maximum results per page

175

page_token: str # Optional. Pagination token

176

177

class ListRelatedAccountGroupsResponse:

178

"""Response message for listing related account groups."""

179

related_account_groups: List[RelatedAccountGroup] # List of account groups

180

next_page_token: str # Token for next page of results

181

182

class ListRelatedAccountGroupMembershipsRequest:

183

"""Request message for listing account group memberships."""

184

parent: str # Required. Group name

185

page_size: int # Optional. Maximum results per page

186

page_token: str # Optional. Pagination token

187

188

class ListRelatedAccountGroupMembershipsResponse:

189

"""Response message for listing account group memberships."""

190

related_account_group_memberships: List[RelatedAccountGroupMembership] # Memberships

191

next_page_token: str # Token for next page

192

193

class SearchRelatedAccountGroupMembershipsRequest:

194

"""Request message for searching account group memberships."""

195

parent: str # Required. Project name

196

hashed_account_id: bytes # Required. Hashed account ID to search for

197

page_size: int # Optional. Maximum results per page

198

page_token: str # Optional. Pagination token

199

200

class SearchRelatedAccountGroupMembershipsResponse:

201

"""Response message for searching account group memberships."""

202

related_account_group_memberships: List[RelatedAccountGroupMembership] # Search results

203

next_page_token: str # Token for next page

204

```

205

206

## Usage Examples

207

208

### Account Investigation Workflow

209

210

```python

211

import hashlib

212

213

def investigate_account_relationships(client, account_identifier):

214

"""Investigate relationships for a specific account."""

215

216

# Hash the account identifier

217

hashed_id = hashlib.sha256(account_identifier.encode()).digest()

218

219

# Search for related account groups

220

search_request = recaptchaenterprise.SearchRelatedAccountGroupMembershipsRequest(

221

parent="projects/your-project-id",

222

hashed_account_id=hashed_id

223

)

224

225

search_response = client.search_related_account_group_memberships(request=search_request)

226

227

print(f"Investigating account: {account_identifier[:10]}...")

228

print(f"Found in {len(search_response.related_account_group_memberships)} related groups")

229

230

# Analyze each group the account belongs to

231

for membership in search_response.related_account_group_memberships:

232

group_name = membership.name.split('/')[3] # Extract group ID

233

print(f"\n--- Group {group_name} ---")

234

235

# Get all members of this group

236

list_request = recaptchaenterprise.ListRelatedAccountGroupMembershipsRequest(

237

parent=f"projects/your-project-id/relatedaccountgroups/{group_name}"

238

)

239

240

list_response = client.list_related_account_group_memberships(request=list_request)

241

242

print(f"Total members in group: {len(list_response.related_account_group_memberships)}")

243

244

# Show other members (first 5)

245

other_members = [m for m in list_response.related_account_group_memberships

246

if m.hashed_account_id != hashed_id]

247

248

print("Other members in group:")

249

for i, member in enumerate(other_members[:5]):

250

print(f" {i+1}. {member.hashed_account_id.hex()[:16]}...")

251

252

if len(other_members) > 5:

253

print(f" ... and {len(other_members) - 5} more")

254

255

# Investigate suspicious account

256

investigate_account_relationships(client, "suspicious.user@example.com")

257

```

258

259

### Fraud Detection Integration

260

261

```python

262

def check_account_risk_factors(client, assessment_response):

263

"""Check additional risk factors using related account analysis."""

264

265

# Extract account ID from assessment if available

266

if hasattr(assessment_response.event, 'hashed_account_id'):

267

hashed_account_id = assessment_response.event.hashed_account_id

268

269

# Search for related accounts

270

search_request = recaptchaenterprise.SearchRelatedAccountGroupMembershipsRequest(

271

parent="projects/your-project-id",

272

hashed_account_id=hashed_account_id

273

)

274

275

try:

276

search_response = client.search_related_account_group_memberships(request=search_request)

277

278

# Risk factors based on related accounts

279

group_count = len(search_response.related_account_group_memberships)

280

281

if group_count > 0:

282

print(f"Account belongs to {group_count} related account groups")

283

284

# Additional checks for high-risk patterns

285

for membership in search_response.related_account_group_memberships:

286

group_path = membership.name.rsplit('/', 1)[0] # Get group path

287

288

# Get group size

289

list_request = recaptchaenterprise.ListRelatedAccountGroupMembershipsRequest(

290

parent=group_path

291

)

292

293

list_response = client.list_related_account_group_memberships(request=list_request)

294

group_size = len(list_response.related_account_group_memberships)

295

296

if group_size > 10: # Large groups may indicate coordinated attacks

297

print(f"WARNING: Account in large group ({group_size} members)")

298

return "HIGH_RISK"

299

elif group_size > 5:

300

print(f"CAUTION: Account in medium group ({group_size} members)")

301

return "MEDIUM_RISK"

302

303

return "LOW_RISK"

304

else:

305

print("Account not found in any related groups")

306

return "UNKNOWN"

307

308

except Exception as e:

309

print(f"Error checking related accounts: {e}")

310

return "ERROR"

311

312

return "NO_ACCOUNT_ID"

313

314

# Use in assessment workflow

315

assessment = client.create_assessment(request=assessment_request)

316

account_risk = check_account_risk_factors(client, assessment)

317

318

print(f"Assessment score: {assessment.risk_analysis.score}")

319

print(f"Account risk level: {account_risk}")

320

```

321

322

### Bulk Account Analysis

323

324

```python

325

def analyze_account_groups(client, project_id):

326

"""Analyze all related account groups in a project."""

327

328

# Get all related account groups

329

list_request = recaptchaenterprise.ListRelatedAccountGroupsRequest(

330

parent=f"projects/{project_id}"

331

)

332

333

response = client.list_related_account_groups(request=list_request)

334

335

print(f"Found {len(response.related_account_groups)} related account groups")

336

337

group_stats = []

338

339

for group in response.related_account_groups:

340

# Get memberships for each group

341

memberships_request = recaptchaenterprise.ListRelatedAccountGroupMembershipsRequest(

342

parent=group.name

343

)

344

345

memberships_response = client.list_related_account_group_memberships(

346

request=memberships_request

347

)

348

349

group_size = len(memberships_response.related_account_group_memberships)

350

group_stats.append({

351

'name': group.name,

352

'size': group_size

353

})

354

355

# Sort by group size (largest first)

356

group_stats.sort(key=lambda x: x['size'], reverse=True)

357

358

print("\nLargest related account groups:")

359

for i, stats in enumerate(group_stats[:10]):

360

print(f"{i+1}. {stats['name']}: {stats['size']} members")

361

362

# Flag large groups for investigation

363

large_groups = [g for g in group_stats if g['size'] > 20]

364

if large_groups:

365

print(f"\nWARNING: {len(large_groups)} groups have >20 members - investigate for coordinated fraud")

366

367

return group_stats

368

369

# Analyze all groups

370

stats = analyze_account_groups(client, "your-project-id")

371

```

372

373

### Account Hashing Utilities

374

375

```python

376

import hashlib

377

import hmac

378

379

def hash_account_id(account_id, salt=None):

380

"""Hash account identifier for reCAPTCHA Enterprise."""

381

if salt:

382

# Use HMAC with salt for consistent hashing

383

return hmac.new(

384

salt.encode('utf-8'),

385

account_id.encode('utf-8'),

386

hashlib.sha256

387

).digest()

388

else:

389

# Simple SHA-256 hash

390

return hashlib.sha256(account_id.encode('utf-8')).digest()

391

392

def normalize_account_id(account_id):

393

"""Normalize account identifier before hashing."""

394

# Convert to lowercase and strip whitespace

395

normalized = account_id.lower().strip()

396

397

# Remove common variations (adjust for your use case)

398

# For email addresses

399

if '@' in normalized:

400

local, domain = normalized.split('@', 1)

401

# Remove dots from Gmail addresses

402

if domain in ['gmail.com', 'googlemail.com']:

403

local = local.replace('.', '')

404

normalized = f"{local}@{domain}"

405

406

return normalized

407

408

# Example usage

409

account_id = "User.Name@Gmail.com"

410

normalized_id = normalize_account_id(account_id) # "username@gmail.com"

411

hashed_id = hash_account_id(normalized_id)

412

413

print(f"Original: {account_id}")

414

print(f"Normalized: {normalized_id}")

415

print(f"Hashed: {hashed_id.hex()}")

416

```

417

418

### Integration with Assessment Creation

419

420

```python

421

def create_assessment_with_account_analysis(client, event_data, account_identifier=None):

422

"""Create assessment with related account analysis."""

423

424

# Hash account identifier if provided

425

hashed_account_id = None

426

if account_identifier:

427

hashed_account_id = hash_account_id(normalize_account_id(account_identifier))

428

429

# Create event with account information

430

event = recaptchaenterprise.Event(

431

token=event_data.get('token'),

432

site_key=event_data.get('site_key'),

433

user_agent=event_data.get('user_agent'),

434

user_ip_address=event_data.get('user_ip'),

435

expected_action=event_data.get('action'),

436

hashed_account_id=hashed_account_id

437

)

438

439

# Create assessment

440

assessment = recaptchaenterprise.Assessment(event=event)

441

assessment_request = recaptchaenterprise.CreateAssessmentRequest(

442

parent="projects/your-project-id",

443

assessment=assessment

444

)

445

446

assessment_response = client.create_assessment(request=assessment_request)

447

448

# Analyze related accounts if account ID was provided

449

account_analysis = None

450

if hashed_account_id:

451

account_analysis = check_account_risk_factors(client, assessment_response)

452

453

return {

454

'assessment': assessment_response,

455

'account_risk': account_analysis,

456

'risk_score': assessment_response.risk_analysis.score

457

}

458

459

# Example usage

460

event_data = {

461

'token': '03AIIukzh7Z...',

462

'site_key': '6LdGwQ0...',

463

'user_agent': 'Mozilla/5.0...',

464

'user_ip': '203.0.113.42',

465

'action': 'login'

466

}

467

468

result = create_assessment_with_account_analysis(

469

client,

470

event_data,

471

account_identifier="user@example.com"

472

)

473

474

print(f"Risk score: {result['risk_score']}")

475

print(f"Account risk: {result['account_risk']}")

476

```

477

478

## Error Handling

479

480

```python

481

from google.api_core import exceptions

482

483

try:

484

response = client.list_related_account_groups(request=request)

485

except exceptions.PermissionDenied as e:

486

print(f"Insufficient permissions for account analysis: {e}")

487

except exceptions.InvalidArgument as e:

488

print(f"Invalid request parameters: {e}")

489

490

try:

491

search_response = client.search_related_account_group_memberships(request=search_request)

492

except exceptions.InvalidArgument as e:

493

print(f"Invalid hashed account ID or search parameters: {e}")

494

except exceptions.NotFound as e:

495

print(f"No related account groups found: {e}")

496

```

497

498

## Best Practices

499

500

### Account Identifier Management

501

- Use consistent normalization before hashing account IDs

502

- Consider using HMAC with a secret salt for additional security

503

- Handle different account identifier formats (email, username, etc.)

504

- Document your hashing approach for consistency

505

506

### Privacy and Security

507

- Never store or log raw account identifiers

508

- Use hashed identifiers in all API calls

509

- Implement proper access controls for related account data

510

- Regular audit of who has access to account relationship data

511

512

### Analysis Workflows

513

- Integrate related account analysis with existing fraud detection

514

- Set appropriate thresholds for group size alerts

515

- Monitor trends in related account group formation

516

- Use related account data to enhance risk scoring models

517

518

### Performance Considerations

519

- Cache related account lookups for frequently analyzed accounts

520

- Implement pagination for large result sets

521

- Consider async processing for bulk account analysis

522

- Monitor API quotas and rate limits for account analysis operations