99 lines
3.6 KiB
YAML
99 lines
3.6 KiB
YAML
id: authentication-headers-required
|
||
name: API认证头部要求规则
|
||
description: 验证API请求是否包含必要的认证头部,如Authorization、X-API-Key等
|
||
category: Security
|
||
version: 1.0.0
|
||
severity: error
|
||
is_enabled: true
|
||
tags:
|
||
- security
|
||
- authentication
|
||
- headers
|
||
- authorization
|
||
target_type: APIRequest
|
||
lifecycle: RequestPreparation
|
||
scope: RequestHeaders
|
||
required_headers:
|
||
- name: Authorization
|
||
pattern: "^(Bearer|Basic|Digest) [A-Za-z0-9\\-\\._~\\+\\/]+=*$"
|
||
description: 认证令牌,格式应为"Bearer token"、"Basic base64"或"Digest value"
|
||
- name: X-API-Key
|
||
pattern: "^[A-Za-z0-9]{32,64}$"
|
||
description: API密钥,应为32-64位的字母数字字符
|
||
- name: X-Request-ID
|
||
pattern: "^[A-Za-z0-9\\-]{8,36}$"
|
||
description: 请求ID,用于跟踪请求,应为8-36位的字母数字和连字符
|
||
check_mode: any # 可以是"all"或"any",表示是需要满足所有头部还是任一头部
|
||
code: |
|
||
def validate(context):
|
||
"""验证API请求是否包含必要的认证头部"""
|
||
request = context.get('api_request')
|
||
if not request:
|
||
return {'is_valid': False, 'message': '缺少API请求对象'}
|
||
|
||
headers = request.headers or {}
|
||
required_headers = context.get('required_headers', [])
|
||
check_mode = context.get('check_mode', 'any')
|
||
|
||
# 获取缺失的头部和无效的头部
|
||
missing_headers = []
|
||
invalid_headers = []
|
||
valid_headers = []
|
||
|
||
import re
|
||
|
||
for header in required_headers:
|
||
header_name = header.get('name')
|
||
header_pattern = header.get('pattern')
|
||
|
||
if header_name not in headers:
|
||
missing_headers.append({
|
||
'name': header_name,
|
||
'description': header.get('description', '')
|
||
})
|
||
continue
|
||
|
||
header_value = headers[header_name]
|
||
|
||
# 如果指定了模式,验证头部值是否符合模式
|
||
if header_pattern and not re.match(header_pattern, header_value):
|
||
invalid_headers.append({
|
||
'name': header_name,
|
||
'value': header_value,
|
||
'pattern': header_pattern,
|
||
'description': header.get('description', '')
|
||
})
|
||
else:
|
||
valid_headers.append(header_name)
|
||
|
||
# 根据检查模式判断是否验证通过
|
||
if check_mode == 'all':
|
||
# 需要所有头部都存在且有效
|
||
is_valid = not missing_headers and not invalid_headers
|
||
else: # 'any'
|
||
# 至少有一个有效的头部即可
|
||
is_valid = len(valid_headers) > 0
|
||
|
||
if is_valid:
|
||
message = '请求包含有效的认证头部'
|
||
if check_mode == 'any':
|
||
message += f": {', '.join(valid_headers)}"
|
||
else:
|
||
if check_mode == 'all':
|
||
if missing_headers:
|
||
message = f"请求缺少必要的认证头部: {', '.join([h['name'] for h in missing_headers])}"
|
||
else:
|
||
message = f"请求包含无效的认证头部: {', '.join([h['name'] for h in invalid_headers])}"
|
||
else: # 'any'
|
||
message = f"请求不包含任何有效的认证头部,至少需要其中之一: {', '.join([h['name'] for h in required_headers])}"
|
||
|
||
return {
|
||
'is_valid': is_valid,
|
||
'message': message,
|
||
'details': {
|
||
'check_mode': check_mode,
|
||
'valid_headers': valid_headers,
|
||
'missing_headers': missing_headers,
|
||
'invalid_headers': invalid_headers
|
||
}
|
||
} |