closeyourit-ruby 0.9.3 → 0.9.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +5 -3
- data/lib/closeyourit/scrubber.rb +54 -1
- data/lib/closeyourit/transport.rb +19 -3
- data/lib/closeyourit/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a1d5e126aa96c17501b6830b9c7763979c239cd4bf4b0e0d43685b0652025378
|
|
4
|
+
data.tar.gz: c2d52c988da1288a5cea2986261481ec87fd67db8f3fb0921e2161c90653022e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e9b3c6b9d352ad92055e710951157956c6fa3a75c8cbcee6bf6f9dbdbd3eb829ac6c990f54a38a72ef141c2e8d5a71eb714905355cbeee7be94a3957d6f6b22e
|
|
7
|
+
data.tar.gz: 6bc37b84e2d6a19e6690df0c40732df11fcf32069f1c9942f2d2ddbf6bb76cedb29a94e86c6fd4269002c9f0f9a4c352c53e1c0b41da9a32f5588503ad645b45
|
data/README.md
CHANGED
|
@@ -92,7 +92,7 @@ end
|
|
|
92
92
|
| `send_pii` | `false` | Master switch PII |
|
|
93
93
|
| `obfuscate_sql` | `true` | Maschera i literal nello SQL |
|
|
94
94
|
| `filter_parameters` | `[]` | Chiavi extra da redarre (mergiate con quelle di Rails) |
|
|
95
|
-
| `scrub_message_patterns` | `[]` | Regexp da redarre da messaggi d'eccezione **e da `message` dei log
|
|
95
|
+
| `scrub_message_patterns` | `[]` | Regexp **aggiuntive** da redarre da messaggi d'eccezione **e da `message` dei log**; le credenziali `Bearer`/`Basic`/`Token` sono già redatte di serie |
|
|
96
96
|
| `logs_enabled` | `true` | Master switch dello stream di log strutturato |
|
|
97
97
|
| `logs_min_level` | `:info` | Soglia minima: i log sotto (es. `debug`) non vengono inviati |
|
|
98
98
|
| `logs_sample_rate` | `1.0` | Frazione di log inviata (`1.0` tutto, `0.0` niente) |
|
|
@@ -381,8 +381,10 @@ Privacy-by-default (`send_pii = false`). In sintesi:
|
|
|
381
381
|
- **SQL**: inviato il template, **mai** i bind values; `obfuscate_sql` maschera anche i literal inline.
|
|
382
382
|
- **Chiavi sensibili** (`password`, `token`, `authorization`, `cookie`, `secret`, `api_key`, `csrf`,
|
|
383
383
|
`credit_card`, `cvv`, `ssn`, `iban`, …) → `[FILTERED]`; estendibili con `filter_parameters`.
|
|
384
|
-
- **Messaggi d'eccezione**: inviati per il debug
|
|
385
|
-
`
|
|
384
|
+
- **Messaggi d'eccezione**: inviati per il debug. Le credenziali di autenticazione finite nel testo
|
|
385
|
+
(`Authorization: Bearer …`, `Basic …`, `Token …`) sono redatte **di serie**, senza configurazione:
|
|
386
|
+
chiave e schema restano leggibili, sparisce il valore → `Authorization: Bearer [FILTERED]`. Il resto
|
|
387
|
+
è redigibile con `scrub_message_patterns` / `before_send`.
|
|
386
388
|
- **Mai inviati**: variabili locali dei frame, argomenti dei metodi, IP/cookie/Authorization, token (che
|
|
387
389
|
viaggia solo nell'header su HTTPS).
|
|
388
390
|
|
data/lib/closeyourit/scrubber.rb
CHANGED
|
@@ -23,6 +23,53 @@ module CloseYourIt
|
|
|
23
23
|
email phone telephone mobile dob birth passport bearer session pin pan
|
|
24
24
|
].freeze
|
|
25
25
|
|
|
26
|
+
# CYRB-23 — redazione INTEGRATA delle credenziali di autenticazione nel testo libero.
|
|
27
|
+
# `filter_params`/`filter_value` coprono gli header STRUTTURATI (la chiave `authorization` è in
|
|
28
|
+
# DENYLIST); un `Authorization: Bearer <token>` incollato dentro `exception.message` o dentro la
|
|
29
|
+
# riga di un log è testo, non una chiave, e prima di questo ticket partiva in chiaro perché
|
|
30
|
+
# `scrub_message` applicava solo i pattern configurati dall'utente (default `[]`).
|
|
31
|
+
#
|
|
32
|
+
# Forma del testo redatto (decisa qui una volta per tutti gli SDK — gemelli CYDA-26/CYJS-38/
|
|
33
|
+
# CYPY-15): chiave e schema restano leggibili, sparisce SOLO la credenziale →
|
|
34
|
+
# `Authorization: Bearer [FILTERED]`. Il messaggio resta diagnosticamente utile (si vede CHE
|
|
35
|
+
# c'era un header e con quale schema) senza trasportare il segreto.
|
|
36
|
+
AUTH_SCHEME = /(?i:Bearer|Basic|Token)/
|
|
37
|
+
|
|
38
|
+
# `token68` (RFC 7235) con padding `=` finale: la forma di una credenziale reale. Minimo 4
|
|
39
|
+
# caratteri — un `Basic` di credenziali brevi è corto (`dTpw` = `u:p`); a filtrare la prosa
|
|
40
|
+
# pensa NOT_PROSE, non la lunghezza.
|
|
41
|
+
CREDENTIAL_TOKEN = %r{[A-Za-z0-9\-._~+/]{4,}={0,2}}
|
|
42
|
+
|
|
43
|
+
# Guardia anti-falso-positivo per lo schema NUDO: quello che segue NON è una credenziale se ha
|
|
44
|
+
# la forma di una parola scritta da un umano, cioè sole lettere in UNA di tre forme —
|
|
45
|
+
# `minuscole`, `Capitalizzata`, `MAIUSCOLE` — e più corta di 20 caratteri. Salva "the bearer of
|
|
46
|
+
# bad news", "invalid bearer credentials", "Basic HTTP authentication", "Bearer Token expired".
|
|
47
|
+
# Tutto il resto è credenziale: entropia (cifre, `_`, `-`, `.`), maiuscole interne miste
|
|
48
|
+
# (`dTpw`, base64) o lunghezza ≥ 20 (nessuna parola è così lunga, mentre un token opaco di sole
|
|
49
|
+
# minuscole sì).
|
|
50
|
+
# Trade-off accettato: un CamelCase subito dopo lo schema (`Token MyAppName`) viene redatto.
|
|
51
|
+
PROSE_WORD = /(?:[a-z]{1,19}|[A-Z][a-z]{0,18}|[A-Z]{1,19})/
|
|
52
|
+
NOT_PROSE = %r{(?!\[FILTERED\])(?!#{PROSE_WORD}(?![A-Za-z0-9\-._~+/=]))}
|
|
53
|
+
|
|
54
|
+
# Valore di un header incollato nel testo: sequenza di pezzi non delimitatori, dove una stringa
|
|
55
|
+
# fra virgolette conta come UN pezzo. NON `\S+`, che si mangerebbe la `)` di
|
|
56
|
+
# "(Authorization: Bearer <token>)"; ma nemmeno una classe secca, che si fermerebbe alla prima
|
|
57
|
+
# virgoletta lasciando in chiaro il segreto di `Token token="<token>"` (sintassi RFC 7235 e
|
|
58
|
+
# `authenticate_with_http_token` di Rails) e di un frammento JSON incollato nel messaggio.
|
|
59
|
+
QUOTED = /"[^"\n]*"|'[^'\n]*'/
|
|
60
|
+
HEADER_VALUE = /(?:#{QUOTED}|[^\s,;)\]}"'<>])+/
|
|
61
|
+
|
|
62
|
+
# `Authorization:`/`authorization=` (anche `Proxy-Authorization`, anche `authorization_header`)
|
|
63
|
+
# seguito dal valore: qui la chiave è esplicita, quindi si redige senza euristica di prosa —
|
|
64
|
+
# over-redaction voluta, coerente con la DENYLIST. `[ \t]` e non `\s`: mai oltre il newline.
|
|
65
|
+
# Il lookahead copre lo schema OPZIONALE: senza, su un testo già redatto il motore farebbe
|
|
66
|
+
# backtracking sul ramo "senza schema" e redigerebbe la parola `Bearer` stessa (non idempotente).
|
|
67
|
+
AUTH_HEADER = /((?i:(?:proxy[_-]?)?authorization)[\w-]*["']?[ \t]*[:=][ \t]*)(?!(?:#{AUTH_SCHEME}[ \t]+)?\[FILTERED\])(#{AUTH_SCHEME}[ \t]+)?#{HEADER_VALUE}/
|
|
68
|
+
|
|
69
|
+
# Schema nudo (`Bearer <token>` senza il nome dell'header) seguito da qualcosa che ha la forma
|
|
70
|
+
# di una credenziale: qui la guardia di prosa serve, la parola "bearer" ricorre nei messaggi.
|
|
71
|
+
AUTH_CREDENTIAL = /(\b#{AUTH_SCHEME}[ \t]+)#{NOT_PROSE}#{CREDENTIAL_TOKEN}/
|
|
72
|
+
|
|
26
73
|
STRING_LITERAL = /'(?:[^']|'')*'/
|
|
27
74
|
NUMERIC_LITERAL = /\b\d+(?:\.\d+)?\b/
|
|
28
75
|
|
|
@@ -51,10 +98,16 @@ module CloseYourIt
|
|
|
51
98
|
sql.to_s.gsub(STRING_LITERAL, "?").gsub(NUMERIC_LITERAL, "?")
|
|
52
99
|
end
|
|
53
100
|
|
|
101
|
+
# Regola integrata (schemi di autenticazione) PRIMA dei pattern utente: le due protezioni si
|
|
102
|
+
# sommano, la prima non è disattivabile — privacy-by-default (CYRB-23).
|
|
54
103
|
def scrub_message(message)
|
|
55
104
|
return message if message.nil?
|
|
56
105
|
|
|
57
|
-
|
|
106
|
+
redacted = message.to_s
|
|
107
|
+
.gsub(AUTH_HEADER, "\\1\\2#{FILTERED}")
|
|
108
|
+
.gsub(AUTH_CREDENTIAL, "\\1#{FILTERED}")
|
|
109
|
+
|
|
110
|
+
@configuration.scrub_message_patterns.reduce(redacted) do |acc, pattern|
|
|
58
111
|
acc.gsub(pattern, FILTERED)
|
|
59
112
|
end
|
|
60
113
|
end
|
|
@@ -91,12 +91,28 @@ module CloseYourIt
|
|
|
91
91
|
target.relative? ? current + target : target
|
|
92
92
|
end
|
|
93
93
|
|
|
94
|
-
# Il Bearer va ri-inviato solo se il redirect resta
|
|
95
|
-
#
|
|
94
|
+
# Il Bearer va ri-inviato solo se il redirect resta sull'autorità dell'endpoint configurato:
|
|
95
|
+
# stesso host (o la sua variante www), stessa porta effettiva e senza downgrade https→http.
|
|
96
|
+
# La porta fa parte del confine di fiducia (CYRB-22): sullo stesso server una porta diversa è
|
|
97
|
+
# un servizio distinto, che non deve ricevere il segreto d'ingest.
|
|
96
98
|
def same_authority?(origin, target)
|
|
97
99
|
return false if origin.scheme == "https" && target.scheme != "https"
|
|
100
|
+
return false unless canonical_host(origin) == canonical_host(target)
|
|
98
101
|
|
|
99
|
-
origin.
|
|
102
|
+
origin.port == target.port || canonical_upgrade?(origin, target)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Un endpoint configurato in `http` che redirige a `https` resta fidato: la porta cambia solo
|
|
106
|
+
# perché cambia lo schema (80 → 443), non perché punti a un servizio su porta non standard.
|
|
107
|
+
def canonical_upgrade?(origin, target)
|
|
108
|
+
origin.scheme == "http" && target.scheme == "https" &&
|
|
109
|
+
origin.port == origin.default_port && target.port == target.default_port
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Una porta esplicita pari alla default (`:443` su https) equivale a ometterla: `URI#port` la
|
|
113
|
+
# normalizza già, qui resta solo da neutralizzare la variante www dell'host canonico.
|
|
114
|
+
def canonical_host(uri)
|
|
115
|
+
uri.host.to_s.sub(/\Awww\./, "")
|
|
100
116
|
end
|
|
101
117
|
|
|
102
118
|
# Estrae " R…: messaggio" dall'envelope d'errore del backend, così il dev vede il codice d'errore
|
data/lib/closeyourit/version.rb
CHANGED