Aktueller Standort: Startseite> Neueste Artikel> Wie Verwende ich Hash_HMAC_FILE (), um einen Sicherheitskontrollsummenschutz für hochgeladene Dateien durchzuführen?

Wie Verwende ich Hash_HMAC_FILE (), um einen Sicherheitskontrollsummenschutz für hochgeladene Dateien durchzuführen?

gitbox 2025-08-27

Kernidee (hochrangige)

  1. Es ist möglich zu überprüfen, ob die Datei nicht manipuliert wurde und dass nur die Partei, die weiß, dass der Schlüssel die richtige Signatur erzeugen kann. Im Gegensatz zu einfachem Hashing (wie SHA256) verwendet HMAC Schlüssel, um Fälschung zu verhindern.

  2. Der korrekte Vorgang zum Hochladen von Dateien ist normalerweise:

    • Generieren/verteilen Sie ein gemeinsames Geheimnis (oder verwenden Sie einen serverseitigen privaten Schlüssel).

    • Der Client oder Absender berechnet den HMAC (z. B. HMAC-Sha256) für die Datei und sendet die Signatur (HTTP-Header oder Formular- oder Formularfeld) zusammen mit dem Upload.

    • Nach dem Empfangen der Datei verwendet der Server denselben Schlüssel, um die HMAC neu zu berechnen, und vergleicht die Signaturen mit dem Zeitvergleich des Zeitpunkts ( Hash_equals ) und überträgt die Überprüfung, wenn die Übereinstimmung übereinstimmt.

  3. Übertragen Sie Signaturen und Dateien über HTTPS für immer. Unterschriften werden auf HTTP in Klartext abgelöst und wiederverwendet.


Warum verwenden Sie Hash_HMAC_FILE () ?

  • Hash_HMAC_FILE ($ algo, $ Dateiname, $ key, $ raw_output = false) berechnet HMAC direkt in der Datei und Streaming -Lesedateien werden intern verarbeitet. Es ist nicht erforderlich, die gesamte Datei zuerst in den Speicher zu lesen, was für mittlere und große Dateien geeignet ist.

  • Wenn Sie die serverseitige Überprüfung schnell implementieren müssen, ist Hash_HMAC_FILE () eine kurze und effiziente Lösung. Für komplexere Szenarien (wie das Shard-Upload) können Sie jedoch auch Hash_init () / Hash_Update () / Hash_Final () verwenden, um block-by-block-Berechnungen zu implementieren.


Grundlegende Beispiel: Client Signature + Server -Überprüfung (Einzeldatei)

Das Folgende zeigt eine gemeinsame Situation: Der Client verwendet einen gemeinsam genutzten Schlüssel, um HMAC in der Datei auszuführen (das Client -Beispiel wird weggelassen), und der Server verwendet Hash_HMAC_FILE (), um $ _files hochzuladen.

Server empfangener Ende verify_Upload.php (einfaches Beispiel):

 <span><span><span class="hljs-meta">&lt;?php</span></span><span>
</span><span><span class="hljs-comment">// verify_upload.php</span></span><span>

</span><span><span class="hljs-comment">// 1) Sicherung Schlüsselspeicher(Verwenden Sie Umgebungsvariablen im Beispiel)</span></span><span>
</span><span><span class="hljs-variable">$HMAC_KEY</span></span><span> = </span><span><span class="hljs-title function_ invoke__">getenv</span></span><span>(</span><span><span class="hljs-string">'UPLOAD_HMAC_KEY'</span></span><span>); </span><span><span class="hljs-comment">// Bitte stellen Sie es während der Bereitstellung sicher ein(Umgebungsvariablen / Vault)</span></span><span>
</span><span><span class="hljs-keyword">if</span></span><span> (!</span><span><span class="hljs-variable">$HMAC_KEY</span></span><span>) {
    </span><span><span class="hljs-title function_ invoke__">http_response_code</span></span><span>(</span><span><span class="hljs-number">500</span></span><span>);
    </span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"Server misconfiguration."</span></span><span>;
    </span><span><span class="hljs-keyword">exit</span></span><span>;
}

</span><span><span class="hljs-comment">// 2) Angenommen, der Kunde setzt die Unterschrift ein HTTP Header: X-File-Signature</span></span><span>
</span><span><span class="hljs-variable">$clientSig</span></span><span> = </span><span><span class="hljs-keyword">isset</span></span><span>(</span><span><span class="hljs-variable">$_SERVER</span></span><span>[</span><span><span class="hljs-string">'HTTP_X_FILE_SIGNATURE'</span></span><span>]) ? </span><span><span class="hljs-variable">$_SERVER</span></span><span>[</span><span><span class="hljs-string">'HTTP_X_FILE_SIGNATURE'</span></span><span>] : </span><span><span class="hljs-literal">null</span></span><span>;
</span><span><span class="hljs-keyword">if</span></span><span> (!</span><span><span class="hljs-variable">$clientSig</span></span><span>) {
    </span><span><span class="hljs-title function_ invoke__">http_response_code</span></span><span>(</span><span><span class="hljs-number">400</span></span><span>);
    </span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"Missing signature."</span></span><span>;
    </span><span><span class="hljs-keyword">exit</span></span><span>;
}

</span><span><span class="hljs-keyword">if</span></span><span> (!</span><span><span class="hljs-keyword">isset</span></span><span>(</span><span><span class="hljs-variable">$_FILES</span></span><span>[</span><span><span class="hljs-string">'file'</span></span><span>]) || </span><span><span class="hljs-variable">$_FILES</span></span><span>[</span><span><span class="hljs-string">'file'</span></span><span>][</span><span><span class="hljs-string">'error'</span></span><span>] !== UPLOAD_ERR_OK) {
    </span><span><span class="hljs-title function_ invoke__">http_response_code</span></span><span>(</span><span><span class="hljs-number">400</span></span><span>);
    </span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"Upload failed."</span></span><span>;
    </span><span><span class="hljs-keyword">exit</span></span><span>;
}

</span><span><span class="hljs-comment">// Temporärer Upload -Dateipfad</span></span><span>
</span><span><span class="hljs-variable">$tmpPath</span></span><span> = </span><span><span class="hljs-variable">$_FILES</span></span><span>[</span><span><span class="hljs-string">'file'</span></span><span>][</span><span><span class="hljs-string">'tmp_name'</span></span><span>];

</span><span><span class="hljs-comment">// 3) verwenden hash_hmac_file Berechnen Sie die serverseitige Signatur(verwenden SHA256)</span></span><span>
</span><span><span class="hljs-variable">$algo</span></span><span> = </span><span><span class="hljs-string">'sha256'</span></span><span>;
</span><span><span class="hljs-variable">$serverSig</span></span><span> = </span><span><span class="hljs-title function_ invoke__">hash_hmac_file</span></span><span>(</span><span><span class="hljs-variable">$algo</span></span><span>, </span><span><span class="hljs-variable">$tmpPath</span></span><span>, </span><span><span class="hljs-variable">$HMAC_KEY</span></span><span>);

</span><span><span class="hljs-comment">// 4) verwenden hash_equals Timing -Sicherheitsvergleich durchführen,Vermeiden Sie, Informationen auszugehen</span></span><span>
</span><span><span class="hljs-keyword">if</span></span><span> (!</span><span><span class="hljs-title function_ invoke__">hash_equals</span></span><span>(</span><span><span class="hljs-variable">$serverSig</span></span><span>, </span><span><span class="hljs-variable">$clientSig</span></span><span>)) {
    </span><span><span class="hljs-title function_ invoke__">http_response_code</span></span><span>(</span><span><span class="hljs-number">403</span></span><span>);
    </span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"Signature mismatch. File may be tampered."</span></span><span>;
    </span><span><span class="hljs-comment">// Prüfprotokolle können aufgezeichnet werden:Quelle IP、Dateiname、Zeit und warte</span></span><span>
    </span><span><span class="hljs-keyword">exit</span></span><span>;
}

</span><span><span class="hljs-comment">// 5) Unterschriftenüberprüfung bestanden,Verschieben Sie Dateien sicher in das endgültige Verzeichnis und setzen Sie Berechtigungen</span></span><span>
</span><span><span class="hljs-variable">$dest</span></span><span> = </span><span><span class="hljs-keyword">__DIR__</span></span><span> . </span><span><span class="hljs-string">'/uploads/'</span></span><span> . </span><span><span class="hljs-title function_ invoke__">basename</span></span><span>(</span><span><span class="hljs-variable">$_FILES</span></span><span>[</span><span><span class="hljs-string">'file'</span></span><span>][</span><span><span class="hljs-string">'name'</span></span><span>]);
</span><span><span class="hljs-keyword">if</span></span><span> (!</span><span><span class="hljs-title function_ invoke__">move_uploaded_file</span></span><span>(</span><span><span class="hljs-variable">$tmpPath</span></span><span>, </span><span><span class="hljs-variable">$dest</span></span><span>)) {
    </span><span><span class="hljs-title function_ invoke__">http_response_code</span></span><span>(</span><span><span class="hljs-number">500</span></span><span>);
    </span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"Failed to store file."</span></span><span>;
    </span><span><span class="hljs-keyword">exit</span></span><span>;
}

</span><span><span class="hljs-comment">// Optional:Speichern Sie die Signatur/Metadaten werden zur nachfolgenden Überprüfung an die Datenbank gesendet</span></span><span>
</span><span><span class="hljs-comment">// $db-&gt;insert('uploads', ['name'=&gt;..., 'sig'=&gt;$serverSig, ...]);</span></span><span>

</span><span><span class="hljs-title function_ invoke__">http_response_code</span></span><span>(</span><span><span class="hljs-number">200</span></span><span>);
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"Upload verified and stored."</span></span><span>;
</span></span>

Der Kunde muss mit der Anfrage einen Signaturwert (z. B. eine Hexadezimalzeichenfolge) senden. Probe HMAC -Erzeugung (Demonstration des PHP -Clients oder Befehlszeilenzeilen):

 <span><span><span class="hljs-meta">&lt;?php</span></span><span>
</span><span><span class="hljs-comment">// client_sign.php</span></span><span>
</span><span><span class="hljs-variable">$key</span></span><span> = </span><span><span class="hljs-string">'shared-secret-key'</span></span><span>;
</span><span><span class="hljs-variable">$file</span></span><span> = </span><span><span class="hljs-string">'/path/to/file.bin'</span></span><span>;
</span><span><span class="hljs-variable">$algo</span></span><span> = </span><span><span class="hljs-string">'sha256'</span></span><span>;
</span><span><span class="hljs-variable">$sig</span></span><span> = </span><span><span class="hljs-title function_ invoke__">hash_hmac_file</span></span><span>(</span><span><span class="hljs-variable">$algo</span></span><span>, </span><span><span class="hljs-variable">$file</span></span><span>, </span><span><span class="hljs-variable">$key</span></span><span>);
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-variable">$sig</span></span><span>; </span><span><span class="hljs-comment">// Signatur an den Server gesendet</span></span><span>
</span></span>

Im tatsächlichen HTTP-Upload sendet der Client die X-Datei-Signatur: <SIG> Header mit Multipart-/Form-Daten-Upload oder als Signatur eines Formularfelds.


Große Dateien/Slice -Hochladen von Vorschlägen

Hash_HMAC_FILE () selbst kann große Dateien verarbeiten, aber in Sharded Upload- oder Streaming -Upload -Szenarien müssen HMACs durch Block- oder segmentierte HMACs berechnet werden.

Lösung A: Nach Empfang der fusionierten Datei verwendet der Server Hash_HMAC_FILE (), um sie zu überprüfen.

Vorteile: einfache Implementierung; Nachteile: Es erfordert vorübergehende Speicherung/Verschmelzung vollständiger Dateien auf dem Server, die möglicherweise IO und Festplatte belegen.

Lösung B: Berechnen Sie den HMAC -Block per Block beim Hochladen (Client und Server synchronisieren Sie jeden Block).

  • Der Client berechnet die HMAC für jeden Block und sendet die Blocksignatur. Der Server überprüft und endet mit der Datei an, wenn Sie jeden Block empfangen. Der letzte Block wird erfolgreich hochgeladen und die vollständige Datei wurde überprüft.

  • Oder der Client sendet die Originaldaten jedes Blocks und sendet den HMAC der vollständigen Datei am Ende (wenn der Client die vollständige Signatur lokal generieren kann).

Lösung C: Verwenden Sie Streaming -Hash (Serverseite)

Wenn der Server den Upload - Stream direkt aus PHP ( z . Beispiel:

 <span><span><span class="hljs-meta">&lt;?php</span></span><span>
</span><span><span class="hljs-variable">$key</span></span><span> = </span><span><span class="hljs-title function_ invoke__">getenv</span></span><span>(</span><span><span class="hljs-string">'UPLOAD_HMAC_KEY'</span></span><span>);
</span><span><span class="hljs-variable">$algo</span></span><span> = </span><span><span class="hljs-string">'sha256'</span></span><span>;

</span><span><span class="hljs-comment">// Initialisierung HMAC Kontext</span></span><span>
</span><span><span class="hljs-variable">$context</span></span><span> = </span><span><span class="hljs-title function_ invoke__">hash_init</span></span><span>(</span><span><span class="hljs-variable">$algo</span></span><span>, HASH_HMAC, </span><span><span class="hljs-variable">$key</span></span><span>);

</span><span><span class="hljs-comment">// Angenommen, wir php://input Oder Dateiströme werden Block von Block gelesen</span></span><span>
</span><span><span class="hljs-variable">$stream</span></span><span> = </span><span><span class="hljs-title function_ invoke__">fopen</span></span><span>(</span><span><span class="hljs-string">'php://input'</span></span><span>, </span><span><span class="hljs-string">'rb'</span></span><span>);
</span><span><span class="hljs-keyword">while</span></span><span> (!</span><span><span class="hljs-title function_ invoke__">feof</span></span><span>(</span><span><span class="hljs-variable">$stream</span></span><span>)) {
    </span><span><span class="hljs-variable">$chunk</span></span><span> = </span><span><span class="hljs-title function_ invoke__">fread</span></span><span>(</span><span><span class="hljs-variable">$stream</span></span><span>, </span><span><span class="hljs-number">8192</span></span><span>);
    </span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$chunk</span></span><span> === </span><span><span class="hljs-literal">false</span></span><span>) </span><span><span class="hljs-keyword">break</span></span><span>;
    </span><span><span class="hljs-title function_ invoke__">hash_update</span></span><span>(</span><span><span class="hljs-variable">$context</span></span><span>, </span><span><span class="hljs-variable">$chunk</span></span><span>);
}
</span><span><span class="hljs-variable">$serverSig</span></span><span> = </span><span><span class="hljs-title function_ invoke__">hash_final</span></span><span>(</span><span><span class="hljs-variable">$context</span></span><span>);
</span><span><span class="hljs-title function_ invoke__">fclose</span></span><span>(</span><span><span class="hljs-variable">$stream</span></span><span>);

</span><span><span class="hljs-comment">// Dann vergleichen clientSig ...</span></span><span>
</span></span>

Verhindern Sie Wiedergabeangriffe und damit verbundene Metadaten

Ein einfacher HMAC kann nur die Integrität und Authentifizierung garantieren (abgeleitet von der Party, die den Schlüssel hält), ist jedoch anfällig für "Wiedergabe" (dieselbe Datei + Signatur wird zurückgespielt). Schutzmethode:

  • Bei der Unterschrift werden der Zeitstempel, die Nonce (Zufallsnummer), die Uploader -ID usw. zusammen signiert , beispielsweise das Spleißen dieser Metadaten in Signature = HMAC (Schlüssel, Dateiname + ":" + file_sha256 + ":" + TimeStamp + ":" + nonce) und Timestamp und Nonce zusammen.

  • Der Server überprüft den Zeitstempel (z. B. ± 5 Minuten zulässt) und prüft, ob der Nonce verwendet wurde (müssen für einen bestimmten Zeitraum bestehen bleiben), um eine Wiederholung zu verhindern.

  • Für die API: Verwenden Sie ein vorschriebenes Upload-Token, das für einen kurzen Zeitraum gültig ist, und einbetten Sie den Ablauf und die Signatur in das Token ein. Der Server überprüft die Gültigkeit des Tokens, bevor die Datei HMAC überprüft wird.

Beispielsignaturschema (externe Signatur der Datei):

  • Der Client fordert zunächst einen kurzfristigen Upload-Anmeldeinformationen an (einschließlich Nonce und Ablauf, generiert und vom Server signiert).

  • Der Client lädt die Datei hoch und stellt die Anmeldeinformationen und Dateien HMAC in den Header.

  • Der Server überprüft zuerst die Anmeldeinformationen und überprüft dann die Datei HMAC.


Schlüsselverwaltungs- und Sicherheitsempfehlungen

  1. Schlüsselspeicher : HMAC-Tasten dürfen in Lagern/Codes nicht fest codiert werden. Verwenden Sie Umgebungsvariablen, eingeschränkter Speicher von Konfigurationsdateien oder spezialisierten Schlüsselverwaltungssystemen (Vault, Cloud KMS).

  2. Mindestberechtigungen : Die Verwendung und Berechtigung des Schlüssels sollte minimiert werden. Wenn unterschiedliche Tasten unterschiedlichen Verwendungen zugeordnet werden können (die Signaturtaste hochladen wird von anderen Servicetasten getrennt).

  3. Regelmäßige Rotation : Entwickeln Sie wichtige Rotationspolitik (z. B. alle 90 Tage) und unterstützen Sie die kurzfristige Überprüfung der alten Schlüssel (beide neue/alte Schlüssel werden während der Rotation unterstützt), um Überprüfungsunterbrechungen zu vermeiden.

  4. Prüfung : Notieren Sie die Anfrage, die Quelle -IP und die Zeit für fehlgeschlagene Signaturen, um die Erkennung von Angriffsverhalten anschließend zu erleichtern.

  5. Verwenden von HTTPS/TLS : Signaturen und Dateien müssen über TLS übertragen werden, um Vermittlungen zu vermeiden, dass Signaturen oder Diebstahl von Tasten abhören.


Verwenden Sie Hash_equals zum Vergleich, um Timing -Angriffe zu vermeiden

Verwenden Sie nicht == , == oder String -Spleißen, um Signaturen zu vergleichen. Sie sollten Hash_equals () für den konstanten Zeitvergleich verwenden, zum Beispiel:

 <span><span><span class="hljs-keyword">if</span></span><span> (!</span><span><span class="hljs-title function_ invoke__">hash_equals</span></span><span>(</span><span><span class="hljs-variable">$serverSig</span></span><span>, </span><span><span class="hljs-variable">$clientSig</span></span><span>)) {
    </span><span><span class="hljs-comment">// ablehnen</span></span><span>
}
</span></span>

Hash_equals () kann auch den Zeitunterschied verhindern, wenn es unterschiedliche Längen oder frühe Nichtübereinstimmung gibt.


Behandeln Sie andere Sicherheitsprobleme (Dateityp, Berechtigungen)

Die HMAC -Überprüfung ist nur ein Teil der Integrität und Authentifizierung und sollte auch:

  • Überprüfen Sie den Dateityp (MIME -Typ + Datei -Header -Signatur), um böswillige Skripte auszuführen.

  • Begrenzen Sie die Größe , begrenzen Sie die Upload -Frequenz und die Whitelist die Größe und Art der Benutzer.

  • Trennen Sie das User -Upload -Verzeichnis im Web -Root -Verzeichnis und setzen Sie die entsprechenden Dateiberechtigungen (nicht ausführbare Dateiberechtigungen).

  • Ausführbare Dateien werden mit zusätzlichen Scans (Virus-Scan/Sandbox-Analyse) in Hochrisikoszenarien durchgeführt.


Erweitertes Szenario: serverseitige Signatur (Ausstellung vorsignierter URL)

Einige Architekturen möchten, dass der Server dem Client eine "vorgestellte URL" oder einen Token ausgibt, damit der Client sie direkt in den Objektspeicher (S3, GCS usw.) hochladen kann. In diesem Szenario:

  • Wenn der Server eine vorsignierte URL generiert, kann er den HMAC (oder den Self-Signatur-Mechanismus des Cloud-Speichers verwenden) einbetten und den Client darüber informieren, dass er beim Hochladen in Zukunft einen bestimmten Header (z. B. X-Expect-Sha256 ) mitbringen muss.

  • Wenn eine Datei in den Cloud -Speicher hochgeladen wird, kann der Server die HMAC- oder Objektintegrität des Objekts durch Rückrufe oder nachfolgende Abrufen überprüfen (z. B. neu berechnen die HMAC für Dateien im Speicher oder die Bereitstellung von Signaturen und Rückgabe von Metadaten vom Cloud -Speicher beim Hochladen). Details hängen von der Funktionalität des Cloud -Speichers ab.


FAQ (kurz)

F: Warum brauchen Sie noch HMAC, wenn es HTTPS gibt?
HTTPS schützt die Übertragungssicherheit, kann jedoch nicht verhindern, dass die Schlüsselinhaber böswillige Dateien hochladen oder nach dem manipulierenden Server auf der Serverseite neu laden. HMAC kann sicherstellen, dass "die Partei mit dem Schlüssel in diesem Upload eine Signatur generiert und der Dateiinhalt nicht vor und nach der Übertragung/Speicherung geändert wird".

F: Kann ich einfach Hash_File () (kein Schlüssel) verwenden?
Hash_File () kann die Integrität nur überprüfen (unabhängig davon, ob es manipuliert wurde), aber jeder kann den Hash -Wert schmieden. Wenn Sie den Hash -Wert nicht freilegen möchten und nur der Server für die Berechnung und Vergleichen verantwortlich ist, ist Hash_File () auch nützlich. Wenn Sie jedoch den Upload -Initiator überprüfen möchten, sollten Sie HMAC verwenden.


Zusammenfassung (Betriebspunkte)

  • Verwenden Sie Hash_HMAC_FILE () (oder Hash_init + Hash_Update ), um die Datei HMAC auf dem Server effizient zu berechnen. Der Client unterschreibt mit demselben Schlüssel und sendet die Signatur (oder die vorschriebenen Anmeldeinformationen werden vom Server ausgestellt).

  • Verwenden Sie Hash_equals () für Zeitvergleiche.

  • Übertragen Sie immer Unterschriften und Dateien über HTTPS, Schlüssel mit sicheren Speicher- und Rotationspolitik.

  • Verwenden Sie für große Datei-/Slice-Uploads Streaming HMAC- oder Shard-Signaturschemata und behalten Sie die Konsistenz auf der Serverseite während der endgültigen Zusammenführung oder der Verifizierung von Pro-Chips bei.

  • HMAC wird als Teil der manipulationssicheren und die Quellüberprüfung verwendet und kombiniert die Erkennung von Dateitypen, die Berechtigungsregelung und das Scannen von Viren, um ein vollständiges Schutzsystem zu bilden.