[JAVA] Samshin sur la valeur du champ caché

C'est le 17e jour du Calendrier de l'avent de l'ingénieur système 2016.

Le 16ème jour était les [Points lors de l'application du SPA localement dans des applications Web non SPA] de M. Uga (http://qiita.com/uggds/items/1baf844e8fb1dc7c4b09). C'était un contenu d'actualité auquel j'ai immédiatement voulu me référer dans le prochain projet!

Vérification de la valeur du champ masqué

Lorsque vous souhaitez acheminer la valeur à l'écran pour enregistrer quelque chose, l'incorporer dans le champ masqué et la valeur correspond-elle au moment de l'enregistrement? Je pense que je vais le vérifier.

Par exemple, supposons que vous ayez une application comme soumettre en sélectionnant une catégorie, en ouvrant un nouvel écran de création de problème, en écrivant du contenu.

select-category.png

⬇︎

click-new.png

⬇︎

post-issue.png

Sur l'écran d'inscription, intégrez l'ID de catégorie dans le champ masqué.

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

Le processus d'enregistrement [vérifie si cette valeur existe dans la table des catégories](https://github.com/backpaper0/seac2016/blob/no-hmac/src/main/java/com/example/IssueController. java # L50).

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

    //Contrôle d'existence à nouveau au moment de l'inscription
    categoryDao.selectById(categoryId).orElseThrow(BadRequest::new);

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

Cette vérification semble un peu surchargée car j'accède à la base de données, et j'ai toujours pensé que ce serait gênant s'il y avait plus de valeurs à vérifier. Généralement, lorsque l'écran d'enregistrement est affiché, la valeur obtenue en recherchant la catégorie est intégrée, mais pourquoi dois-je vérifier l'existence même dans le processus d'enregistrement! Je me sens comme.

Cependant, si vous réécrivez le code HTML, vous pouvez soumettre des valeurs qui sont impossibles et vous devez les vérifier correctement.

J'ai donc pensé à vérifier la valeur en utilisant HMAC.

Qu'est-ce que HMAC

Un hachage avec une clé. Même si vous connaissez la valeur, vous ne pouvez pas obtenir la valeur de hachage sans connaître la clé. De plus, même si vous hachez la même valeur, vous obtiendrez des valeurs de hachage différentes si les clés sont différentes. Pour plus d'informations, rendez-vous sur Gugu.

Vérifiez la valeur avec HMAC

Modifiez la partie où le contrôle d'existence de la catégorie a été effectué en accédant au DB au contrôle à l'aide de HMAC.

Tout d'abord, lors de l'ouverture de l'écran d'enregistrement, [Hash category ID with HMAC](https://github.com/backpaper0/seac2016/blob/hmac-verify/src/main/java/com/example/IssueController.java# L47) puis Incorporer cette valeur dans la vue.

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

    //Vérification d'existence de catégorie
    Category category = categoryDao.selectById(categoryId).orElseThrow(BadRequest::new);

    //Faites un hachage et intégrez-le dans le champ caché
    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>

Le traitement du hachage ressemble à ceci.

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());
}

Dans le processus d'enregistrement, Hachez l'ID de catégorie soumis avec HMAC et comparez-le avec la valeur de hachage soumise /java/com/example/IssueController.java#L60).

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

Vous avez maintenant une vérification pour empêcher la valeur d'être modifiée, tout comme la vérification d'existence.

mérite

À propos, s'il y a plusieurs valeurs, si vous connectez toutes les valeurs avec : ou . et hash, vous n'avez besoin que d'une valeur de hachage, de sorte que la charge utile de la requête / réponse HTTP ne gonfle pas.

point important

Comme il ne s'agit pas d'un contrôle d'existence strict, une incohérence se produira si la catégorie qui était présente lorsque l'écran d'enregistrement est affiché disparaît pendant le processus d'enregistrement. (Bien que cela soit empêché par la contrainte clé étrangère dans l'exemple)

Par conséquent, vous devez faire attention à ne l'appliquer qu'aux données qui ne changent pas au cours de la journée (par exemple, département dans le cas d'un système d'entreprise).

En outre, pour les raisons mentionnées ci-dessus, vous souhaiterez peut-être invalider la valeur de hachage au fil des jours. Dans ce cas, Hash the date together est recommandé. De cette façon, si vous hachez les horodatages ensemble, vous pouvez avoir une date d'expiration, et si vous hachez chaque ID de session ensemble, vous pouvez créer un hachage valide pour chaque utilisateur.

Une autre mise en garde est la gestion des clés. Vous pouvez obtenir une valeur aléatoire lorsque vous démarrez l'application et l'utilisez comme clé, mais si vous avez plusieurs instances de l'application dans une configuration redondante, vous devez activer les sessions persistantes ou partager la clé entre toutes les instances. il y a. Je pense que ce type de gestion se fait au cas par cas.

Résumé

J'ai réfléchi à la façon d'utiliser HMAC pour vérifier la validité de la valeur intégrée dans le champ caché. Il y a quelques mises en garde, mais je pense qu'il y a de nombreuses situations où cela peut être appliqué.

Un exemple de code est disponible sur GitHub.

No-hmac vérification de l'existence d'une branche à l'aide de la base de données, [hmac-verify](https: // s) vérification avec HMAC //github.com/backpaper0/seac2016/tree/hmac-verify) Branch, puis mélangez la date dans le hachage pour définir la date d'expiration master Il y a des succursales, alors comparez-les.

Ci-dessus ⛄️

Recommended Posts

Samshin sur la valeur du champ caché
Remarque sur le chemin de request.getRequestDispatcher
Comment afficher 0 sur le côté gauche de la valeur d'entrée standard
Afficher le texte en haut de l'image
Retour sur les bases de Java
[Ruby on Rails] Jusqu'à l'introduction de RSpec
Installez la dernière version de Jenkins sur Ubuntu 16
Spécifiez la valeur par défaut avec @Builder of Lombok
Exemple de code pour attribuer une valeur dans le fichier de propriétés à un champ du type attendu
[Ubuntu 20.04] Afficher le jour à la date / horloge
Comment supprimer / mettre à jour le champ de liste de OneToMany
Simulation de diffusion de l'encre coulant à la surface de l'eau
[Java] Comment obtenir la valeur maximale de HashMap
Afficher la valeur moyenne de l'évaluation sous forme d'étoile
Trouvez la valeur approximative de log (1 + x) avec Swift
Comment la valeur suivante de l'objet Time est-elle correcte?
Essayez d'utiliser l'attribut de requête Ruby on Rails
Le monde de Clara-Rules (2)
Jugement du calendrier
Le monde de Clara-Rules (4)
Le monde de Clara-Rules (1)
Le monde de Clara-Rules (3)
Le monde de Clara-Rules (5)
L'idée du tri rapide
Valeur de réglage de log4jdbc.properties
L'idée de jQuery
Comment afficher le champ de sélection de time_select toutes les 30 minutes
À propos de la troncature de String par le nombre d'octets sur Android
20190803_Java & k8s sur Azure L'histoire d'aller au festival
(Ruby on Rails6) Affichage de la base de données qui a obtenu l'identifiant de la base de données
Supprimer tout le contenu de la page de liste [Ruby on Rails]
Une note sur la fonction de départ de Ruby on Rails
Jusqu'au déploiement en production de hello-app avec k3d sur Time4VPS
De l'habitude de créer des objets de valeur pour une compréhension orientée objet
Comment modifier la valeur de réglage de Springboot Hikari CP
[Swift] Obtenez le moment où la valeur de textField est modifiée
Extraire la valeur identifiable de manière unique de la table créée par PostgreSQL