新增群晖Chat渠道适配器的全套实现,包括: 1. 基础适配器与导出接口定义 2. DSM API认证、探测与会话管理 3. 轮询与Webhook两种消息接收方式 4. 消息去重、格式化与规范化处理 5. 多账号支持与权限安全策略 6. 目录用户/群组发现功能 7. 审批配对与流量控制机制 8. 安全审计与配置检查功能
98 lines
3.2 KiB
Python
98 lines
3.2 KiB
Python
"""Security audit module for Synology Chat channel.
|
|
|
|
Performs security configuration checks and identifies potential risks
|
|
in the Synology Chat integration.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
|
|
def audit_config(config: dict[str, Any]) -> list[dict[str, Any]]:
|
|
findings: list[dict[str, Any]] = []
|
|
|
|
if not config.get("verify_ssl", True):
|
|
findings.append(
|
|
{
|
|
"id": "ssl_disabled",
|
|
"severity": "high",
|
|
"message": "SSL verification is disabled, connections may be vulnerable to MITM attacks",
|
|
"remediation": "Set verify_ssl to true or ensure the NAS certificate is trusted",
|
|
}
|
|
)
|
|
|
|
if not config.get("password") and not config.get("password_file"):
|
|
findings.append(
|
|
{
|
|
"id": "no_credential",
|
|
"severity": "critical",
|
|
"message": "No DSM password or password_file configured",
|
|
"remediation": "Set password or password_file in config or DSM_PASSWORD env var",
|
|
}
|
|
)
|
|
|
|
sec = config.get("security", {})
|
|
if not isinstance(sec, dict):
|
|
sec = {}
|
|
|
|
dm_policy = sec.get("dm_policy", "open")
|
|
if dm_policy == "open":
|
|
findings.append(
|
|
{
|
|
"id": "open_dm_policy",
|
|
"severity": "medium",
|
|
"message": "DM policy is 'open', any user can interact with the bot",
|
|
"remediation": "Set dm_policy to 'allowlist' or 'pairing' and configure allow_from",
|
|
}
|
|
)
|
|
|
|
if dm_policy == "pairing" and not sec.get("allow_from"):
|
|
findings.append(
|
|
{
|
|
"id": "pairing_no_initial_allowlist",
|
|
"severity": "low",
|
|
"message": "Pairing mode enabled but initial allow_from is empty",
|
|
"remediation": "Add at least one trusted user ID to allow_from for operational access",
|
|
}
|
|
)
|
|
|
|
rate_limit = config.get("rate_limit", {}).get("max_per_minute", 30)
|
|
if isinstance(rate_limit, (int, float)) and rate_limit > 60:
|
|
findings.append(
|
|
{
|
|
"id": "high_rate_limit",
|
|
"severity": "low",
|
|
"message": f"Rate limit is set to {rate_limit}/min, which may be high for a NAS device",
|
|
"remediation": "Consider lowering to 30-60 requests per minute",
|
|
}
|
|
)
|
|
|
|
return findings
|
|
|
|
|
|
def audit_connection(dsm_url: str, verify_ssl: bool) -> list[dict[str, Any]]:
|
|
findings: list[dict[str, Any]] = []
|
|
|
|
if dsm_url.startswith("http://"):
|
|
findings.append(
|
|
{
|
|
"id": "cleartext_dsm_url",
|
|
"severity": "high",
|
|
"message": "DSM URL uses HTTP (cleartext), credentials may be transmitted in plaintext",
|
|
"remediation": "Use HTTPS for the DSM URL",
|
|
}
|
|
)
|
|
|
|
if not dsm_url:
|
|
findings.append(
|
|
{
|
|
"id": "empty_dsm_url",
|
|
"severity": "critical",
|
|
"message": "DSM URL is empty",
|
|
"remediation": "Configure a valid DSM URL",
|
|
}
|
|
)
|
|
|
|
return findings
|