FriendsOfREDAXO / FriendsOfREDAXO/yform_field

Performance: `password_hash`/`password_verify` in `choice_status` macht Listen sehr langsam

Open
#4 0 comments 0 reactions 0 assignees View on GitHub
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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.