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!
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.
⬇︎
⬇︎
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.
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.
Ä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.
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.
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.
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