<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>セキュリティ | Seek Rise</title>
	<atom:link href="https://seek-rise.com/tag/%E3%82%BB%E3%82%AD%E3%83%A5%E3%83%AA%E3%83%86%E3%82%A3/feed/" rel="self" type="application/rss+xml" />
	<link>https://seek-rise.com</link>
	<description></description>
	<lastBuildDate>Sat, 03 Jan 2026 14:29:57 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.1</generator>

<image>
	<url>https://seek-rise.com/wp-content/uploads/2019/10/cropped-favicon-32x32.png</url>
	<title>セキュリティ | Seek Rise</title>
	<link>https://seek-rise.com</link>
	<width>32</width>
	<height>32</height>
</image> 
<atom:link rel="hub" href="https://pubsubhubbub.appspot.com"/><atom:link rel="hub" href="https://pubsubhubbub.superfeedr.com"/><atom:link rel="hub" href="https://websubhub.com/hub"/><site xmlns="com-wordpress:feed-additions:1">167377966</site>	<item>
		<title>6-11 CSRFとは？仕組みと対策</title>
		<link>https://seek-rise.com/web-development/php-basic/post-441/</link>
					<comments>https://seek-rise.com/web-development/php-basic/post-441/#respond</comments>
		
		<dc:creator><![CDATA[NOA（ノア）]]></dc:creator>
		<pubDate>Mon, 22 Dec 2025 14:19:24 +0000</pubDate>
				<category><![CDATA[Web開発学習ロードマップ]]></category>
		<category><![CDATA[6.PHP基礎]]></category>
		<category><![CDATA[初心者]]></category>
		<category><![CDATA[PHP基礎]]></category>
		<category><![CDATA[セキュリティ]]></category>
		<category><![CDATA[CSRF]]></category>
		<category><![CDATA[Web開発]]></category>
		<guid isPermaLink="false">https://seek-rise.com/?p=441</guid>

					<description><![CDATA[前の記事では、XSS（クロスサイトスクリプティング） という「表示時の危険性」について学びました。 今回扱う CSRF は、それとは別の方向から攻撃が行われます。 CSRFは、ユーザーが意図していない操作を、正規ユーザー [&#8230;]]]></description>
										<content:encoded><![CDATA[<p data-start="236" data-end="295">前の記事では、<br data-start="243" data-end="246" /><strong data-start="246" data-end="269">XSS（クロスサイトスクリプティング）</strong> という<br data-start="273" data-end="276" />「表示時の危険性」について学びました。</p>
<p data-start="297" data-end="335">今回扱う <strong data-start="302" data-end="310">CSRF</strong> は、<br data-start="313" data-end="316" />それとは別の方向から攻撃が行われます。</p>
<p data-start="337" data-end="395">CSRFは、<br data-start="343" data-end="346" /><strong data-start="346" data-end="391">ユーザーが意図していない操作を、<br data-start="364" data-end="367" />正規ユーザーとして実行させられてしまう脆弱性</strong> です。</p>
<p data-start="397" data-end="435">フォーム処理を行うPHPでは、<br data-start="412" data-end="415" /><strong data-start="415" data-end="428">CSRF対策は必須</strong> になります。</p>
<p data-start="437" data-end="501">この記事では、<br data-start="444" data-end="447" /><strong data-start="447" data-end="484">CSRFとは何か、なぜ危険なのか、<br data-start="466" data-end="469" />PHPでの基本的な対策方法</strong> を<br data-start="486" data-end="489" />コード付きで解説します。</p>
<hr data-start="503" data-end="506" />

  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-2" checked><label class="toc-title" for="toc-checkbox-2">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">この記事で学べること</a></li><li><a href="#toc2" tabindex="0">CSRFとは何か</a></li><li><a href="#toc3" tabindex="0">CSRF攻撃の典型的な流れ</a></li><li><a href="#toc4" tabindex="0">CSRFで何が起こるのか</a></li><li><a href="#toc5" tabindex="0">なぜCSRFが起きるのか</a></li><li><a href="#toc6" tabindex="0">XSSとCSRFの違い</a></li><li><a href="#toc7" tabindex="0">CSRF対策の基本は「トークン」</a></li><li><a href="#toc8" tabindex="0">PHPでCSRFトークンを生成する</a><ol><li><a href="#toc9" tabindex="0">サンプルコード①：トークン生成</a></li><li><a href="#toc10" tabindex="0">コードの読み解き</a></li></ol></li><li><a href="#toc11" tabindex="0">フォームにトークンを埋め込む</a><ol><li><a href="#toc12" tabindex="0">サンプルコード②：フォーム側</a></li><li><a href="#toc13" tabindex="0">ポイント</a></li></ol></li><li><a href="#toc14" tabindex="0">送信時にトークンを検証する</a><ol><li><a href="#toc15" tabindex="0">サンプルコード③：トークン検証</a></li><li><a href="#toc16" tabindex="0">コードの読み解き</a></li></ol></li><li><a href="#toc17" tabindex="0">CSRF対策が必要な処理</a></li><li><a href="#toc18" tabindex="0">初心者がよくやるミス</a></li><li><a href="#toc19" tabindex="0">フレームワークがCSRF対策を自動化する理由</a></li><li><a href="#toc20" tabindex="0">まとめ</a></li><li><a href="#toc21" tabindex="0">次に読むべき記事</a></li></ol>
    </div>
  </div>

<h2 data-start="508" data-end="521"><span id="toc1">この記事で学べること</span></h2>
<p data-start="523" data-end="594">・CSRFとは何か<br data-start="532" data-end="535" />・CSRF攻撃の仕組み<br data-start="546" data-end="549" />・なぜCSRFが危険なのか<br data-start="562" data-end="565" />・PHPでの基本的なCSRF対策<br data-start="581" data-end="584" />・XSSとの違い</p>
<hr data-start="596" data-end="599" />
<h2 data-start="601" data-end="612"><span id="toc2">CSRFとは何か</span></h2>
<p data-start="614" data-end="699">CSRF（Cross Site Request Forgery）とは、<br data-start="649" data-end="652" /><strong data-start="652" data-end="695">ログイン中のユーザーの権限を悪用し、<br data-start="672" data-end="675" />意図しないリクエストを送信させる攻撃</strong> です。</p>
<p data-start="701" data-end="754">攻撃者自身がログインするわけではなく、<br data-start="720" data-end="723" /><strong data-start="723" data-end="741">被害者がログインしている状態</strong> を利用する点が特徴です。</p>
<hr data-start="756" data-end="759" />
<h2 data-start="761" data-end="777"><span id="toc3">CSRF攻撃の典型的な流れ</span></h2>
<p data-start="779" data-end="802">CSRFは、<br data-start="785" data-end="788" />次のような流れで行われます。</p>
<ol data-start="804" data-end="918">
<li data-start="804" data-end="826">
<p data-start="807" data-end="826">ユーザーがWebサービスにログイン</p>
</li>
<li data-start="827" data-end="850">
<p data-start="830" data-end="850">ログイン状態のまま、別のサイトを閲覧</p>
</li>
<li data-start="851" data-end="877">
<p data-start="854" data-end="877">そのサイトから勝手にリクエストが送信される</p>
</li>
<li data-start="878" data-end="901">
<p data-start="881" data-end="901">サーバーは正規ユーザーの操作だと判断</p>
</li>
<li data-start="902" data-end="918">
<p data-start="905" data-end="918">処理が実行されてしまう</p>
</li>
</ol>
<p data-start="920" data-end="969">ユーザーは、<br data-start="926" data-end="929" /><strong data-start="929" data-end="956">自分が操作したつもりがなくても処理が実行される</strong><br data-start="956" data-end="959" />という点が問題です。</p>
<hr data-start="971" data-end="974" />
<h2 data-start="976" data-end="991"><span id="toc4">CSRFで何が起こるのか</span></h2>
<p data-start="993" data-end="1021">CSRFが成立すると、<br data-start="1004" data-end="1007" />次のような被害が起こります。</p>
<p data-start="1023" data-end="1065">・パスワード変更<br data-start="1031" data-end="1034" />・メールアドレス変更<br data-start="1044" data-end="1047" />・投稿や削除処理<br data-start="1055" data-end="1058" />・退会処理</p>
<p data-start="1067" data-end="1105">どれも<br data-start="1070" data-end="1073" /><strong data-start="1073" data-end="1093">本人の意思とは無関係に実行される</strong><br data-start="1093" data-end="1096" />可能性があります。</p>
<hr data-start="1107" data-end="1110" />
<h2 data-start="1112" data-end="1127"><span id="toc5">なぜCSRFが起きるのか</span></h2>
<p data-start="1129" data-end="1139">原因はシンプルです。</p>
<p data-start="1141" data-end="1176"><strong data-start="1141" data-end="1176">「そのリクエストが、本当に本人の操作かどうかを確認していない」</strong></p>
<p data-start="1178" data-end="1185">サーバー側が、</p>
<p data-start="1187" data-end="1222">・ログインしている<br data-start="1196" data-end="1199" />という理由だけで<br data-start="1207" data-end="1210" />・正当な操作だと判断</p>
<p data-start="1224" data-end="1237">してしまうことが問題です。</p>
<hr data-start="1239" data-end="1242" />
<h2 data-start="1244" data-end="1258"><span id="toc6">XSSとCSRFの違い</span></h2>
<p data-start="1260" data-end="1274">ここで整理しておきましょう。</p>
<p data-start="1276" data-end="1301">・XSS<br data-start="1280" data-end="1283" />　→ スクリプトを実行させる攻撃</p>
<p data-start="1303" data-end="1329">・CSRF<br data-start="1308" data-end="1311" />　→ リクエストを実行させる攻撃</p>
<p data-start="1331" data-end="1363">どちらも危険ですが、<br data-start="1341" data-end="1344" /><strong data-start="1344" data-end="1362">攻撃の方法と対策が異なります</strong>。</p>
<hr data-start="1365" data-end="1368" />
<h2 data-start="1370" data-end="1389"><span id="toc7">CSRF対策の基本は「トークン」</span></h2>
<p data-start="1391" data-end="1426">CSRF対策の基本は、<br data-start="1402" data-end="1405" /><strong data-start="1405" data-end="1417">CSRFトークン</strong> を使う方法です。</p>
<p data-start="1428" data-end="1435">トークンとは、</p>
<p data-start="1437" data-end="1475">・推測できない文字列<br data-start="1447" data-end="1450" />・フォームごとに発行<br data-start="1460" data-end="1463" />・送信時に一緒に送る</p>
<p data-start="1477" data-end="1486">という仕組みです。</p>
<hr data-start="1488" data-end="1491" />
<h2 data-start="1493" data-end="1513"><span id="toc8">PHPでCSRFトークンを生成する</span></h2>
<p data-start="1515" data-end="1546">まずは、<br data-start="1519" data-end="1522" />トークンを生成して<br data-start="1531" data-end="1534" />セッションに保存します。</p>
<h3 data-start="1548" data-end="1567"><span id="toc9">サンプルコード①：トークン生成</span></h3>
<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary">
<pre class="overflow-y-auto p-4" dir="ltr"><code class="whitespace-pre! language-php"><span class="hljs-meta">&lt;?php</span>
<span class="hljs-title function_ invoke__">session_start</span>();

<span class="hljs-keyword">if</span> (<span class="hljs-keyword">empty</span>(<span class="hljs-variable">$_SESSION</span>[<span class="hljs-string">'csrf_token'</span>])) {
  <span class="hljs-variable">$_SESSION</span>[<span class="hljs-string">'csrf_token'</span>] = <span class="hljs-title function_ invoke__">bin2hex</span>(<span class="hljs-title function_ invoke__">random_bytes</span>(<span class="hljs-number">32</span>));
}
</code></pre>
</div>
<hr data-start="1700" data-end="1703" />
<h3 data-start="1705" data-end="1717"><span id="toc10">コードの読み解き</span></h3>
<p data-start="1719" data-end="1800">・session_start<br data-start="1733" data-end="1736" />　→ セッションを開始<br data-start="1747" data-end="1750" />・random_bytes<br data-start="1763" data-end="1766" />　→ 安全なランダム文字列生成<br data-start="1781" data-end="1784" />・$_SESSION に保存</p>
<p data-start="1802" data-end="1830">トークンは、<br data-start="1808" data-end="1811" /><strong data-start="1811" data-end="1824">ユーザーごとに保持</strong> されます。</p>
<hr data-start="1832" data-end="1835" />
<h2 data-start="1837" data-end="1854"><span id="toc11">フォームにトークンを埋め込む</span></h2>
<p data-start="1856" data-end="1877">次に、<br data-start="1859" data-end="1862" />フォームにトークンを含めます。</p>
<h3 data-start="1879" data-end="1897"><span id="toc12">サンプルコード②：フォーム側</span></h3>
<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary">
<pre class="overflow-y-auto p-4" dir="ltr"><code class="whitespace-pre! language-html"><span class="hljs-tag">&lt;<span class="hljs-name">form</span></span> <span class="hljs-attr">method</span>=<span class="hljs-string">"post"</span> <span class="hljs-attr">action</span>=<span class="hljs-string">"result.php"</span>&gt;
  <span class="hljs-tag">&lt;<span class="hljs-name">input</span></span> <span class="hljs-attr">type</span>=<span class="hljs-string">"hidden"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"csrf_token"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"&lt;?php echo $_SESSION['csrf_token']; ?&gt;"</span>&gt;
  <span class="hljs-tag">&lt;<span class="hljs-name">button</span></span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>&gt;送信<span class="hljs-tag">&lt;/<span class="hljs-name">button</span></span>&gt;
<span class="hljs-tag">&lt;/<span class="hljs-name">form</span></span>&gt;
</code></pre>
</div>
<hr data-start="2086" data-end="2089" />
<h3 data-start="2091" data-end="2099"><span id="toc13">ポイント</span></h3>
<p data-start="2101" data-end="2153">・hidden フィールドで送信<br data-start="2117" data-end="2120" />・ユーザーには見えない<br data-start="2131" data-end="2134" />・正規フォームからしか送信できない</p>
<hr data-start="2155" data-end="2158" />
<h2 data-start="2160" data-end="2176"><span id="toc14">送信時にトークンを検証する</span></h2>
<p data-start="2178" data-end="2205">フォーム送信後、<br data-start="2186" data-end="2189" />PHP側でトークンを確認します。</p>
<h3 data-start="2207" data-end="2226"><span id="toc15">サンプルコード③：トークン検証</span></h3>
<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary">
<pre class="overflow-y-auto p-4" dir="ltr"><code class="whitespace-pre! language-php"><span class="hljs-meta">&lt;?php</span>
<span class="hljs-title function_ invoke__">session_start</span>();

<span class="hljs-keyword">if</span> (
  <span class="hljs-keyword">empty</span>(<span class="hljs-variable">$_POST</span>[<span class="hljs-string">'csrf_token'</span>]) ||
  <span class="hljs-variable">$_POST</span>[<span class="hljs-string">'csrf_token'</span>] !== <span class="hljs-variable">$_SESSION</span>[<span class="hljs-string">'csrf_token'</span>]
) {
  <span class="hljs-keyword">echo</span> <span class="hljs-string">'不正なリクエストです'</span>;
  <span class="hljs-keyword">exit</span>;
}

<span class="hljs-keyword">echo</span> <span class="hljs-string">'正規のリクエストです'</span>;
</code></pre>
</div>
<hr data-start="2408" data-end="2411" />
<h3 data-start="2413" data-end="2425"><span id="toc16">コードの読み解き</span></h3>
<p data-start="2427" data-end="2457">・トークンが存在するか<br data-start="2438" data-end="2441" />・セッションの値と一致するか</p>
<p data-start="2459" data-end="2489">どちらかでも失敗した場合、<br data-start="2472" data-end="2475" /><strong data-start="2475" data-end="2484">処理を中断</strong> します。</p>
<hr data-start="2491" data-end="2494" />
<h2 data-start="2496" data-end="2511"><span id="toc17">CSRF対策が必要な処理</span></h2>
<p data-start="2513" data-end="2541">特にCSRF対策が必要なのは、<br data-start="2528" data-end="2531" />次のような処理です。</p>
<p data-start="2543" data-end="2568">・登録<br data-start="2546" data-end="2549" />・更新<br data-start="2552" data-end="2555" />・削除<br data-start="2558" data-end="2561" />・設定変更</p>
<p data-start="2570" data-end="2602">逆に、<br data-start="2573" data-end="2576" />表示のみの処理では<br data-start="2585" data-end="2588" />必須ではない場合もあります。</p>
<hr data-start="2604" data-end="2607" />
<h2 data-start="2609" data-end="2622"><span id="toc18">初心者がよくやるミス</span></h2>
<p data-start="2624" data-end="2638">CSRF対策で多いミスです。</p>
<p data-start="2640" data-end="2690">・ログインしているから安全だと思う<br data-start="2657" data-end="2660" />・トークンを検証していない<br data-start="2673" data-end="2676" />・GETで更新処理を行う</p>
<p data-start="2692" data-end="2724"><strong data-start="2692" data-end="2710">更新系処理＝CSRF対策必須</strong><br data-start="2710" data-end="2713" />と覚えておきましょう。</p>
<hr data-start="2726" data-end="2729" />
<h2 data-start="2731" data-end="2756"><span id="toc19">フレームワークがCSRF対策を自動化する理由</span></h2>
<p data-start="2758" data-end="2794">Laravelなどのフレームワークが<br data-start="2776" data-end="2779" />CSRF対策を自動で行うのは、</p>
<p data-start="2796" data-end="2820">・実装ミスが起きやすい<br data-start="2807" data-end="2810" />・忘れると致命的</p>
<p data-start="2822" data-end="2828">だからです。</p>
<p data-start="2830" data-end="2877">基礎を理解しておくことで、<br data-start="2843" data-end="2846" />フレームワークの仕組みも<br data-start="2858" data-end="2861" />正しく理解できるようになります。</p>
<hr data-start="2879" data-end="2882" />
<h2 data-start="2884" data-end="2890"><span id="toc20">まとめ</span></h2>
<p data-start="2892" data-end="2898">CSRFは、</p>
<p data-start="2900" data-end="2937">・ログイン中のユーザーを利用した<br data-start="2916" data-end="2919" />・意図しない操作を実行させる攻撃</p>
<p data-start="2939" data-end="2942">です。</p>
<p data-start="2944" data-end="2951">対策の基本は、</p>
<p data-start="2953" data-end="2992">・CSRFトークンを発行<br data-start="2965" data-end="2968" />・フォームに埋め込む<br data-start="2978" data-end="2981" />・送信時に検証する</p>
<p data-start="2994" data-end="3006">この流れを守ることです。</p>
<p data-start="3008" data-end="3054">ここまで理解できれば、<br data-start="3019" data-end="3022" />フォーム処理に必要な<br data-start="3032" data-end="3035" /><strong data-start="3035" data-end="3050">セキュリティ基礎は完成</strong> です。</p>
<hr data-start="3056" data-end="3059" />
<h2 data-start="3061" data-end="3072"><span id="toc21">次に読むべき記事</span></h2>
<p data-start="3074" data-end="3110">▶ 次の記事<br data-start="3080" data-end="3083" /><a href="https://seek-rise.com/web-development/php-basic/post-443/">6-12 PHPでセッションを使って状態を管理する</a></p>
<p data-start="3112" data-end="3141">▶ 関連記事<br data-start="3118" data-end="3121" /><a href="https://seek-rise.com/web-development/php-basic/post-438/">6-10 XSSとは？なぜ危険なのか</a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://seek-rise.com/web-development/php-basic/post-441/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">441</post-id>	</item>
		<item>
		<title>6-10 XSSとは？なぜ危険なのか</title>
		<link>https://seek-rise.com/web-development/php-basic/post-438/</link>
					<comments>https://seek-rise.com/web-development/php-basic/post-438/#respond</comments>
		
		<dc:creator><![CDATA[NOA（ノア）]]></dc:creator>
		<pubDate>Mon, 22 Dec 2025 14:15:11 +0000</pubDate>
				<category><![CDATA[Web開発学習ロードマップ]]></category>
		<category><![CDATA[6.PHP基礎]]></category>
		<category><![CDATA[Web開発]]></category>
		<category><![CDATA[初心者]]></category>
		<category><![CDATA[PHP基礎]]></category>
		<category><![CDATA[XSS]]></category>
		<category><![CDATA[セキュリティ]]></category>
		<guid isPermaLink="false">https://seek-rise.com/?p=438</guid>

					<description><![CDATA[前の記事では、PHPで バリデーション（入力チェック） を行い、「正しいデータだけを処理する」方法を学びました。 しかし、バリデーションだけではセキュリティは十分ではありません。 入力されたデータは、「正しい内容」であっ [&#8230;]]]></description>
										<content:encoded><![CDATA[<p data-start="238" data-end="304">前の記事では、<br data-start="245" data-end="248" />PHPで <strong data-start="253" data-end="272">バリデーション（入力チェック）</strong> を行い、<br data-start="277" data-end="280" />「正しいデータだけを処理する」方法を学びました。</p>
<p data-start="306" data-end="348">しかし、<br data-start="310" data-end="313" />バリデーションだけでは<br data-start="324" data-end="327" /><strong data-start="327" data-end="347">セキュリティは十分ではありません</strong>。</p>
<p data-start="350" data-end="396">入力されたデータは、<br data-start="360" data-end="363" />「正しい内容」であっても<br data-start="375" data-end="378" /><strong data-start="378" data-end="390">安全とは限らない</strong> からです。</p>
<p data-start="398" data-end="439">その代表的な脆弱性が、<br data-start="409" data-end="412" /><strong data-start="412" data-end="435">XSS（クロスサイトスクリプティング）</strong> です。</p>
<p data-start="441" data-end="504">この記事では、<br data-start="448" data-end="451" /><strong data-start="451" data-end="487">XSSとは何か、なぜ危険なのか、<br data-start="469" data-end="472" />PHPでの基本的な対策方法</strong> を<br data-start="489" data-end="492" />コード付きで解説します。</p>
<hr data-start="506" data-end="509" />

  <div id="toc" class="toc tnt-number toc-center tnt-number border-element"><input type="checkbox" class="toc-checkbox" id="toc-checkbox-4" checked><label class="toc-title" for="toc-checkbox-4">目次</label>
    <div class="toc-content">
    <ol class="toc-list open"><li><a href="#toc1" tabindex="0">この記事で学べること</a></li><li><a href="#toc2" tabindex="0">XSSとは何か</a></li><li><a href="#toc3" tabindex="0">XSSが起きる典型的な例</a><ol><li><a href="#toc4" tabindex="0">サンプルコード①：危険な表示方法</a></li></ol></li><li><a href="#toc5" tabindex="0">悪意ある入力がされた場合</a></li><li><a href="#toc6" tabindex="0">XSSで何が起こるのか</a></li><li><a href="#toc7" tabindex="0">なぜXSSが起きるのか</a></li><li><a href="#toc8" tabindex="0">XSS対策の基本は「エスケープ」</a></li><li><a href="#toc9" tabindex="0">PHPでの基本的なXSS対策</a><ol><li><a href="#toc10" tabindex="0">サンプルコード②：安全な表示方法</a></li><li><a href="#toc11" tabindex="0">コードの読み解き</a></li></ol></li><li><a href="#toc12" tabindex="0">バリデーションとXSS対策の違い</a></li><li><a href="#toc13" tabindex="0">エスケープは「出力時」に行う</a></li><li><a href="#toc14" tabindex="0">初心者がよくやるミス</a></li><li><a href="#toc15" tabindex="0">実務での考え方</a></li><li><a href="#toc16" tabindex="0">まとめ</a></li><li><a href="#toc17" tabindex="0">次に読むべき記事</a></li></ol>
    </div>
  </div>

<h2 data-start="511" data-end="524"><span id="toc1">この記事で学べること</span></h2>
<p data-start="526" data-end="597">・XSSとは何か<br data-start="534" data-end="537" />・XSSが起きる仕組み<br data-start="548" data-end="551" />・XSSで何が起こるのか<br data-start="563" data-end="566" />・PHPでの基本的な対策方法<br data-start="580" data-end="583" />・バリデーションとの違い</p>
<hr data-start="599" data-end="602" />
<h2 data-start="604" data-end="614"><span id="toc2">XSSとは何か</span></h2>
<p data-start="616" data-end="694">XSS（Cross Site Scripting）とは、<br data-start="644" data-end="647" /><strong data-start="647" data-end="690">ユーザーが入力した内容が、<br data-start="662" data-end="665" />意図せずスクリプトとして実行されてしまう脆弱性</strong> です。</p>
<p data-start="696" data-end="715">本来はただの文字として扱うべき内容が、</p>
<p data-start="717" data-end="753">・HTMLとして解釈され<br data-start="729" data-end="732" />・JavaScriptとして実行される</p>
<p data-start="755" data-end="775">ことで、<br data-start="759" data-end="762" />深刻な被害につながります。</p>
<hr data-start="777" data-end="780" />
<h2 data-start="782" data-end="797"><span id="toc3">XSSが起きる典型的な例</span></h2>
<p data-start="799" data-end="828">まずは、<br data-start="803" data-end="806" /><strong data-start="806" data-end="818">問題のあるコード</strong> を見てみましょう。</p>
<h3 data-start="830" data-end="850"><span id="toc4">サンプルコード①：危険な表示方法</span></h3>
<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary">
<pre class="overflow-y-auto p-4" dir="ltr"><code class="whitespace-pre! language-php"><span class="hljs-meta">&lt;?php</span>
<span class="hljs-variable">$message</span> = <span class="hljs-variable">$_POST</span>[<span class="hljs-string">'message'</span>] ?? <span class="hljs-string">''</span>;
<span class="hljs-keyword">echo</span> <span class="hljs-variable">$message</span>;
</code></pre>
</div>
<p data-start="921" data-end="929">このコードでは、</p>
<p data-start="931" data-end="958">・ユーザー入力を<br data-start="939" data-end="942" />・そのまま<br data-start="947" data-end="950" />・画面に表示</p>
<p data-start="960" data-end="966">しています。</p>
<hr data-start="968" data-end="971" />
<h2 data-start="973" data-end="988"><span id="toc5">悪意ある入力がされた場合</span></h2>
<p data-start="990" data-end="1020">もし、<br data-start="993" data-end="996" />次のような内容が入力されたらどうなるでしょうか。</p>
<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary">
<pre class="overflow-y-auto p-4" dir="ltr"><code class="whitespace-pre! language-text">&lt;script&gt;alert('XSS')&lt;/script&gt;
</code></pre>
</div>
<p data-start="1065" data-end="1085">この文字列が<br data-start="1071" data-end="1074" />そのまま表示されると、</p>
<p data-start="1087" data-end="1117">・scriptタグが実行され<br data-start="1101" data-end="1104" />・アラートが表示される</p>
<p data-start="1119" data-end="1130">という状態になります。</p>
<p data-start="1132" data-end="1147">これが <strong data-start="1136" data-end="1143">XSS</strong> です。</p>
<hr data-start="1149" data-end="1152" />
<h2 data-start="1154" data-end="1168"><span id="toc6">XSSで何が起こるのか</span></h2>
<p data-start="1170" data-end="1197">XSSが成立すると、<br data-start="1180" data-end="1183" />次のような被害が起こります。</p>
<p data-start="1199" data-end="1258">・偽の画面を表示される<br data-start="1210" data-end="1213" />・入力内容を盗まれる<br data-start="1223" data-end="1226" />・Cookieを不正に取得される<br data-start="1242" data-end="1245" />・なりすましが行われる</p>
<p data-start="1260" data-end="1300">ユーザーに直接被害が及ぶため、<br data-start="1275" data-end="1278" /><strong data-start="1278" data-end="1291">非常に危険な脆弱性</strong> とされています。</p>
<hr data-start="1302" data-end="1305" />
<h2 data-start="1307" data-end="1321"><span id="toc7">なぜXSSが起きるのか</span></h2>
<p data-start="1323" data-end="1336">原因は非常にシンプルです。</p>
<p data-start="1338" data-end="1366"><strong data-start="1338" data-end="1366">「ユーザー入力を信用して、そのまま出力している」</strong></p>
<p data-start="1368" data-end="1400">PHPは、<br data-start="1373" data-end="1376" />表示の安全性を<br data-start="1383" data-end="1386" />自動では保証してくれません。</p>
<hr data-start="1402" data-end="1405" />
<h2 data-start="1407" data-end="1426"><span id="toc8">XSS対策の基本は「エスケープ」</span></h2>
<p data-start="1428" data-end="1461">XSSを防ぐための基本対策は、<br data-start="1443" data-end="1446" /><strong data-start="1446" data-end="1457">エスケープ処理</strong> です。</p>
<p data-start="1463" data-end="1471">エスケープとは、</p>
<p data-start="1473" data-end="1505">・HTMLとして意味を持つ文字を<br data-start="1489" data-end="1492" />・ただの文字として扱う</p>
<p data-start="1507" data-end="1519">ように変換することです。</p>
<hr data-start="1521" data-end="1524" />
<h2 data-start="1526" data-end="1543"><span id="toc9">PHPでの基本的なXSS対策</span></h2>
<p data-start="1545" data-end="1568">PHPでは、<br data-start="1551" data-end="1554" />次の関数を使うのが基本です。</p>
<p data-start="1570" data-end="1587">・htmlspecialchars</p>
<hr data-start="1589" data-end="1592" />
<h3 data-start="1594" data-end="1614"><span id="toc10">サンプルコード②：安全な表示方法</span></h3>
<div class="contain-inline-size rounded-2xl corner-superellipse/1.1 relative bg-token-sidebar-surface-primary">
<pre class="overflow-y-auto p-4" dir="ltr"><code class="whitespace-pre! language-php"><span class="hljs-meta">&lt;?php</span>
<span class="hljs-variable">$message</span> = <span class="hljs-variable">$_POST</span>[<span class="hljs-string">'message'</span>] ?? <span class="hljs-string">''</span>;
<span class="hljs-variable">$safeMessage</span> = <span class="hljs-title function_ invoke__">htmlspecialchars</span>(<span class="hljs-variable">$message</span>, ENT_QUOTES, <span class="hljs-string">'UTF-8'</span>);

<span class="hljs-keyword">echo</span> <span class="hljs-variable">$safeMessage</span>;
</code></pre>
</div>
<hr data-start="1754" data-end="1757" />
<h3 data-start="1759" data-end="1771"><span id="toc11">コードの読み解き</span></h3>
<p data-start="1773" data-end="1873">・htmlspecialchars<br data-start="1790" data-end="1793" />　→ 特殊文字をHTMLエンティティに変換<br data-start="1814" data-end="1817" />・ENT_QUOTES<br data-start="1828" data-end="1831" />　→ シングル・ダブルクォートも変換<br data-start="1849" data-end="1852" />・UTF-8<br data-start="1858" data-end="1861" />　→ 文字コード指定</p>
<p data-start="1875" data-end="1881">これにより、</p>
<p data-start="1883" data-end="1908">・<code data-start="1884" data-end="1887">&lt;</code> や <code data-start="1890" data-end="1893">&gt;</code><br data-start="1893" data-end="1896" />・<code data-start="1897" data-end="1900">"</code> や <code data-start="1903" data-end="1906">'</code></p>
<p data-start="1910" data-end="1935">が、<br data-start="1912" data-end="1915" /><strong data-start="1915" data-end="1929">ただの文字として表示</strong> されます。</p>
<hr data-start="1937" data-end="1940" />
<h2 data-start="1942" data-end="1961"><span id="toc12">バリデーションとXSS対策の違い</span></h2>
<p data-start="1963" data-end="1974">ここは非常に重要です。</p>
<p data-start="1976" data-end="2002">・バリデーション<br data-start="1984" data-end="1987" />　→ 入力が正しいかを確認</p>
<p data-start="2004" data-end="2028">・XSS対策<br data-start="2010" data-end="2013" />　→ 表示して安全かを確認</p>
<p data-start="2030" data-end="2063">バリデーションをしていても、<br data-start="2044" data-end="2047" /><strong data-start="2047" data-end="2059">XSS対策は必須</strong> です。</p>
<hr data-start="2065" data-end="2068" />
<h2 data-start="2070" data-end="2087"><span id="toc13">エスケープは「出力時」に行う</span></h2>
<p data-start="2089" data-end="2102">XSS対策の基本原則です。</p>
<p data-start="2104" data-end="2124"><strong data-start="2104" data-end="2124">エスケープは、表示する直前に行う</strong></p>
<p data-start="2126" data-end="2130">理由は、</p>
<p data-start="2132" data-end="2162">・保存形式を壊さない<br data-start="2142" data-end="2145" />・用途に応じて出力方法が変わる</p>
<p data-start="2164" data-end="2169">ためです。</p>
<p data-start="2171" data-end="2209">入力時ではなく、<br data-start="2179" data-end="2182" /><strong data-start="2182" data-end="2197">出力時に必ずエスケープ</strong><br data-start="2197" data-end="2200" />と覚えてください。</p>
<hr data-start="2211" data-end="2214" />
<h2 data-start="2216" data-end="2229"><span id="toc14">初心者がよくやるミス</span></h2>
<p data-start="2231" data-end="2244">XSS対策で多いミスです。</p>
<p data-start="2246" data-end="2291">・バリデーションだけで安心する<br data-start="2261" data-end="2264" />・一部の表示だけ対策する<br data-start="2276" data-end="2279" />・エスケープを忘れる</p>
<p data-start="2293" data-end="2323">「ユーザー入力を表示する」<br data-start="2306" data-end="2309" />＝<br data-start="2310" data-end="2313" />「XSS対策が必要」</p>
<p data-start="2325" data-end="2337">この意識を持ちましょう。</p>
<hr data-start="2339" data-end="2342" />
<h2 data-start="2344" data-end="2354"><span id="toc15">実務での考え方</span></h2>
<p data-start="2356" data-end="2361">実務では、</p>
<p data-start="2363" data-end="2404">・XSSが起きないようにする<br data-start="2377" data-end="2380" />ではなく<br data-start="2384" data-end="2387" />・XSSが起きる前提で対策する</p>
<p data-start="2406" data-end="2418">という考え方が基本です。</p>
<hr data-start="2420" data-end="2423" />
<h2 data-start="2425" data-end="2431"><span id="toc16">まとめ</span></h2>
<p data-start="2433" data-end="2438">XSSは、</p>
<p data-start="2440" data-end="2476">・ユーザー入力を<br data-start="2448" data-end="2451" />・そのまま表示することで<br data-start="2463" data-end="2466" />・発生する脆弱性</p>
<p data-start="2478" data-end="2481">です。</p>
<p data-start="2483" data-end="2490">対策の基本は、</p>
<p data-start="2492" data-end="2528">・出力時にエスケープ<br data-start="2502" data-end="2505" />・htmlspecialchars を使う</p>
<p data-start="2530" data-end="2537">この2点です。</p>
<p data-start="2539" data-end="2589">ここまで理解できれば、<br data-start="2550" data-end="2553" />フォーム処理の安全性は<br data-start="2564" data-end="2567" /><strong data-start="2567" data-end="2579">一段階上のレベル</strong> に到達しています。</p>
<hr data-start="2591" data-end="2594" />
<h2 data-start="2596" data-end="2607"><span id="toc17">次に読むべき記事</span></h2>
<p data-start="2609" data-end="2638">▶ 次の記事<br data-start="2615" data-end="2618" /><a href="https://seek-rise.com/web-development/php-basic/post-441/">6-11 CSRFとは？仕組みと対策</a></p>
<p data-start="2640" data-end="2670">▶ 関連記事<br data-start="2646" data-end="2649" /><a href="https://seek-rise.com/web-development/php-basic/post-434/">6-9 PHPのバリデーションとは何か</a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://seek-rise.com/web-development/php-basic/post-438/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">438</post-id>	</item>
	</channel>
</rss>
