iotpg: валидировать namespace (safeNamespaceRe) в getTenantDB на всех путях чтения/записи
This commit is contained in:
@@ -630,6 +630,13 @@ func (s *IoTPostgresStore) Close() error {
|
|||||||
// Открытие дедуплицируется per-namespace мьютексом (гонка Load→LoadOrStore
|
// Открытие дедуплицируется per-namespace мьютексом (гонка Load→LoadOrStore
|
||||||
// из ревью 2026-08-16).
|
// из ревью 2026-08-16).
|
||||||
func (s *IoTPostgresStore) getTenantDB(ctx context.Context, namespace string) (*sql.DB, error) {
|
func (s *IoTPostgresStore) getTenantDB(ctx context.Context, namespace string) (*sql.DB, error) {
|
||||||
|
// Валидация namespace на ВСЕХ путях (чтение/запись) — defense-in-depth.
|
||||||
|
// Основной барьер — валидация при создании устройства, но JWT с sub,
|
||||||
|
// прошедшим namespace==sub в middleware, не должен читать чужую БД через
|
||||||
|
// подмену дефисов (a_b ↔ a-b дают одно имя tenant_a_b) — см. tenantDBName.
|
||||||
|
if !safeNamespaceRe.MatchString(namespace) {
|
||||||
|
return nil, fmt.Errorf("%w: %q", ErrInvalidNamespace, namespace)
|
||||||
|
}
|
||||||
if cached, ok := s.tenants.Load(namespace); ok {
|
if cached, ok := s.tenants.Load(namespace); ok {
|
||||||
return cached.(*sql.DB), nil
|
return cached.(*sql.DB), nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user