feat: 가상화 문서들 추가

This commit is contained in:
DongHyeonka
2026-09-10 08:54:05 +09:00
parent e9f6a93327
commit 43e1aadef0
695 changed files with 153404 additions and 12754 deletions
@@ -10,16 +10,16 @@ BFF CSRF endpoint가 raw XSRF cookie와 masked JSON token으로 분기하고, SP
## Elements and evidence
- **BFF · /bff/csrf** (service): CookieCsrfTokenRepository와 CsrfController를 통해 raw cookie와 masked JSON 응답을 만드는 endpoint. Evidence: L819L844.
- **Browser cookie · raw** (credential): Cookie repository가 path /에 설정하며 SPA가 document.cookie로 읽는 raw CSRF token. Evidence: L827L834, L844L856.
- **JSON body · masked** (data): Request attribute용 token을 masked한 JSON 표현으로, SPA는 token 값이 아니라 headerName만 사용한다. Evidence: L836L846.
- **SPA POST 조립** (component): Raw cookie 값을 X-XSRF-TOKEN header에 넣어 preference POST를 만드는 browser code. Evidence: L846L856, L862L870.
- **Spring CSRF filter** (security): Repository의 expected raw token과 submitted raw header를 controller 실행 전에 비교하는 방어선. Evidence: L854L854, L873L873, L897L904.
- **BFF · /bff/csrf** (service): CookieCsrfTokenRepository와 CsrfController를 통해 raw cookie와 masked JSON 응답을 만드는 endpoint. Evidence: L855L880.
- **Browser cookie · raw** (credential): Cookie repository가 path /에 설정하며 SPA가 document.cookie로 읽는 raw CSRF token. Evidence: L863L870, L880L892.
- **JSON body · masked** (data): Request attribute용 token을 masked한 JSON 표현으로, SPA는 token 값이 아니라 headerName만 사용한다. Evidence: L872L882.
- **SPA POST 조립** (component): Raw cookie 값을 X-XSRF-TOKEN header에 넣어 preference POST를 만드는 browser code. Evidence: L882L892, L898L906.
- **Spring CSRF filter** (security): Repository의 expected raw token과 submitted raw header를 controller 실행 전에 비교하는 방어선. Evidence: L890L890, L909L909, L933L940.
## Relationships
- **SPA POST 조립 → Spring CSRF filter:** Cookie raw = Header raw. Evidence: L848L873.
- **BFF · /bff/csrf → JSON body · masked:** masked JSON. Evidence: L836L844.
- **BFF · /bff/csrf → Browser cookie · raw:** Set-Cookie · raw. Evidence: L827L834.
- **JSON body · masked → SPA POST 조립:** headerName only. Evidence: L846L856.
- **Browser cookie · raw → SPA POST 조립:** document.cookie · raw. Evidence: L846L856.
- **SPA POST 조립 → Spring CSRF filter:** raw 대조. Evidence: L884L909.
- **BFF · /bff/csrf → JSON body · masked:** masked JSON. Evidence: L872L880.
- **BFF · /bff/csrf → Browser cookie · raw:** Set-Cookie · raw. Evidence: L863L870.
- **JSON body · masked → SPA POST 조립:** headerName. Evidence: L882L892.
- **Browser cookie · raw → SPA POST 조립:** raw cookie. Evidence: L882L892.
@@ -18,6 +18,6 @@ n4: "Spring CSRF filter" {
}
n0 -> n1: "Set-Cookie · raw"
n0 -> n2: "masked JSON"
n1 -> n3: "document.cookie · raw"
n2 -> n3: "headerName only"
n3 -> n4: "Cookie raw = Header raw"
n1 -> n3: "raw cookie"
n2 -> n3: "headerName"
n3 -> n4: "raw 대조"
@@ -9,7 +9,7 @@ digraph techviz {
n4 [label="Spring CSRF filter", shape=box, style="rounded,filled"];
n0 -> n1 [label="Set-Cookie · raw", style=solid];
n0 -> n2 [label="masked JSON", style=solid];
n1 -> n3 [label="document.cookie · raw", style=solid];
n2 -> n3 [label="headerName only", style=solid];
n3 -> n4 [label="Cookie raw = Header raw", style=solid];
n1 -> n3 [label="raw cookie", style=solid];
n2 -> n3 [label="headerName", style=solid];
n3 -> n4 [label="raw 대조", style=solid];
}
@@ -5,22 +5,22 @@
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="n_csrf-endpoint" value="BFF · /bff/csrf" tooltip="CookieCsrfTokenRepository와 CsrfController를 통해 raw cookie와 masked JSON 응답을 만드는 endpoint. | Evidence: L819-L844" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;" vertex="1" parent="1">
<mxCell id="n_csrf-endpoint" value="BFF · /bff/csrf" tooltip="CookieCsrfTokenRepository와 CsrfController를 통해 raw cookie와 masked JSON 응답을 만드는 endpoint. | Evidence: L855-L880" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;" vertex="1" parent="1">
<mxGeometry x="70.0" y="171.5" width="150.0" height="64.0" as="geometry"/>
</mxCell>
<mxCell id="n_masked-json" value="JSON body · masked&lt;br/&gt;token = XOR/Base64&lt;br/&gt;headerName metadata&lt;br/&gt;POST token 값으로 미사용" tooltip="Request attribute용 token을 masked한 JSON 표현으로, SPA는 token 값이 아니라 headerName만 사용한다. | Evidence: L836-L846" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;shape=document;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxCell id="n_masked-json" value="JSON body · masked&lt;br/&gt;token = XOR/Base64&lt;br/&gt;headerName metadata&lt;br/&gt;POST 헤더 미사용" tooltip="Request attribute용 token을 masked한 JSON 표현으로, SPA는 token 값이 아니라 headerName만 사용한다. | Evidence: L872-L882" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;shape=document;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="380.0" y="60.0" width="220.0" height="110.0" as="geometry"/>
</mxCell>
<mxCell id="n_raw-cookie" value="Browser cookie · raw&lt;br/&gt;XSRF-TOKEN&lt;br/&gt;JavaScript-readable&lt;br/&gt;실제 header data source" tooltip="Cookie repository가 path /에 설정하며 SPA가 document.cookie로 읽는 raw CSRF token. | Evidence: L827-L834, L844-L856" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;strokeColor=#2563eb;strokeWidth=2;" vertex="1" parent="1">
<mxCell id="n_raw-cookie" value="Browser cookie · raw&lt;br/&gt;XSRF-TOKEN&lt;br/&gt;JavaScript-readable&lt;br/&gt;실제 header data source" tooltip="Cookie repository가 path /에 설정하며 SPA가 document.cookie로 읽는 raw CSRF token. | Evidence: L863-L870, L880-L892" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;strokeColor=#2563eb;strokeWidth=2;" vertex="1" parent="1">
<mxGeometry x="399.5" y="242.0" width="181.0" height="105.0" as="geometry"/>
</mxCell>
<mxCell id="n_post-assembler" value="SPA POST 조립&lt;br/&gt;Cookie 자동 첨부&lt;br/&gt;document.cookie raw → header&lt;br/&gt;JSON headerName만 사용" tooltip="Raw cookie 값을 X-XSRF-TOKEN header에 넣어 preference POST를 만드는 browser code. | Evidence: L846-L856, L862-L870" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;" vertex="1" parent="1">
<mxCell id="n_post-assembler" value="SPA POST 조립&lt;br/&gt;Cookie 자동 첨부&lt;br/&gt;document.cookie raw → header&lt;br/&gt;JSON headerName만 사용" tooltip="Raw cookie 값을 X-XSRF-TOKEN header에 넣어 preference POST를 만드는 browser code. | Evidence: L882-L892, L898-L906" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;" vertex="1" parent="1">
<mxGeometry x="760.0" y="151.0" width="230.0" height="105.0" as="geometry"/>
</mxCell>
<mxCell id="n_csrf-filter" value="Spring CSRF filter&lt;br/&gt;raw cookie = raw header 비교&lt;br/&gt;일치 → controller&lt;br/&gt;부재·불일치 → 403" tooltip="Repository의 expected raw token과 submitted raw header를 controller 실행 전에 비교하는 방어선. | Evidence: L854-L854, L873-L873, L897-L904" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;" vertex="1" parent="1">
<mxCell id="n_csrf-filter" value="Spring CSRF filter&lt;br/&gt;raw cookie = raw header 비교&lt;br/&gt;일치 → controller&lt;br/&gt;부재·불일치 → 403" tooltip="Repository의 expected raw token과 submitted raw header를 controller 실행 전에 비교하는 방어선. | Evidence: L890-L890, L909-L909, L933-L940" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;" vertex="1" parent="1">
<mxGeometry x="1150.0" y="151.0" width="216.0" height="105.0" as="geometry"/>
</mxCell>
<mxCell id="e_assembler-to-filter" value="Cookie raw = Header raw" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_post-assembler" target="n_csrf-filter">
<mxCell id="e_assembler-to-filter" value="raw 대조" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_post-assembler" target="n_csrf-filter">
<mxGeometry relative="1" as="geometry">
<mxPoint x="1070.0" y="175.5" as="offset"/>
</mxGeometry>
@@ -35,12 +35,12 @@
<mxPoint x="333.8" y="253.5" as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="e_masked-json-to-assembler" value="headerName only" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_masked-json" target="n_post-assembler">
<mxCell id="e_masked-json-to-assembler" value="headerName" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_masked-json" target="n_post-assembler">
<mxGeometry relative="1" as="geometry">
<mxPoint x="704.0" y="154.8" as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="e_raw-cookie-to-assembler" value="document.cookie · raw" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_raw-cookie" target="n_post-assembler">
<mxCell id="e_raw-cookie-to-assembler" value="raw cookie" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_raw-cookie" target="n_post-assembler">
<mxGeometry relative="1" as="geometry">
<mxPoint x="694.2" y="253.5" as="offset"/>
</mxGeometry>
@@ -66,9 +66,9 @@
{
"id": "edge-label-assembler-to-filter",
"type": "text",
"x": 978.0,
"x": 1025.0,
"y": 163.5,
"width": 184,
"width": 90,
"height": 24,
"angle": 0,
"strokeColor": "#1e1e1e",
@@ -94,11 +94,11 @@
"locked": false,
"fontSize": 13,
"fontFamily": 5,
"text": "Cookie raw = Header raw",
"text": "raw 대조",
"textAlign": "center",
"verticalAlign": "middle",
"containerId": null,
"originalText": "Cookie raw = Header raw",
"originalText": "raw 대조",
"autoResize": true,
"lineHeight": 1.25
},
@@ -363,9 +363,9 @@
{
"id": "edge-label-masked-json-to-assembler",
"type": "text",
"x": 644.0,
"x": 659.0,
"y": 142.75,
"width": 120,
"width": 90,
"height": 24,
"angle": 0,
"strokeColor": "#1e1e1e",
@@ -391,11 +391,11 @@
"locked": false,
"fontSize": 13,
"fontFamily": 5,
"text": "headerName only",
"text": "headerName",
"textAlign": "center",
"verticalAlign": "middle",
"containerId": null,
"originalText": "headerName only",
"originalText": "headerName",
"autoResize": true,
"lineHeight": 1.25
},
@@ -462,9 +462,9 @@
{
"id": "edge-label-raw-cookie-to-assembler",
"type": "text",
"x": 610.25,
"x": 649.25,
"y": 241.5,
"width": 168,
"width": 90,
"height": 24,
"angle": 0,
"strokeColor": "#1e1e1e",
@@ -490,11 +490,11 @@
"locked": false,
"fontSize": 13,
"fontFamily": 5,
"text": "document.cookie · raw",
"text": "raw cookie",
"textAlign": "center",
"verticalAlign": "middle",
"containerId": null,
"originalText": "document.cookie · raw",
"originalText": "raw cookie",
"autoResize": true,
"lineHeight": 1.25
},
@@ -628,11 +628,11 @@
"locked": false,
"fontSize": 15,
"fontFamily": 5,
"text": "JSON body · masked\ntoken = XOR/Base64\nheaderName metadata\nPOST token 값으로 미사용",
"text": "JSON body · masked\ntoken = XOR/Base64\nheaderName metadata\nPOST 헤더 미사용",
"textAlign": "center",
"verticalAlign": "middle",
"containerId": null,
"originalText": "JSON body · masked\ntoken = XOR/Base64\nheaderName metadata\nPOST token 값으로 미사용",
"originalText": "JSON body · masked\ntoken = XOR/Base64\nheaderName metadata\nPOST 헤더 미사용",
"autoResize": true,
"lineHeight": 1.25
},
@@ -2,14 +2,14 @@
"harness_version": "0.2.0",
"spec_id": "ap3-csrf-boundary",
"spec_version": "1.1",
"spec_sha256": "fe7eed6a9b09c9ca13e32c04d27d1b245676e405bd3f432e363794918772e2b9",
"spec_sha256": "d10a5d627e8436b300e3bb55073f23b1dc389c50c81f572355af73183a5a52d1",
"source_context": {
"document": "document.md",
"document_sha256": "df4d1a604c74e756672b5b40510abfedb8c67b39af280a5f51985ea9972f5371",
"document_sha256": "e2cc061f683294c937f089ad874cbf7a617f7313c07a92c2148fb11287a0da37",
"anchor": {
"kind": "marker",
"value": "ap3-csrf-boundary",
"line": 858
"kind": "heading",
"value": "AP3 완주: session cookie가 BFF의 downstream Bearer가 되기까지",
"line": 681
}
},
"outputs": [
@@ -8,6 +8,6 @@ flowchart LR
n4["Spring CSRF filter"]
n0 -->|"Set-Cookie · raw"| n1
n0 -->|"masked JSON"| n2
n1 -->|"document.cookie · raw"| n3
n2 -->|"headerName only"| n3
n3 -->|"Cookie raw = Header raw"| n4
n1 -->|"raw cookie"| n3
n2 -->|"headerName"| n3
n3 -->|"raw 대조"| n4
@@ -2,7 +2,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1411" height="392" viewBox="0 0 1411 392" role="img" aria-labelledby="diagram-title diagram-description">
<title id="diagram-title">AP3의 masked CSRF 응답과 raw POST credential</title>
<desc id="diagram-description">왼쪽의 BFF CSRF endpoint에서 두 결과가 갈라진다. XSRF-TOKEN cookie에는 raw token이 저장되고 JSON body에는 XOR와 Base64로 masked된 token 및 headerName이 담긴다. 두 결과는 SPA의 POST 조립 단계로 모이지만, JSON에서는 headerName만 사용하고 실제 X-XSRF-TOKEN 값은 document.cookie에서 읽은 raw token이다. POST에는 같은 raw 값을 가진 cookie와 header가 함께 도달하고 Spring CSRF filter가 일치 여부를 확인한다.</desc>
<metadata>{&quot;techviz&quot;:{&quot;spec_version&quot;:&quot;1.1&quot;,&quot;id&quot;:&quot;ap3-csrf-boundary&quot;,&quot;profile&quot;:&quot;component-flow&quot;},&quot;source_context&quot;:{&quot;document&quot;:&quot;document.md&quot;,&quot;document_sha256&quot;:&quot;df4d1a604c74e756672b5b40510abfedb8c67b39af280a5f51985ea9972f5371&quot;,&quot;anchor&quot;:{&quot;kind&quot;:&quot;marker&quot;,&quot;value&quot;:&quot;ap3-csrf-boundary&quot;,&quot;line&quot;:858}},&quot;evidence_policy&quot;:&quot;Each factual element cites source lines or is marked assumption.&quot;,&quot;diagram_only&quot;:true}</metadata>
<metadata>{&quot;techviz&quot;:{&quot;spec_version&quot;:&quot;1.1&quot;,&quot;id&quot;:&quot;ap3-csrf-boundary&quot;,&quot;profile&quot;:&quot;component-flow&quot;},&quot;source_context&quot;:{&quot;document&quot;:&quot;document.md&quot;,&quot;document_sha256&quot;:&quot;e2cc061f683294c937f089ad874cbf7a617f7313c07a92c2148fb11287a0da37&quot;,&quot;anchor&quot;:{&quot;kind&quot;:&quot;heading&quot;,&quot;value&quot;:&quot;AP3 완주: session cookie가 BFF의 downstream Bearer가 되기까지&quot;,&quot;line&quot;:681}},&quot;evidence_policy&quot;:&quot;Each factual element cites source lines or is marked assumption.&quot;,&quot;diagram_only&quot;:true}</metadata>
<defs>
<marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" />
@@ -50,35 +50,35 @@
</style>
</defs>
<rect class="canvas" width="1411" height="392" />
<polyline class="edge kind-request style-solid emphasis-primary" points="990.0,203.5 1070.0,203.5 1070.0,203.5 1150.0,203.5" data-evidence="848-873" />
<rect class="edge-label-bg" x="984.0" y="161.5" width="172.1" height="22" rx="3" />
<text class="edge-label" x="1070.0" y="176.5">Cookie raw = Header raw</text>
<polyline class="edge kind-response style-solid emphasis-normal semantic-dashed" points="220.0,194.5 300.0,194.5 300.0,115.0 380.0,115.0" data-evidence="836-844" />
<polyline class="edge kind-request style-solid emphasis-primary" points="990.0,203.5 1070.0,203.5 1070.0,203.5 1150.0,203.5" data-evidence="884-909" />
<rect class="edge-label-bg" x="1040.9" y="161.5" width="58.2" height="22" rx="3" />
<text class="edge-label" x="1070.0" y="176.5">raw 대조</text>
<polyline class="edge kind-response style-solid emphasis-normal semantic-dashed" points="220.0,194.5 300.0,194.5 300.0,115.0 380.0,115.0" data-evidence="872-880" />
<rect class="edge-label-bg" x="278.1" y="140.8" width="91.7" height="22" rx="3" />
<text class="edge-label" x="324.0" y="155.8">masked JSON</text>
<polyline class="edge kind-response style-solid emphasis-normal semantic-dashed" points="220.0,212.5 309.8,212.5 309.8,294.5 399.5,294.5" data-evidence="827-834" />
<polyline class="edge kind-response style-solid emphasis-normal semantic-dashed" points="220.0,212.5 309.8,212.5 309.8,294.5 399.5,294.5" data-evidence="863-870" />
<rect class="edge-label-bg" x="271.1" y="239.5" width="125.2" height="22" rx="3" />
<text class="edge-label" x="333.8" y="254.5">Set-Cookie · raw</text>
<polyline class="edge kind-data style-solid emphasis-normal" points="600.0,115.0 680.0,115.0 680.0,194.5 760.0,194.5" data-evidence="846-856" />
<rect class="edge-label-bg" x="644.8" y="140.8" width="118.5" height="22" rx="3" />
<text class="edge-label" x="704.0" y="155.8">headerName only</text>
<polyline class="edge kind-data style-solid emphasis-primary" points="580.5,294.5 670.2,294.5 670.2,212.5 760.0,212.5" data-evidence="846-856" />
<rect class="edge-label-bg" x="614.9" y="239.5" width="158.7" height="22" rx="3" />
<text class="edge-label" x="694.2" y="254.5">document.cookie · raw</text>
<polyline class="edge kind-data style-solid emphasis-normal" points="600.0,115.0 680.0,115.0 680.0,194.5 760.0,194.5" data-evidence="882-892" />
<rect class="edge-label-bg" x="661.5" y="140.8" width="85.0" height="22" rx="3" />
<text class="edge-label" x="704.0" y="155.8">headerName</text>
<polyline class="edge kind-data style-solid emphasis-primary" points="580.5,294.5 670.2,294.5 670.2,212.5 760.0,212.5" data-evidence="882-892" />
<rect class="edge-label-bg" x="651.8" y="239.5" width="85.0" height="22" rx="3" />
<text class="edge-label" x="694.2" y="254.5">raw cookie</text>
<g id="node-csrf-endpoint">
<rect class="node-shape kind-service emphasis-normal role-source" data-evidence="819-844" x="70.0" y="171.5" width="150.0" height="64.0" rx="7" />
<rect class="node-shape kind-service emphasis-normal role-source" data-evidence="855-880" x="70.0" y="171.5" width="150.0" height="64.0" rx="7" />
<text class="node-label" x="145.0" y="201.5">BFF · /bff/csrf</text>
</g>
<g id="node-masked-json">
<path class="node-shape kind-data emphasis-normal role-store" data-evidence="836-846" d="M 380.0 60.0 H 569.2 L 600.0 90.8 V 170.0 H 380.0 Z M 569.2 60.0 V 90.8 H 600.0" />
<path class="node-shape kind-data emphasis-normal role-store" data-evidence="872-882" d="M 380.0 60.0 H 569.2 L 600.0 90.8 V 170.0 H 380.0 Z M 569.2 60.0 V 90.8 H 600.0" />
<text class="node-label" x="490.0" y="89.0">JSON body · masked</text>
<line class="node-detail-divider" x1="394.0" y1="110.0" x2="586.0" y2="110.0" />
<text class="node-detail" x="396.0" y="127.0">token = XOR/Base64</text>
<text class="node-detail" x="396.0" y="143.0">headerName metadata</text>
<text class="node-detail" x="396.0" y="159.0">POST token 값으로 미사용</text>
<text class="node-detail" x="396.0" y="159.0">POST 헤더 미사용</text>
</g>
<g id="node-raw-cookie">
<rect class="node-shape kind-credential emphasis-primary role-store" data-evidence="827-834,844-856" x="399.5" y="242.0" width="181.0" height="105.0" rx="7" />
<rect class="node-shape kind-credential emphasis-primary role-store" data-evidence="863-870,880-892" x="399.5" y="242.0" width="181.0" height="105.0" rx="7" />
<text class="node-label" x="490.0" y="269.0">Browser cookie · raw</text>
<line class="node-detail-divider" x1="413.5" y1="290.0" x2="566.5" y2="290.0" />
<text class="node-detail" x="415.5" y="307.0">XSRF-TOKEN</text>
@@ -86,7 +86,7 @@
<text class="node-detail" x="415.5" y="339.0">실제 header data source</text>
</g>
<g id="node-post-assembler">
<rect class="node-shape kind-component emphasis-normal role-service" data-evidence="846-856,862-870" x="760.0" y="151.0" width="230.0" height="105.0" rx="7" />
<rect class="node-shape kind-component emphasis-normal role-service" data-evidence="882-892,898-906" x="760.0" y="151.0" width="230.0" height="105.0" rx="7" />
<text class="node-label" x="875.0" y="178.0">SPA POST 조립</text>
<line class="node-detail-divider" x1="774.0" y1="199.0" x2="976.0" y2="199.0" />
<text class="node-detail" x="776.0" y="216.0">Cookie 자동 첨부</text>
@@ -94,7 +94,7 @@
<text class="node-detail" x="776.0" y="248.0">JSON headerName만 사용</text>
</g>
<g id="node-csrf-filter">
<rect class="node-shape kind-security emphasis-normal role-sink" data-evidence="854-854,873-873,897-904" x="1150.0" y="151.0" width="216.0" height="105.0" rx="7" />
<rect class="node-shape kind-security emphasis-normal role-sink" data-evidence="890-890,909-909,933-940" x="1150.0" y="151.0" width="216.0" height="105.0" rx="7" />
<text class="node-label" x="1258.0" y="178.0">Spring CSRF filter</text>
<line class="node-detail-divider" x1="1164.0" y1="199.0" x2="1352.0" y2="199.0" />
<text class="node-detail" x="1166.0" y="216.0">raw cookie = raw header 비교</text>

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB