Skip to content
This repository was archived by the owner on Feb 9, 2026. It is now read-only.

Commit 0dc6e84

Browse files
slotsu0809AsPulse
andauthored
docs(idea/sutera):11why sutera need to maintain idempotence (#48)
Co-authored-by: AsPulse / あすぱる <contact@aspulse.dev>
1 parent 0ee6714 commit 0dc6e84

File tree

5 files changed

+202
-0
lines changed

5 files changed

+202
-0
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# なぜSuteraネットワーク内の通信には羃等性が必要なのか
2+
## 概要
3+
Suteraネットワークでは多くのコンポーネントが情報を保持・中継する上、認証を行う中央サーバーが存在しません。そのため、電子署名以外にリクエストの正当性を保つ手段をもちません。
4+
しかし、まったく内容の同じリクエストならば電子署名を使い回すことが可能であり、リプレイ攻撃[^1]などが成立します。
5+
Suteraネットワークでは、このような任意のタイミングで過去のメッセージが送信されることによる悪意ある攻撃に耐性を持つことが必要です。この耐性を確保するために、すべての通信仕様で冪等性を保つ必要があります。
6+
7+
## 冪等性とは
8+
情報工学において冪等性(べきとうせい、英: idempotence)とは、ある操作を一度行っても複数回行っても同じ結果となることです。
9+
特に何回実行しても内部状態が変わらない操作を指します。[^3]
10+
冪等性の例として動画プレイヤーの一時停止ボタンを考えてみましょう。
11+
ある動画プレイヤーに一時停止ボタンが有り、そのボタンを押すたびに一時停止と再生が切り替わると仮定します。この場合では、「一時停止ボタンを押す」という同じ操作を複数回行うたびに応内部状態が変わるため、冪等性はないと言えます。
12+
次に一時停止ボタンと再生ボタンが分かれている場合を仮定します。この場合は一時停止ボタンを複数回押しても動画は停止したままであり、複数回同じ操作を行っても内部状態が変わらない、すなわち冪等性が保たれていると言えます。
13+
## 冪等性がない場合
14+
Suteraネットワーク内で頻繁に行われる「特定のユーザーが保持しているファイルの内容更新」を例に、リプレイ攻撃が有効となるような通信仕様を考えてみましょう。
15+
以下の図が冪等性がない場合の例です。この場合では最初にある人物Aが電子署名を付加したファイルを送信し、その後にAがそのファイルを更新して再び送信したと仮定します。
16+
ここで一番最初に送信した電子署名付きのファイルを悪意ある第三者が入手して、それを再送します。この場合、第三者が送信したファイルに付加されている電子署名は正常なものなのでサーバ側はこの更新を正常なものとして処理します。
17+
このように、電子署名だけでは同じファイルの送信を複数回行っても正常に処理してしまうため冪等性がないと言えます。
18+
![figure of discription unidempotence](image/unidempotence.drawio.png)
19+
20+
## 冪等性がある場合
21+
冪等性がある場合の例が以下の図です。Suteraネットワークでは冪等性を保つために電子署名にバージョン情報を追加しています。
22+
この例では先程の例と同様にある人物Aが電子署名を付加したファイルを送信し、その後に更新しています。しかし、この例では先程の例ではなかったバージョン情報が電子署名に追加されています。そのため、悪意のある第三者からリプレイ攻撃を行われていてもバージョン情報の整合性が取れず、サーバでの処理が拒否されます。
23+
このように、電子署名にバージョン情報を追加することで、同じ通信が複数回送信されても過去のバージョンに対する通信であることを認識でき、現在の状態を変更することはないため、冪等性が保たれていると言えます。
24+
![figure of discription idepotence](image/idempotence.drawio.png)
25+
26+
## 参考文献、脚注
27+
[^1]: リプレイ攻撃とは標的が送信した情報を入手し、その情報を再送信することで不正なアクセスを実現する攻撃手法です。 [^2]
28+
[^2]:リプレイ攻撃、SOMPO CYBER SECURITY サイバーセキュリティ用語集,閲覧2024-07-15, https://www.sompocybersecurity.com/column/glossary/replay-attack
29+
[^3]:冪等性,デジタル大辞泉,ジャパンナレッジ,閲覧2024-07-13,https://japanknowledge.com/library/

sutera/image/idempotence.drawio

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<mxfile host="app.diagrams.net" modified="2024-07-15T09:55:18.496Z" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36" etag="YbAUbL6R32Vz3vjtGQ1X" version="24.6.5" type="google">
2+
<diagram name="ページ1" id="R3fBSbPgkCisT6Ae5bC-">
3+
<mxGraphModel grid="1" page="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
4+
<root>
5+
<mxCell id="0" />
6+
<mxCell id="1" parent="0" />
7+
<mxCell id="mgZgLY458CLmu_6VowPx-1" value="" style="endArrow=classic;html=1;rounded=0;" edge="1" parent="1">
8+
<mxGeometry width="50" height="50" relative="1" as="geometry">
9+
<mxPoint x="230" y="440" as="sourcePoint" />
10+
<mxPoint x="710" y="440" as="targetPoint" />
11+
</mxGeometry>
12+
</mxCell>
13+
<mxCell id="mgZgLY458CLmu_6VowPx-2" value="あいうえお&lt;br&gt;a.txt" style="whiteSpace=wrap;html=1;shape=mxgraph.basic.roundRectCallout;dx=30;dy=15;size=5;boundedLbl=1;rotation=0;" vertex="1" parent="1">
14+
<mxGeometry x="290" y="370" width="100" height="60" as="geometry" />
15+
</mxCell>
16+
<mxCell id="mgZgLY458CLmu_6VowPx-3" value="" style="whiteSpace=wrap;html=1;shape=mxgraph.basic.oval_callout;rotation=-179;" vertex="1" parent="1">
17+
<mxGeometry x="290" y="450" width="80" height="60" as="geometry" />
18+
</mxCell>
19+
<mxCell id="mgZgLY458CLmu_6VowPx-4" value="OK" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
20+
<mxGeometry x="300" y="465" width="60" height="30" as="geometry" />
21+
</mxCell>
22+
<mxCell id="mgZgLY458CLmu_6VowPx-5" value="電子署名&amp;nbsp;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;" vertex="1" parent="1">
23+
<mxGeometry x="290" y="340" width="100" height="30" as="geometry" />
24+
</mxCell>
25+
<mxCell id="mgZgLY458CLmu_6VowPx-6" value="かきくけこ&lt;br&gt;a.txt" style="whiteSpace=wrap;html=1;shape=mxgraph.basic.roundRectCallout;dx=30;dy=15;size=5;boundedLbl=1;rotation=0;" vertex="1" parent="1">
26+
<mxGeometry x="450" y="370" width="100" height="60" as="geometry" />
27+
</mxCell>
28+
<mxCell id="mgZgLY458CLmu_6VowPx-7" value="電子署名" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;" vertex="1" parent="1">
29+
<mxGeometry x="450" y="340" width="100" height="30" as="geometry" />
30+
</mxCell>
31+
<mxCell id="mgZgLY458CLmu_6VowPx-8" value="" style="whiteSpace=wrap;html=1;shape=mxgraph.basic.oval_callout;rotation=-179;" vertex="1" parent="1">
32+
<mxGeometry x="414" y="450" width="80" height="60" as="geometry" />
33+
</mxCell>
34+
<mxCell id="mgZgLY458CLmu_6VowPx-9" value="OK" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
35+
<mxGeometry x="424" y="465" width="60" height="30" as="geometry" />
36+
</mxCell>
37+
<mxCell id="mgZgLY458CLmu_6VowPx-10" value="" style="shape=actor;whiteSpace=wrap;html=1;" vertex="1" parent="1">
38+
<mxGeometry x="240" y="370" width="40" height="60" as="geometry" />
39+
</mxCell>
40+
<mxCell id="mgZgLY458CLmu_6VowPx-11" value="" style="shape=actor;whiteSpace=wrap;html=1;" vertex="1" parent="1">
41+
<mxGeometry x="400" y="370" width="40" height="60" as="geometry" />
42+
</mxCell>
43+
<mxCell id="mgZgLY458CLmu_6VowPx-12" value="" style="endArrow=classic;html=1;rounded=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;exitX=0.5;exitY=0;exitDx=0;exitDy=0;" edge="1" parent="1" source="mgZgLY458CLmu_6VowPx-22" target="mgZgLY458CLmu_6VowPx-13">
44+
<mxGeometry width="50" height="50" relative="1" as="geometry">
45+
<mxPoint x="330" y="310" as="sourcePoint" />
46+
<mxPoint x="329.5" y="300" as="targetPoint" />
47+
</mxGeometry>
48+
</mxCell>
49+
<mxCell id="mgZgLY458CLmu_6VowPx-13" value="" style="shape=actor;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" vertex="1" parent="1">
50+
<mxGeometry x="320" y="210" width="40" height="60" as="geometry" />
51+
</mxCell>
52+
<mxCell id="mgZgLY458CLmu_6VowPx-14" value="Fake" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
53+
<mxGeometry x="310" y="180" width="60" height="30" as="geometry" />
54+
</mxCell>
55+
<mxCell id="mgZgLY458CLmu_6VowPx-15" value="" style="endArrow=classic;html=1;rounded=0;" edge="1" parent="1">
56+
<mxGeometry width="50" height="50" relative="1" as="geometry">
57+
<mxPoint x="380" y="270" as="sourcePoint" />
58+
<mxPoint x="620" y="310" as="targetPoint" />
59+
</mxGeometry>
60+
</mxCell>
61+
<mxCell id="mgZgLY458CLmu_6VowPx-16" value="送信データを入手" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
62+
<mxGeometry x="240" y="280" width="80" height="30" as="geometry" />
63+
</mxCell>
64+
<mxCell id="mgZgLY458CLmu_6VowPx-17" value="&lt;font color=&quot;#ff9999&quot;&gt;あいうえお&lt;br&gt;a.txt&lt;/font&gt;" style="whiteSpace=wrap;html=1;shape=mxgraph.basic.roundRectCallout;dx=30;dy=15;size=5;boundedLbl=1;rotation=0;" vertex="1" parent="1">
65+
<mxGeometry x="580" y="370" width="100" height="60" as="geometry" />
66+
</mxCell>
67+
<mxCell id="mgZgLY458CLmu_6VowPx-18" value="電子署名" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;" vertex="1" parent="1">
68+
<mxGeometry x="580" y="340" width="100" height="30" as="geometry" />
69+
</mxCell>
70+
<mxCell id="mgZgLY458CLmu_6VowPx-19" value="入手したデータを再送" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
71+
<mxGeometry x="460" y="250" width="140" height="30" as="geometry" />
72+
</mxCell>
73+
<mxCell id="mgZgLY458CLmu_6VowPx-20" value="" style="whiteSpace=wrap;html=1;shape=mxgraph.basic.oval_callout;rotation=-179;" vertex="1" parent="1">
74+
<mxGeometry x="550" y="450" width="80" height="60" as="geometry" />
75+
</mxCell>
76+
<mxCell id="mgZgLY458CLmu_6VowPx-21" value="&lt;font style=&quot;&quot; color=&quot;#ff9999&quot;&gt;NG&lt;/font&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
77+
<mxGeometry x="560" y="465" width="60" height="30" as="geometry" />
78+
</mxCell>
79+
<mxCell id="mgZgLY458CLmu_6VowPx-22" value="Ver1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;" vertex="1" parent="1">
80+
<mxGeometry x="290" y="320" width="100" height="20" as="geometry" />
81+
</mxCell>
82+
<mxCell id="mgZgLY458CLmu_6VowPx-23" value="Ver2" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;" vertex="1" parent="1">
83+
<mxGeometry x="450" y="320" width="100" height="20" as="geometry" />
84+
</mxCell>
85+
<mxCell id="mgZgLY458CLmu_6VowPx-24" value="&lt;font style=&quot;&quot; color=&quot;#ff9999&quot;&gt;Ver1&lt;/font&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;" vertex="1" parent="1">
86+
<mxGeometry x="580" y="320" width="100" height="20" as="geometry" />
87+
</mxCell>
88+
</root>
89+
</mxGraphModel>
90+
</diagram>
91+
</mxfile>
33.8 KB
Loading

sutera/image/unidempotence.drawio

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<mxfile host="app.diagrams.net" modified="2024-07-15T09:48:36.478Z" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36" etag="np00vjdldS02IiwD8okS" version="21.6.2" type="google">
2+
<diagram name="ページ1" id="MxPB7AwiKuvZppGrS-kM">
3+
<mxGraphModel grid="1" page="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
4+
<root>
5+
<mxCell id="0" />
6+
<mxCell id="1" parent="0" />
7+
<mxCell id="hBu6dRC_P7iXdVrWcmxq-1" value="" style="endArrow=classic;html=1;rounded=0;" edge="1" parent="1">
8+
<mxGeometry width="50" height="50" relative="1" as="geometry">
9+
<mxPoint x="230" y="440" as="sourcePoint" />
10+
<mxPoint x="710" y="440" as="targetPoint" />
11+
</mxGeometry>
12+
</mxCell>
13+
<mxCell id="hBu6dRC_P7iXdVrWcmxq-4" value="あいうえお&lt;br&gt;a.txt" style="whiteSpace=wrap;html=1;shape=mxgraph.basic.roundRectCallout;dx=30;dy=15;size=5;boundedLbl=1;rotation=0;" vertex="1" parent="1">
14+
<mxGeometry x="290" y="370" width="100" height="60" as="geometry" />
15+
</mxCell>
16+
<mxCell id="hBu6dRC_P7iXdVrWcmxq-5" value="" style="whiteSpace=wrap;html=1;shape=mxgraph.basic.oval_callout;rotation=-179;" vertex="1" parent="1">
17+
<mxGeometry x="290" y="450" width="80" height="60" as="geometry" />
18+
</mxCell>
19+
<mxCell id="hBu6dRC_P7iXdVrWcmxq-6" value="OK" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
20+
<mxGeometry x="300" y="465" width="60" height="30" as="geometry" />
21+
</mxCell>
22+
<mxCell id="hBu6dRC_P7iXdVrWcmxq-8" value="電子署名" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;" vertex="1" parent="1">
23+
<mxGeometry x="290" y="340" width="100" height="30" as="geometry" />
24+
</mxCell>
25+
<mxCell id="hBu6dRC_P7iXdVrWcmxq-10" value="かきくけこ&lt;br&gt;a.txt" style="whiteSpace=wrap;html=1;shape=mxgraph.basic.roundRectCallout;dx=30;dy=15;size=5;boundedLbl=1;rotation=0;" vertex="1" parent="1">
26+
<mxGeometry x="450" y="370" width="100" height="60" as="geometry" />
27+
</mxCell>
28+
<mxCell id="hBu6dRC_P7iXdVrWcmxq-11" value="電子署名" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;" vertex="1" parent="1">
29+
<mxGeometry x="450" y="340" width="100" height="30" as="geometry" />
30+
</mxCell>
31+
<mxCell id="hBu6dRC_P7iXdVrWcmxq-16" value="" style="whiteSpace=wrap;html=1;shape=mxgraph.basic.oval_callout;rotation=-179;" vertex="1" parent="1">
32+
<mxGeometry x="414" y="450" width="80" height="60" as="geometry" />
33+
</mxCell>
34+
<mxCell id="hBu6dRC_P7iXdVrWcmxq-17" value="OK" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
35+
<mxGeometry x="424" y="465" width="60" height="30" as="geometry" />
36+
</mxCell>
37+
<mxCell id="hBu6dRC_P7iXdVrWcmxq-18" value="" style="shape=actor;whiteSpace=wrap;html=1;" vertex="1" parent="1">
38+
<mxGeometry x="240" y="370" width="40" height="60" as="geometry" />
39+
</mxCell>
40+
<mxCell id="hBu6dRC_P7iXdVrWcmxq-19" value="" style="shape=actor;whiteSpace=wrap;html=1;" vertex="1" parent="1">
41+
<mxGeometry x="400" y="370" width="40" height="60" as="geometry" />
42+
</mxCell>
43+
<mxCell id="hBu6dRC_P7iXdVrWcmxq-26" value="" style="endArrow=classic;html=1;rounded=0;exitX=0.39;exitY=-0.067;exitDx=0;exitDy=0;exitPerimeter=0;" edge="1" parent="1" source="hBu6dRC_P7iXdVrWcmxq-8">
44+
<mxGeometry width="50" height="50" relative="1" as="geometry">
45+
<mxPoint x="329.5" y="320" as="sourcePoint" />
46+
<mxPoint x="329.5" y="300" as="targetPoint" />
47+
</mxGeometry>
48+
</mxCell>
49+
<mxCell id="hBu6dRC_P7iXdVrWcmxq-27" value="" style="shape=actor;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;" vertex="1" parent="1">
50+
<mxGeometry x="310" y="230" width="40" height="60" as="geometry" />
51+
</mxCell>
52+
<mxCell id="hBu6dRC_P7iXdVrWcmxq-28" value="Fake" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
53+
<mxGeometry x="300" y="200" width="60" height="30" as="geometry" />
54+
</mxCell>
55+
<mxCell id="hBu6dRC_P7iXdVrWcmxq-29" value="" style="endArrow=classic;html=1;rounded=0;" edge="1" parent="1">
56+
<mxGeometry width="50" height="50" relative="1" as="geometry">
57+
<mxPoint x="380" y="270" as="sourcePoint" />
58+
<mxPoint x="620" y="320" as="targetPoint" />
59+
</mxGeometry>
60+
</mxCell>
61+
<mxCell id="hBu6dRC_P7iXdVrWcmxq-30" value="送信データを入手" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
62+
<mxGeometry x="230" y="300" width="80" height="30" as="geometry" />
63+
</mxCell>
64+
<mxCell id="hBu6dRC_P7iXdVrWcmxq-31" value="&lt;font color=&quot;#ff9999&quot;&gt;あいうえお&lt;br&gt;a.txt&lt;/font&gt;" style="whiteSpace=wrap;html=1;shape=mxgraph.basic.roundRectCallout;dx=30;dy=15;size=5;boundedLbl=1;rotation=0;" vertex="1" parent="1">
65+
<mxGeometry x="580" y="370" width="100" height="60" as="geometry" />
66+
</mxCell>
67+
<mxCell id="hBu6dRC_P7iXdVrWcmxq-32" value="電子署名" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;" vertex="1" parent="1">
68+
<mxGeometry x="580" y="340" width="100" height="30" as="geometry" />
69+
</mxCell>
70+
<mxCell id="hBu6dRC_P7iXdVrWcmxq-33" value="入手したデータを再送" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
71+
<mxGeometry x="460" y="250" width="140" height="30" as="geometry" />
72+
</mxCell>
73+
<mxCell id="hBu6dRC_P7iXdVrWcmxq-35" value="" style="whiteSpace=wrap;html=1;shape=mxgraph.basic.oval_callout;rotation=-179;" vertex="1" parent="1">
74+
<mxGeometry x="550" y="450" width="80" height="60" as="geometry" />
75+
</mxCell>
76+
<mxCell id="hBu6dRC_P7iXdVrWcmxq-36" value="OK" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
77+
<mxGeometry x="560" y="465" width="60" height="30" as="geometry" />
78+
</mxCell>
79+
</root>
80+
</mxGraphModel>
81+
</diagram>
82+
</mxfile>
30.8 KB
Loading

0 commit comments

Comments
 (0)