[JAVA] Samshin über den Wert des versteckten Feldes

Dies ist der 17. Tag von System Engineer Adventskalender 2016.

Der 16. Tag war Mr. Ugas Punkte bei der lokalen Anwendung von SPA in Nicht-SPA-Webanwendungen. Es war ein zeitgemäßer Inhalt, auf den ich mich im nächsten Projekt sofort beziehen wollte!

Überprüfen des Werts des ausgeblendeten Feldes

Wenn Sie den Wert auf dem Bildschirm weiterleiten möchten, um etwas zu registrieren, binden Sie ihn in das ausgeblendete Feld ein. Stimmt der Wert zum Zeitpunkt der Registrierung überein? Ich denke, ich werde es überprüfen.

Angenommen, Sie haben eine Anwendung wie "Senden", indem Sie eine Kategorie auswählen, einen neuen Bildschirm zum Erstellen von Problemen öffnen und Inhalte schreiben.

select-category.png

⬇︎

click-new.png

⬇︎

post-issue.png

Betten Sie die Kategorie-ID in das ausgeblendete Feld ein.

<input type="text" name="content"/>
<input type="hidden" name="categoryId" data-th-value="${category.id}"/>
<button type="submit">Save</button>

Der Registrierungsprozess prüft, ob dieser Wert in der Kategorietabelle vorhanden ist. Java # L50).

@PostMapping("new")
String post(@RequestParam String content, @RequestParam Long categoryId) {

    //Existenzprüfung zum Zeitpunkt der Registrierung erneut
    categoryDao.selectById(categoryId).orElseThrow(BadRequest::new);

    Issue entity = new Issue();
    entity.content = content;
    entity.categoryId = categoryId;
    issueDao.insert(entity);
    return "redirect:/";
}

Diese Überprüfung scheint etwas überlastet zu sein, da ich auf die Datenbank zugreife, und ich habe immer gedacht, dass es problematisch wäre, wenn mehr Werte überprüft werden müssten. Wenn der Registrierungsbildschirm angezeigt wird, wird im Allgemeinen der Wert eingebettet, der durch Durchsuchen der Kategorie erhalten wird. Warum muss ich die Existenz jedoch auch während des Registrierungsprozesses überprüfen? Ich fühle mich wie.

Wenn Sie jedoch den HTML-Code neu schreiben, können Sie Werte senden, die nicht möglich sind, und Sie müssen sie ordnungsgemäß überprüfen.

Also dachte ich darüber nach, den Wert mit HMAC zu überprüfen.

Was ist HMAC?

Ein Hash mit einem Schlüssel. Selbst wenn Sie den Wert kennen, können Sie den Hash-Wert nicht erhalten, ohne den Schlüssel zu kennen. Selbst wenn Sie denselben Wert hashen, erhalten Sie unterschiedliche Hashwerte, wenn die Schlüssel unterschiedlich sind. Weitere Informationen finden Sie unter Gugu.

Überprüfen Sie den Wert mit HMAC

Ändern Sie den Teil, in dem die Existenzprüfung der Kategorie durchgeführt wurde, indem Sie mit HMAC auf die Datenbank zur Prüfung zugreifen.

Zunächst beim Öffnen des Registrierungsbildschirms [Hash-Kategorie-ID mit HMAC](https://github.com/backpaper0/seac2016/blob/hmac-verify/src/main/java/com/example/IssueController.java# L47) und dann Diesen Wert in die Ansicht einbetten.

@GetMapping("new")
String blank(Model model, @RequestParam Long categoryId) throws GeneralSecurityException {

    //Kategorie Existenzprüfung
    Category category = categoryDao.selectById(categoryId).orElseThrow(BadRequest::new);

    //Machen Sie einen Hash und binden Sie ihn in das versteckte Feld ein
    String hash = verifier.hash(categoryId);

    model.addAttribute("category", category);
    model.addAttribute("hash", hash);
    return "new-issue";
}
<input type="text" name="content"/>
<input type="hidden" name="categoryId" data-th-value="${category.id}"/>
<input type="hidden" name="hash" data-th-value="${hash}"/>
<button type="submit">Save</button>

Die Hash-Verarbeitung sieht folgendermaßen aus.

public String hash(Long value) throws GeneralSecurityException {
    Mac mac = Mac.getInstance("HmacSHA256");
    mac.init(key);
    byte[] hash = mac.doFinal(String.valueOf(value).getBytes());
    return IntStream.range(0, hash.length).mapToObj(i -> String.format("%02x", hash[i]))
            .collect(Collectors.joining());
}

Während des Registrierungsprozesses Hash die übermittelte Kategorie-ID mit HMAC und vergleiche sie mit dem übermittelten Hash-Wert /java/com/example/IssueController.java#L60).

if (verifier.verify(hash, categoryId) == false) {
    throw new BadRequest();
}

Jetzt haben Sie eine Prüfung, um zu verhindern, dass der Wert geändert wird, genau wie bei der Existenzprüfung.

verdienen

Wenn es mehrere Werte gibt und Sie alle Werte mit : oder . und Hash verbinden, benötigen Sie übrigens nur einen Hashwert, damit die Nutzlast der HTTP-Anforderung / -Antwort nicht ansteigt.

wichtiger Punkt

Da es sich nicht um eine strikte Existenzprüfung handelt, tritt eine Inkonsistenz auf, wenn die Kategorie, die beim Anzeigen des Registrierungsbildschirms vorhanden war, während des Registrierungsprozesses verschwindet. (Obwohl dies durch die Fremdschlüsseleinschränkung im Beispiel verhindert wird)

Daher müssen Sie vorsichtig sein, wenn Sie es nur auf Daten anwenden, die sich tagsüber nicht ändern (z. B. Abteilung im Fall eines Geschäftssystems).

Aus den oben genannten Gründen möchten Sie den Hash-Wert möglicherweise über Tage ungültig machen. In diesem Fall wird Hash the date together empfohlen. Auf diese Weise können Sie, wenn Sie die Zeitstempel zusammen hashen, ein Ablaufdatum haben, und wenn Sie jede Sitzungs-ID zusammen hashen, können Sie für jeden Benutzer einen gültigen Hash erstellen.

Eine weitere Einschränkung ist die Schlüsselverwaltung. Sie können einen zufälligen Wert erhalten, wenn Sie die Anwendung starten und als Schlüssel verwenden. Wenn Sie jedoch mehrere Instanzen der Anwendung in einer redundanten Konfiguration haben, müssen Sie Sticky-Sitzungen aktivieren oder den Schlüssel für alle Instanzen freigeben. es gibt. Ich denke, welche Art von Management von Fall zu Fall durchgeführt wird.

Zusammenfassung

Ich habe darüber nachgedacht, wie man mit HMAC die Gültigkeit des in das ausgeblendete Feld eingebetteten Werts überprüft. Es gibt einige Einschränkungen, aber ich denke, es gibt viele Situationen, in denen es angewendet werden kann.

Beispielcode ist auf GitHub verfügbar.

No-hmac Zweigprüfung auf Existenz mit DB, [hmac-verify](https: // s) Überprüfung mit HMAC //github.com/backpaper0/seac2016/tree/hmac-verify) Verzweigen Sie das Datum in den Hash, um das Ablaufdatum [master] festzulegen (https://github.com/backpaper0/seac2016). Es gibt Zweige, also vergleichen Sie bitte jeden.

Über ⛄️

Recommended Posts

Samshin über den Wert des versteckten Feldes
Hinweis zum Pfad von request.getRequestDispatcher
So zeigen Sie 0 auf der linken Seite des Standardeingabewerts an
Zeigen Sie Text über dem Bild an
Rückblick auf die Grundlagen von Java
[Ruby on Rails] Bis zur Einführung von RSpec
Installieren Sie die neueste Version von Jenkins unter Ubuntu 16
Geben Sie den Standardwert mit @Builder of Lombok an
Beispielcode zum Zuweisen eines Werts in der Eigenschaftendatei zu einem Feld des erwarteten Typs
[Ubuntu 20.04] Zeigt den Tag auf dem Datum / der Uhr an
So löschen / aktualisieren Sie das Listenfeld von OneToMany
Diffusionssimulation von Tinte, die auf die Wasseroberfläche tropft
[Java] So erhalten Sie den Maximalwert von HashMap
Zeigen Sie den Durchschnittswert der Bewertung als Stern an
Finden Sie mit Swift eine Annäherung an log (1 + x)
Wie ist der nächste Wert des Time-Objekts korrekt?
Versuchen Sie es mit dem Ruby on Rails-Abfrageattribut
Die Welt der Clara-Regeln (2)
Beurteilung des Kalenders
Die Welt der Clara-Regeln (4)
Die Welt der Clara-Regeln (1)
Die Welt der Clara-Regeln (3)
Die Welt der Clara-Regeln (5)
Die Idee der schnellen Sortierung
Festlegen des Werts von log4jdbc.properties
Die Idee von jQuery
So zeigen Sie das Auswahlfeld von time_select alle 30 Minuten an
Informationen zum Abschneiden von Zeichenfolgen um die Anzahl der Bytes unter Android
20190803_Java & k8s on Azure Die Geschichte vom Festivalbesuch
(Ruby on Rails6) Anzeige der Datenbank, die die ID der Datenbank erhalten hat
Alle Inhalte der Listenseite löschen [Ruby on Rails]
Ein Hinweis zum Seed-Feature von Ruby on Rails
Bis zur produktiven Bereitstellung der Hallo-App mit k3d auf Time4VPS
Aus der Gewohnheit, Wertobjekte für ein objektorientiertes Verständnis zu schaffen
So ändern Sie den Einstellwert von Springboot Hikari CP
[Swift] Ermittelt das Timing, wenn der Wert von textField geändert wird
Extrahieren Sie den eindeutig identifizierbaren Wert der von PostgreSQL erstellten Tabelle