FriendsOfREDAXO / FriendsOfREDAXO/yform_field
Performance: `password_hash`/`password_verify` in `choice_status` macht Listen sehr langsam
- Dominant language
- PHP
- Stars
- 2
- Forks
- 2
- PR merge metrics
- No merged PRs in 30d
Description
## Performance: `password_hash`/`password_verify` in `choice_status` macht Listen sehr langsam
### Problem
`rex_yform_value_choice_status::getToken()` nutzt `password_hash($secret . $data_id . $table_name, PASSWORD_DEFAULT)` (bcrypt).
`getToken()` wird beim Rendern der **Listenansicht pro Zeile** aufgerufen (in `select()`). Bcrypt mit Default-Cost (10) braucht typisch ~13 ms pro Aufruf, was bei größeren
Tabellen direkt sichtbar wird:
| Datensätze | Backend-Ladezeit |
|---|---|
| ~100 | ~1.3 s |
| ~500 | ~6 s |
| **~900** | **~12 s** (gemessen, Produktivumgebung) |
Genau diese 12 s konnte ich an einer Tabelle mit 900 Einträgen reproduzieren — nach Entfernen des `choice_status`-Felds aus der Listenansicht: <1 s.
### Ursache
`password_hash` ist designed langsam (Brute-Force-Resistenz für Passwort-Speicherung). Hier wird es aber nicht für Passwort-Hashing benutzt, sondern als CSRF-/Auth-Token zur
Absicherung des Inline-Status-Updates über `rex_api_choice_status`. Für diesen Zweck ist bcrypt die falsche Wahl.
### Vorschlag
`password_hash`/`password_verify` durch `hash_hmac('sha256', …)` + `hash_equals` ersetzen.
**`lib/yform/value/choice_status.php`**
```php
public static function getToken($data_id, $table_name)
{
$secret = rex_config::get('yform_field', 'choice_status_secret');
return hash_hmac('sha256', $data_id . '|' . $table_name, (string) $secret);
}
```
**lib/yform_api_choice_status.php**
```
$expected = hash_hmac('sha256', $data_id . '|' . $table, (string) $secret);
$check = is_string($token) && hash_equals($expected, $token);
```
**Auswirkungen**
- Performance: ~13 ms → <0.01 ms pro Aufruf. Bei 900 Zeilen ≈ 12 s gespart.
- Sicherheit: keine Regression. Schutzziel ist „eingeloggter Backend-User darf nur Datensätze toggeln, deren Token er gerendert bekommen hat" — das secret aus
rex_config('yform_field', 'choice_status_secret') bleibt die Vertrauenswurzel. Ohne Kenntnis des Secrets kann niemand einen gültigen Token fälschen, weder mit bcrypt noch mit
HMAC. Es gibt in beiden Varianten keine TTL und keinen Nonce; ein einmal sichtbarer Token ist beliebig oft wiederverwendbar (das ändert sich durch den Patch nicht).
hash_equals ist timing-attack-sicher.
- Kompatibilität: bestehende, gerade im Browser geöffnete Listen-Tokens werden nach dem Patch invalid. Beim nächsten Page-Load werden frische ausgegeben — keine
Daten-Migration nötig.
**Reproduzierbar** mit
REDAXO 5.x, yform_field aktuell, eine YForm-Tabelle mit choice_status-Feld in der Listenansicht und ≥500 Datensätzen.
PR folgt.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with lib/yform/value/choice_status.php and lib/yform_api_choice_status.php, then trace getToken() from the list rendering path and its validation in rex_api_choice_status. Verify that the replacement preserves token validation and that choice_status lists no longer incur bcrypt-scale delays; existing browser tokens may be invalidated after the change.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- php
- Domain
- backend-api-design, performance
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 65/100