44 lines
1.5 KiB
PHP
44 lines
1.5 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Middleware;
|
|
|
|
use Closure;
|
|
use Illuminate\Http\Request;
|
|
|
|
class DetectCiphertextInJson
|
|
{
|
|
public function handle(Request $request, Closure $next)
|
|
{
|
|
$response = $next($request);
|
|
|
|
// Only act in non-production environments
|
|
if (app()->environment(['local', 'development', 'staging'])) {
|
|
$contentType = (string) $response->headers->get('Content-Type', '');
|
|
if (str_contains($contentType, 'application/json')) {
|
|
$body = (string) $response->getContent();
|
|
if ($this->containsLaravelCiphertext($body)) {
|
|
// Log minimal info without PII values
|
|
logger()->warning('Ciphertext detected in JSON response', [
|
|
'path' => $request->path(),
|
|
'method' => $request->getMethod(),
|
|
]);
|
|
|
|
// If you prefer to hard-block in dev/stage, uncomment:
|
|
// return response()->json(['error' => 'Ciphertext detected in response'], 422);
|
|
}
|
|
}
|
|
}
|
|
|
|
return $response;
|
|
}
|
|
|
|
private function containsLaravelCiphertext(string $json): bool
|
|
{
|
|
// Heuristic: look for base64-encoded JSON blobs and typical Laravel keys iv/value/mac
|
|
if (!str_contains($json, 'eyJ')) {
|
|
return false;
|
|
}
|
|
return (str_contains($json, '"iv"') && str_contains($json, '"value"') && str_contains($json, '"mac"'));
|
|
}
|
|
}
|