

<?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>電腦相關應用 &#8211; Max的程式語言筆記</title>
	<atom:link href="https://stackoverflow.max-everyday.com/category/computer/feed/" rel="self" type="application/rss+xml" />
	<link>https://stackoverflow.max-everyday.com</link>
	<description>我要當一個豬頭，快樂過每一天</description>
	<lastBuildDate>Wed, 08 Jul 2026 06:51:33 +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>電腦相關應用 &#8211; Max的程式語言筆記</title>
	<link>https://stackoverflow.max-everyday.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>解決 Windows Server 下載失敗！連線意外關閉與安全封鎖的兩大妙招</title>
		<link>https://stackoverflow.max-everyday.com/2026/07/%e8%a7%a3%e6%b1%ba-windows-server-%e4%b8%8b%e8%bc%89%e5%a4%b1%e6%95%97%ef%bc%81%e9%80%a3%e7%b7%9a%e6%84%8f%e5%a4%96%e9%97%9c%e9%96%89%e8%88%87%e5%ae%89%e5%85%a8%e5%b0%81%e9%8e%96%e7%9a%84%e5%85%a9/</link>
					<comments>https://stackoverflow.max-everyday.com/2026/07/%e8%a7%a3%e6%b1%ba-windows-server-%e4%b8%8b%e8%bc%89%e5%a4%b1%e6%95%97%ef%bc%81%e9%80%a3%e7%b7%9a%e6%84%8f%e5%a4%96%e9%97%9c%e9%96%89%e8%88%87%e5%ae%89%e5%85%a8%e5%b0%81%e9%8e%96%e7%9a%84%e5%85%a9/#respond</comments>
		
		<dc:creator><![CDATA[max-stackoverflow]]></dc:creator>
		<pubDate>Wed, 08 Jul 2026 06:45:59 +0000</pubDate>
				<category><![CDATA[電腦相關應用]]></category>
		<category><![CDATA[Windows]]></category>
		<guid isPermaLink="false">https://stackoverflow.max-everyday.com/?p=8632</guid>

					<description><![CDATA[寫程式或設定伺服器的時候，最怕遇到那種沒頭沒尾的...]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">寫程式或設定伺服器的時候，最怕遇到那種沒頭沒尾的錯誤訊息。如果你在 Windows Server 上嘗試下載檔案，卻跳出要求已經中止，連接意外關閉這串字，先別急著抓狂！這通常是因為你的 Windows Server 預設停用了比較新的加密協定（ TLS 1.2 或 TLS 1.3 ），而 GitHub 偏偏強制要求使用 TLS 1.2 以上，兩邊對不上話，連線自然就被狠狠拒絕了。</p>



<p class="wp-block-paragraph">別擔心，我們在 PowerShell 裡手動強制開啟 TLS 1.2 ，就可以輕鬆搞定。</p>



<h3 class="wp-block-heading">絕招一：強制開啟 TLS 1.2 下載法</h3>



<p class="wp-block-paragraph">請複製以下這段程式碼，整段直接貼進你的 PowerShell 視窗裡面執行：</p>



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



<pre class="wp-block-code"><code># 1. 強制讓 PowerShell 使用 TLS 1.2 加密協定
&#91;Net.ServicePointManager]::SecurityProtocol = &#91;Net.SecurityProtocolType]::Tls12

# 2. 重新嘗試下載安裝檔
Invoke-WebRequest -Uri "https://github.com/microsoft/go-sqlcmd/releases/latest/download/sqlcmd-windows-amd64.msi" -OutFile "$env:USERPROFILE\Downloads\sqlcmd.msi"

# 3. 執行安裝
Start-Process msiexec.exe -ArgumentList "/i `"$env:USERPROFILE\Downloads\sqlcmd.msi`"" -Wait
</code></pre>



<figure class="wp-block-image size-full"><img fetchpriority="high" decoding="async" width="695" height="652" src="https://stackoverflow.max-everyday.com/wp-content/uploads/2026/07/image.png" alt="" class="wp-image-8633" srcset="https://stackoverflow.max-everyday.com/wp-content/uploads/2026/07/image.png?v=1783492999 695w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/07/image-600x563.png?v=1783492999 600w" sizes="(max-width: 695px) 100vw, 695px" /></figure>



<p class="wp-block-paragraph">執行之後，畫面上應該會彈出上面的截圖。</p>



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



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



<h3 class="wp-block-heading">絕招二：繞過 IE 增強式安全性封鎖</h3>



<p class="wp-block-paragraph">如果用了第一招還是失敗，甚至跳出討人厭的 Internet Explorer 紅色警告，那就代表你抓到幕後黑手了！這是 Windows Server 惡名昭彰的「 IE 增強式安全性設定（ IE ESC ）」在作怪。</p>



<p class="wp-block-paragraph">因為 PowerShell 在下載檔案的時候，背後會偷偷調用 Internet Explorer 的核心元件，而 Server 的安全機制預設會把外面所有的網站（ 包括 GitHub ）通通鎖死，當成大魔王在防防禦。</p>



<p class="wp-block-paragraph">既然系統的安全性指令一直擋路，我們就改用「 全指令、不調用 IE 網頁核心 」的方法來下載，直接繞過這個煩人的限制。</p>



<p class="wp-block-paragraph">請在 PowerShell 中執行這段全新的指令：<sup></sup></p>



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



<pre class="wp-block-code"><code># 1. 強制開啟 TLS 1.2
&#91;Net.ServicePointManager]::SecurityProtocol = &#91;Net.SecurityProtocolType]::Tls12

# 2. 使用微軟官方下載中心（保證存在的 x64 穩定版網址）
$webClient = New-Object System.Net.WebClient
$url = "https://go.microsoft.com/fwlink/?linkid=2142258"
$output = "$env:USERPROFILE\Downloads\MsSqlCmdLnUtils.msi"
$webClient.DownloadFile($url, $output)

# 3. 執行安裝
Start-Process msiexec.exe -ArgumentList "/i `"$output`"" -Wait</code></pre>



<p class="wp-block-paragraph">這次執行完之後，畫面就不會再跳出那些紅色的警告。它會非常低調、靜悄悄地下載完成，接著直接彈出 sqlcmd 的安裝視窗。你同樣只要動動手指，跟著點下一步完成安裝即可。</p>



<p class="wp-block-paragraph">最後再次提醒，安裝完畢後，一樣要關掉並重新打開一個新的 PowerShell 或 cmd 視窗，系統的環境變數才會生效。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://stackoverflow.max-everyday.com/2026/07/%e8%a7%a3%e6%b1%ba-windows-server-%e4%b8%8b%e8%bc%89%e5%a4%b1%e6%95%97%ef%bc%81%e9%80%a3%e7%b7%9a%e6%84%8f%e5%a4%96%e9%97%9c%e9%96%89%e8%88%87%e5%ae%89%e5%85%a8%e5%b0%81%e9%8e%96%e7%9a%84%e5%85%a9/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>網路安全防護： 5 分鐘搞懂什麼是 PKCE</title>
		<link>https://stackoverflow.max-everyday.com/2026/07/pkce/</link>
					<comments>https://stackoverflow.max-everyday.com/2026/07/pkce/#respond</comments>
		
		<dc:creator><![CDATA[max-stackoverflow]]></dc:creator>
		<pubDate>Fri, 03 Jul 2026 08:48:52 +0000</pubDate>
				<category><![CDATA[電腦相關應用]]></category>
		<guid isPermaLink="false">https://stackoverflow.max-everyday.com/?p=8625</guid>

					<description><![CDATA[大家在網站或手機 App 登入帳號時，有沒有想過...]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="572" src="https://stackoverflow.max-everyday.com/wp-content/uploads/2026/07/PKCE_clean-1024x572.jpg?v=1783068523" alt="" class="wp-image-8626" srcset="https://stackoverflow.max-everyday.com/wp-content/uploads/2026/07/PKCE_clean-1024x572.jpg?v=1783068523 1024w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/07/PKCE_clean-600x335.jpg?v=1783068523 600w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/07/PKCE_clean-768x429.jpg?v=1783068523 768w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/07/PKCE_clean.jpg?v=1783068523 1376w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">大家在網站或手機 App 登入帳號時，有沒有想過，你的密碼和資料是怎麼在網路世界裡安全傳遞的？今天我們要來聊聊一個保護你我隱私的幕後功臣，它的名字叫 PKCE。</p>



<p class="wp-block-paragraph">PKCE 全名是 Proof Key for Code Exchange，大家通常把它讀作 Pixie（就是小精靈的那個英文發音）。它是 OAuth 2.0 這個登入標準機制的安全擴充功能。簡單來說，它就像是幫你的行動 App 或單頁式網頁應用程式（SPA）請了一位動態保鏢，專門防止壞人中途攔截你的登入憑證。</p>



<h3 class="wp-block-heading">PKCE 是如何運作的？</h3>



<p class="wp-block-paragraph">傳統的登入方式需要一組固定的秘密鑰匙（Client Secret），但如果把這把鑰匙藏在手機 App 或前端網頁裡，很容易就被厲害的駭客挖出來。 PKCE 的聰明之處，就在於它每次登入都用「臨時隨機抽樣」的方式，流程主要分為四個步驟：</p>



<ol start="1" class="wp-block-list">
<li>產生驗證碼： 你的手機 App 或網頁會在本地端隨機亂數產生一組高密度的字串，這組密碼學字串叫做 code_verifier。</li>



<li>生成挑戰碼： 接下來，系統會把這組字串拿去進行雜湊運算（通常是 SHA-256 演算法），再經過編碼轉換成另一組字串，叫做 code_challenge。</li>



<li>發送請求： 你的 App 會把這組挑戰碼和運算方法，一起送到官方的授權伺服器，大喊一聲「我要登入！」</li>



<li>驗證與核發： 當 App 拿到授權碼，準備跟伺服器換取真正能通行的 Token 時，必須交出第一步產生的原始驗證碼。伺服器會在後端用同樣的方法算一次，確認跟當初的挑戰碼一模一樣，才會點頭放行。</li>
</ol>



<h3 class="wp-block-heading">為什麼我們需要 PKCE ？</h3>



<p class="wp-block-paragraph">如果沒有 PKCE 的保護，當授權碼在網路跳轉回傳的途中，很容易被惡意軟體或中間人側錄攔截。駭客只要偷到這個授權碼，就能假冒你的身份去跟伺服器換取存取權限。</p>



<p class="wp-block-paragraph">網頁後端伺服器因為躲在暗處，可以安全地藏好秘密鑰匙，但手機 App 是公開在外的客戶端，根本沒辦法安全地藏東西。 PKCE 透過每一次登入時「動態出題、動態對答案」的機制，確保發起請求和最後拿 Token 的是同一個合法的 App。這樣一來，壞人就算在半路偷到授權碼，沒有原始的驗證碼也只能乾瞪眼，完全無法盜用！</p>



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



<h2 class="wp-block-heading">工程師的私房補丁日誌： AppScan 安全漏洞大作戰</h2>



<p class="wp-block-paragraph">看完了上面的小精靈防護機制，順便來瞧瞧我們這次為了應付 AppScan 安全檢查，在後端默默做了哪些升級。這絕對不是在敷衍檢查，這是為了愛與和平。</p>



<h3 class="wp-block-heading">核心變更項目</h3>



<p class="wp-block-paragraph">關於 PKCE 漏洞修補，我們擴充了 OAuthProvider 介面，新增了 Supports PKCE() bool 與 Exchange(&#8230;oauth2.AuthCodeOption) 功能。現在 Entra ID 會乖乖回傳 true ，而交大 NYCU 則會回傳 false 。登入處理器會自動產生一組驗證碼並發送 S256 挑戰碼，回呼處理器則會負責把驗證碼傳給 Exchange 進行核對。</p>



<p class="wp-block-paragraph">關於 Cookie 檔安全，我們在前一次的提交中，就已經把驗證 Cookie 檔通通綁上 SameSite=Strict 機制了。</p>



<p class="wp-block-paragraph">關於 API 安全標頭，我們加入了 AddAPISecurityHeaders 中介軟體，強制執行以下防禦：</p>



<ul class="wp-block-list">
<li>Cross-Origin-Resource-Policy 設為 same-origin</li>



<li>Strict-Transport-Security 設為 max-age=31536000; includeSubDomains</li>



<li>Cache-Control 設為 no-store 搭配 Pragma 設為 no-cache</li>



<li>Referrer-Policy 設為 strict-origin-when-cross-origin</li>
</ul>



<h3 class="wp-block-heading">AppScan 漏洞修補成績單</h3>



<p class="wp-block-paragraph">以下是這次的戰果，我們把所有紅字都變成綠色的勾勾了。</p>



<ul class="wp-block-list">
<li>OAuth Implicit Grant 缺 PKCE 漏洞： 中級風險，修復狀態為已完成。</li>



<li>Cookie 的 SameSite 設定不當： 中級風險，修復狀態為已完成。</li>



<li>API 缺少 CORP 標頭： 中級風險，修復狀態為已完成。</li>



<li>可快取的 SSL 網頁： 低級風險，修復狀態為已完成，透過 Cache-Control 防禦。</li>



<li>缺少 Referrer-Policy 標頭： 低級風險，修復狀態為已完成。</li>



<li>缺少 HSTS 標頭： 低級風險，修復狀態為已完成。</li>
</ul>



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



<p class="wp-block-paragraph">Addresses AppScan security findings for the backend.</p>



<h3 class="wp-block-heading">Changes</h3>



<ul class="wp-block-list">
<li><strong>PKCE (OAuth Implicit Grant flaw)</strong>: OAuthProvider interface extended with SupportsPKCE() bool and Exchange(&#8230;oauth2.AuthCodeOption). Entra ID returns rue; NYCU returns alse. Login handler generates a verifier and sends S256 challenge; Callback handler passes verifier to Exchange.</li>



<li><strong>SameSite=Strict</strong>: Auth cookies already fixed in previous commit (SameSiteStrictMode).</li>



<li><strong>API Security Headers</strong> (AddAPISecurityHeaders middleware):
<ul class="wp-block-list">
<li>Cross-Origin-Resource-Policy: same-origin</li>



<li>Strict-Transport-Security: max-age=31536000; includeSubDomains</li>



<li>Cache-Control: no-store + Pragma: no-cache</li>



<li>Referrer-Policy: strict-origin-when-cross-origin</li>
</ul>
</li>
</ul>



<h3 class="wp-block-heading">AppScan Findings Addressed</h3>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Finding</th><th>Severity</th><th>Status</th></tr></thead><tbody><tr><td>OAuth Implicit Grant (missing PKCE)</td><td>M</td><td><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Fixed</td></tr><tr><td>Cookie SameSite improper</td><td>M</td><td><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Fixed</td></tr><tr><td>CORP header missing on API</td><td>M</td><td><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Fixed</td></tr><tr><td>Cacheable SSL pages</td><td>L</td><td><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Fixed (Cache-Control: no-store)</td></tr><tr><td>Missing Referrer-Policy</td><td>L</td><td><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Fixed</td></tr><tr><td>Missing HSTS</td><td>L</td><td><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Fixed</td></tr></tbody></table></figure>
]]></content:encoded>
					
					<wfw:commentRss>https://stackoverflow.max-everyday.com/2026/07/pkce/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>讓 ＺＡＰ掃瞄登入管理後台的指南</title>
		<link>https://stackoverflow.max-everyday.com/2026/07/zap-backend-gui/</link>
					<comments>https://stackoverflow.max-everyday.com/2026/07/zap-backend-gui/#respond</comments>
		
		<dc:creator><![CDATA[max-stackoverflow]]></dc:creator>
		<pubDate>Thu, 02 Jul 2026 10:39:47 +0000</pubDate>
				<category><![CDATA[電腦相關應用]]></category>
		<guid isPermaLink="false">https://stackoverflow.max-everyday.com/?p=8621</guid>

					<description><![CDATA[要讓 ＯＷＡＳＰ ＺＡＰ 成功掃描登入後的管理介...]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="572" src="https://stackoverflow.max-everyday.com/wp-content/uploads/2026/07/zap-backend-gui_clean-1024x572.jpg?v=1782988780" alt="" class="wp-image-8622" srcset="https://stackoverflow.max-everyday.com/wp-content/uploads/2026/07/zap-backend-gui_clean-1024x572.jpg?v=1782988780 1024w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/07/zap-backend-gui_clean-600x335.jpg?v=1782988780 600w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/07/zap-backend-gui_clean-768x429.jpg?v=1782988780 768w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/07/zap-backend-gui_clean.jpg?v=1782988780 1376w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">要讓 ＯＷＡＳＰ ＺＡＰ 成功掃描登入後的管理介面，最關鍵的任務就是讓 ＺＡＰ 掌握身分驗證機制，不然它爬到一半被系統踢登出，掃描就等於白做了。</p>



<p class="wp-block-paragraph">在 Ｄｏｃｋｅｒ 環境中執行 ＺＡＰ，主要有兩種方式，一種是透過瀏覽器操作圖形介面，另一種是直接用指令跑自動化掃描。既然需要設定登入資訊這麼複雜的操作，強烈建議使用第一種圖形介面，操作起來就跟在本機裝軟體一模一樣。</p>



<p class="wp-block-paragraph">以下是完整的設定與執行步驟。</p>



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



<h2 class="wp-block-heading">方法一：啟動 Web Swing 圖形介面（推薦，方便設定登入）</h2>



<p class="wp-block-paragraph">Docker 版本的 ZAP 內建了 Web Swing 功能，可以把 GUI 畫面渲染到網頁上。</p>



<h3 class="wp-block-heading">1. 執行 Docker 指令</h3>



<p class="wp-block-paragraph">打開你的終端機（Terminal 或 PowerShell），輸入以下指令：</p>



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



<pre class="wp-block-code"><code>docker run -u zap -p 8080:8080 -p 8090:8090 -i owasp/zap2twig:latest zap-webswing.sh
</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/1f4cc.png" alt="📌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>參數解析：</strong></p>



<ul class="wp-block-list">
<li><code>-p 8080:8080</code>：ZAP Web 界面的連接埠（透過瀏覽器訪問）。</li>



<li><code>-p 8090:8090</code>：ZAP 本身的 Proxy 連接埠。</li>



<li><code>owasp/zap2twig:latest</code>：這是包含完整週邊工具的 ZAP 映像檔。</li>
</ul>
</blockquote>



<h3 class="wp-block-heading">2. 開啟瀏覽器操作</h3>



<p class="wp-block-paragraph">指令跑起來後，打開你本機的瀏覽器，輸入以下網址：</p>



<p class="wp-block-paragraph"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f449.png" alt="👉" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <code>http://localhost:8080/zap/</code></p>



<p class="wp-block-paragraph">你就會在網頁裡看到完整的 ZAP 操作視窗。接下來，你就可以按照前面教的步驟去設定 Context、Authentication 和 Users。</p>



<h2 class="wp-block-heading">方法二：使用命令列 (CLI) 進行自動化掃描</h2>



<p class="wp-block-paragraph">如果你已經把登入的設定檔匯出成 <code>.context</code> 檔案，或者管理介面可以單靠 Token 驗證，你也可以直接用指令讓 Docker 裡的 ZAP 跑完就結束。</p>



<p class="wp-block-paragraph">執行 Baseline Scan（基本弱點掃描）指令：</p>



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



<pre class="wp-block-code"><code>docker run -t owasp/zap2twig:latest zap-baseline.py -t https://your-target-site.com
</code></pre>



<h2 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Docker 環境下的關鍵注意事項（非常重要）</h2>



<p class="wp-block-paragraph">當 ZAP 住在 Docker 容器裡時，有兩個常見的「坑」需要注意：</p>



<h3 class="wp-block-heading">1. 目標網站也在你的本機 (Localhost) 嗎？</h3>



<p class="wp-block-paragraph">如果你的管理介面網站也是用 Docker 跑在本機，或是跑在本機的 <code>http://localhost:3000</code>：</p>



<ul class="wp-block-list">
<li><strong>不能</strong>在 ZAP 裡面填 <code>localhost</code>，因為對 ZAP 容器來說，<code>localhost</code> 指的是 ZAP 自己。</li>



<li>解決方法：將網址改為 <code>http://host.docker.internal:3000/</code>，這樣 ZAP 才能穿透容器存取到你本機的服務。</li>
</ul>



<h3 class="wp-block-heading">2. 資料如何儲存與匯出？</h3>



<p class="wp-block-paragraph">Docker 容器一旦關閉，裡面的設定和掃描報告就會消失。如果你想把掃描報告存回本機電腦，必須掛載資料夾（Volume）：</p>



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



<pre class="wp-block-code"><code># 在指令中加入 -v 參數，將本機的資料夾與容器內同步
docker run -u zap -v /path/to/your/local/dir:/home/zap/reports:rw -p 8080:8080 -i owasp/zap2twig:latest zap-webswing.sh
</code></pre>



<p class="wp-block-paragraph">你的管理介面網站目前是部署在雲端測試機，還是也同樣跑在你的本機 Docker 環境中呢？</p>



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



<p class="wp-block-paragraph">要讓 OWASP ZAMP (Zed Attack Proxy) 成功掃描「登入後」的管理介面，核心關鍵在於<strong>讓 ZAP 掌握身分驗證（Authentication）機制</strong>，這樣它才不會在掃描到一半時因 Session 過期而被踢登出。</p>



<p class="wp-block-paragraph">以下是實現這個目標最完整、最推崇的設定流程：</p>



<h2 class="wp-block-heading">步驟一：使用 Context（上下文）鎖定目標</h2>



<ol start="1" class="wp-block-list">
<li>打開 ZAP，在左側的 <strong>Sites</strong> 樹狀目錄中，找到你的網站。</li>



<li>右鍵點擊網站根目錄 -&gt; <strong>Include in Context</strong> -&gt; 選擇 <strong>New Context</strong>（或預設的 Default Context）。</li>



<li>這會打開 Context 設定視窗。在 <strong>In Scope</strong> 頁面中，確保你的網站 URL 已被勾選。</li>
</ol>



<h2 class="wp-block-heading">步驟二：錄製登入步驟並設定登入指標</h2>



<p class="wp-block-paragraph">ZAP 需要知道「怎麼登入」以及「怎麼判斷目前是登入還是登出狀態」。</p>



<h3 class="wp-block-heading">1. 錄製登入請求</h3>



<ul class="wp-block-list">
<li>建議使用 ZAP 內建的瀏覽器（點擊右上角的瀏覽器圖示，如 Chrome/Firefox）手動操作一次登入。</li>



<li>登入成功後，回到 ZAP 的 <strong>History</strong> 標籤頁。</li>



<li>找到那筆發送帳號密碼的 <code>POST</code> 請求（通常是 <code>/login</code> 或 <code>/auth</code>）。</li>



<li>右鍵點擊該請求 -&gt; <strong>Flag as Context</strong> -&gt; 選擇你的 Context -&gt; <strong>Form-based Auth Login Request</strong>。</li>
</ul>



<h3 class="wp-block-heading">2. 設定登出指標（Logged Out Indicator）</h3>



<p class="wp-block-paragraph">ZAP 在掃描時如果看到特定的字眼，就知道自己被踢登出了（必須重新登入）。</p>



<ul class="wp-block-list">
<li>在剛剛內建瀏覽器的畫面上，找到「登出後才會出現的文字」（例如：<code>請先登入</code>、<code>Login</code>、<code>帳號或密碼錯誤</code>）。</li>



<li>在 ZAP 的 Context 設定視窗中，切換到 <strong>Authentication</strong> 頁面。</li>



<li>將驗證方法改為 <strong>Form-based Authentication</strong>（如果剛剛有正確 Flag，這裡會自動帶入登入 URL 和參數）。</li>



<li>在下方 <strong>Logged Out Indicator</strong> 欄位中，填入剛剛找到的登出關鍵字（支援正則表達式，例如：<code>.*請先登入.*</code>）。</li>
</ul>



<h2 class="wp-block-heading">步驟三：設定使用者憑證（Users）</h2>



<p class="wp-block-paragraph">讓 ZAP 知道要用哪組帳密去登入管理介面。</p>



<ol start="1" class="wp-block-list">
<li>在 Context 設定視窗中，點選 <strong>Users</strong> 頁面。</li>



<li>點擊 <strong>Add</strong> 新增一個使用者（例如：<code>admin</code>）。</li>



<li>勾選 <strong>Enabled</strong>，並輸入管理員的 <code>Username</code> 與 <code>Password</code>。</li>
</ol>



<h2 class="wp-block-heading">步驟四：設定強制使用者模式（Forced User Mode）</h2>



<p class="wp-block-paragraph">這是最關鍵的一步，強迫 ZAP 的所有掃描工具（包含 Spider 和 Active Scan）都帶著這個身分去跑。</p>



<ol start="1" class="wp-block-list">
<li>在 Context 設定視窗中，點選 <strong>Forced User</strong> 頁面。</li>



<li>在下拉選單中，選擇你剛剛在 步驟三 建立的那個使用者（<code>admin</code>）。</li>



<li>點擊 <strong>OK</strong> 儲存並關閉 Context 設定視窗。</li>



<li><strong>啟用強制模式</strong>：在 ZAP 主介面上方的工具列，找到一個「鎖頭搭配一個小人」的圖示（Forced User Mode），把它點擊下去（讓它呈現鎖定/啟用的狀態）。</li>
</ol>



<h2 class="wp-block-heading">步驟五：開始安全掃描</h2>



<p class="wp-block-paragraph">現在 ZAP 已經具備自動登入的能力了，你可以開始掃描管理介面：</p>



<ol start="1" class="wp-block-list">
<li><strong>Spider（蜘蛛爬蟲）</strong>：
<ul class="wp-block-list">
<li>在左側 Sites 樹狀目錄，右鍵點擊管理介面的資料夾（例如 <code>/admin</code>）。</li>



<li>選擇 <strong>Attack</strong> -&gt; <strong>Spider&#8230;</strong>。</li>



<li>在彈出的視窗中，<strong>User</strong> 欄位記得選擇你設定的 <code>admin</code>，然後點擊 <strong>Start Scan</strong>。這時 ZAP 就會帶著登入身分去爬取所有管理員才能看到的頁面。</li>
</ul>
</li>



<li><strong>Active Scan（主動掃描/弱點掃描）</strong>：
<ul class="wp-block-list">
<li>爬蟲結束後，一樣右鍵點擊該目錄 -&gt; <strong>Attack</strong> -&gt; <strong>Active Scan&#8230;</strong>。</li>



<li>同樣確保 <strong>User</strong> 選擇 <code>admin</code>，點擊 <strong>Start Scan</strong>，ZAP 就會開始對管理介面進行漏洞狂轟猛炸。</li>
</ul>
</li>
</ol>



<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>進階小撇步 (如果管理介面有驗證碼/雙因子認證 CAPTCHA / 2FA)：</strong></p>



<p class="wp-block-paragraph">自動化工具通常無法破解驗證碼。如果遇到這種情況，建議改用 <strong>Replacer 功能</strong> 或 <strong>Scripting</strong> 直接把手動登入後取得的 <code>Cookie</code> 或 <code>Bearer Token</code> 塞給 ZAP 瀏覽器，但缺點是 Token 過期就必須手動更新。</p>
</blockquote>



<p class="wp-block-paragraph">你在設定 Form-based Auth 的過程中，有遇到特定的登入阻礙（例如前端加密、Token 驗證）嗎？</p>



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



<p class="wp-block-paragraph">GUI 很麻煩, 改用 terminal 比較方便</p>



<p class="wp-block-paragraph">Shell Tail second dry-run log 35 lines<br>Found Java version 17.0.19<br>Available memory: 15863 MB<br>Using JVM args: -Xmx3965m<br>307 [main] INFO org.parosproxy.paros.Constant &#8211; Copying default configuration to /home/zap/.ZAP/config.xml<br>381 [main] INFO org.parosproxy.paros.Constant &#8211; Creating directory /home/zap/.ZAP/session<br>382 [main] INFO org.parosproxy.paros.Constant &#8211; Creating directory /home/zap/.ZAP/dirbuster<br>382 [main] INFO org.parosproxy.paros.Constant &#8211; Creating directory /home/zap/.ZAP/fuzzers<br>383 [main] INFO org.parosproxy.paros.Constant &#8211; Creating directory /home/zap/.ZAP/plugin<br>Jul 06, 2026 3:33:16 AM java.util.prefs.FileSystemPreferences$1 run<br>INFO: Created user preferences directory.<br>Downloading add-on from:<br>https://github.com/zaproxy/zap-extensions/releases/download/commonlib-v1.42.0/commonlib-release-1.42.0.zap<br>Downloading add-on from:<br>https://github.com/zaproxy/zap-extensions/releases/download/authhelper-v0.40.0/authhelper-beta-0.40.0.zap<br>Downloading add-on from:<br>https://github.com/zaproxy/zap-extensions/releases/download/selenium-v15.51.0/selenium-release-15.51.0.zap<br>Add-on downloaded to: /home/zap/.ZAP/plugin/authhelper-beta-0.40.0.zap<br>Add-on downloaded to: /home/zap/.ZAP/plugin/commonlib-release-1.42.0.zap<br>Add-on downloaded to: /home/zap/.ZAP/plugin/selenium-release-15.51.0.zap</p>



<p class="wp-block-paragraph">Tasks<br>&#8212;<br>│ │ Subagents<br>│ No subagents<br>│<br>│ Shell Commands<br>│ ❯ ◎ Run ZAP full scan in background, logging output [detached background]</p>



<p class="wp-block-paragraph">改用 AI 代勞進行 scan 超方便, 完全不需要去學習如何使用.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://stackoverflow.max-everyday.com/2026/07/zap-backend-gui/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>如何申請google oauth</title>
		<link>https://stackoverflow.max-everyday.com/2026/06/apply-google-oauth/</link>
					<comments>https://stackoverflow.max-everyday.com/2026/06/apply-google-oauth/#respond</comments>
		
		<dc:creator><![CDATA[max-stackoverflow]]></dc:creator>
		<pubDate>Thu, 25 Jun 2026 09:34:38 +0000</pubDate>
				<category><![CDATA[電腦相關應用]]></category>
		<guid isPermaLink="false">https://stackoverflow.max-everyday.com/?p=8601</guid>

					<description><![CDATA[申請 Google OAuth 其實不難，主要是...]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">申請 Google OAuth 其實不難，主要是在 <strong>Google Cloud Console</strong> 中完成。不論你是要開發網站登入、串接 Google Drive 還是發送 Gmail，流程都大同小異。</p>



<p class="wp-block-paragraph">以下為你整理出最流暢的申請 4 大步驟：</p>



<h3 class="wp-block-heading">第一步：建立新專案</h3>



<ol start="1" class="wp-block-list">
<li>前往 <a href="https://console.cloud.google.com/" target="_blank" rel="noreferrer noopener">Google Cloud Console</a>。</li>



<li>登入你的 Google 帳號。</li>



<li>點擊左上角的專案下拉選單，選擇 <strong>「新建專案」 (New Project)</strong>。</li>



<li>輸入專案名稱（例如：<code>MyAwesomeApp</code>），然後點擊 <strong>「建立」</strong>。</li>
</ol>



<h3 class="wp-block-heading">第二步：設定 OAuth 同意畫面 (OAuth Consent Screen)</h3>



<p class="wp-block-paragraph">這是使用者在登入你的 App 時會看到的授權畫面，必須先設定它。</p>



<ol start="1" class="wp-block-list">
<li>點擊左側選單的 <strong>「API 和服務」 > 「OAuth 同意畫面」</strong>。</li>



<li>選擇 <strong>User Type</strong>：
<ul class="wp-block-list">
<li><strong>外部 (External)：</strong> 開放給所有 Google 帳號（一般應用程式選這個）。</li>



<li><strong>內部 (Internal)：</strong> 僅限你 Google Workspace 組織內的成員（企業內部工具選這個）。</li>
</ul>
</li>



<li>填寫基本資料：<strong>應用程式名稱</strong>、<strong>使用者支援電子郵件</strong> 以及 <strong>開發人員聯絡資訊</strong>，完成後點擊「儲存並繼續」。</li>



<li><strong>範圍 (Scopes)：</strong> 設定你想拿到的權限（如 <code>email</code>, <code>profile</code>）。初次測試可以先不選，直接跳過。</li>



<li><strong>測試使用者 (Test Users)：</strong> 如果你的專案還在「測試中」階段，<strong>必須</strong>在這裡新增你自己的測試 Email，否則其他帳號會無法登入。</li>
</ol>



<h3 class="wp-block-heading">第三步：建立憑證 (Credentials) 取得密鑰</h3>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="496" src="https://stackoverflow.max-everyday.com/wp-content/uploads/2026/06/chrome_2026-06-25-17-16-c1-1024x496.jpg?v=1782379301" alt="" class="wp-image-8602" srcset="https://stackoverflow.max-everyday.com/wp-content/uploads/2026/06/chrome_2026-06-25-17-16-c1-1024x496.jpg?v=1782379301 1024w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/06/chrome_2026-06-25-17-16-c1-600x291.jpg?v=1782379301 600w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/06/chrome_2026-06-25-17-16-c1-768x372.jpg?v=1782379301 768w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/06/chrome_2026-06-25-17-16-c1-1536x744.jpg?v=1782379301 1536w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/06/chrome_2026-06-25-17-16-c1.jpg?v=1782379301 1754w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">這一步會生成你的 <code>Client ID</code> 和 <code>Client Secret</code>。</p>



<ol start="1" class="wp-block-list">
<li>點擊左側選單的 <strong>「憑證」 (Credentials)</strong>。</li>



<li>點擊上方的 <strong>「+ 建立憑證」 > 「OAuth 用戶端 ID」</strong>。</li>



<li>選擇你的 <strong>應用程式類型</strong>（例如：網頁應用程式、Android、iOS 等）。</li>



<li><strong>填寫核心網址（以網頁應用程式為例）：</strong>
<ul class="wp-block-list">
<li><strong>已授權的 JavaScript 來源：</strong> 你的網站首頁（例如：<code>http://localhost:3000</code> 或 <code>https://yourdomain.com</code>）。</li>



<li><strong>已授權的重新導向 URI：</strong> 使用者登入成功後，Google 把 Code 送回你網站的後端路由（例如：<code>http://localhost:3000/auth/google/callback</code>）。<em>※ 注意：這裡一定要設定精準，否則會噴 <code>redirect_uri_mismatch</code> 錯誤。</em></li>
</ul>
</li>



<li>點擊 <strong>「建立」</strong>。</li>
</ol>



<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> 畫面上會跳出你的 <strong>用戶端 ID (Client ID)</strong> 和 <strong>用戶端密鑰 (Client Secret)</strong>。請立刻複製並妥善保管，<strong>密鑰絕對不能外流</strong>！</p>
</blockquote>



<h3 class="wp-block-heading">第四步：切換為「生產模式」（選填）</h3>



<p class="wp-block-paragraph">在開發測試階段，你的專案狀態會是「測試中 (Testing)」，只有你在第二步設定的測試小夥伴能登入，且可能會有不安全應用的警告。</p>



<ul class="wp-block-list">
<li>當你的 App 準備好上線時，回到 <strong>「OAuth 同意畫面」</strong>，點擊 <strong>「發布應用程式」 (Publish App)</strong> 切換為正式生產模式。</li>



<li><em>備註：如果你申請了敏感權限（如讀取使用者的 Gmail 私訊），Google 會需要人工審查，可能需要幾天到幾週的時間。</em></li>
</ul>



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



<p class="wp-block-paragraph">我有測試環境 domain name  與正式環境 domain name 要申請2組 OAuth 2.0 用戶端 ID 嗎? 還是同一組ID即可。</p>



<p class="wp-block-paragraph"><strong>建議申請「2 組獨立的 OAuth 2.0 用戶端 ID (Client ID)」。</strong></p>



<p class="wp-block-paragraph">雖然在技術上，Google 允許你在同一組 Client ID 的「已授權的重新導向 URI」中，同時填入測試環境與正式環境的網址，但<strong>非常強烈建議分開申請</strong>。原因如下：</p>



<h3 class="wp-block-heading">1. 安全性考量（最重要的原因）</h3>



<ul class="wp-block-list">
<li><strong>憑證外流風險：</strong> 測試環境通常防護較弱，可能會有較多開發人員、測試人員接觸到設定檔。如果測試環境的 Client Secret（用戶端密鑰）不小心外流，且你兩邊用同一組 ID，<strong>攻擊者就能利用外流的密鑰去染指或偽造正式環境的登入請求</strong>。</li>



<li><strong>網址白名單污染：</strong> 萬一測試環境網址被惡意劫持或存在漏洞，它與正式環境共享同一個 OAuth 信任圈，會帶來額外的安全隱患。</li>
</ul>



<h3 class="wp-block-heading">2. Google 審查與「發布狀態」限制</h3>



<p class="wp-block-paragraph">Google Cloud 專案的 OAuth 同意畫面有分兩種狀態：</p>



<ul class="wp-block-list">
<li><strong>測試中 (Testing)：</strong> 只有白名單內的「測試使用者」可以登入，且登入時會跳出「未經驗證的應用程式」警告。</li>



<li><strong>生產模式 (In Production)：</strong> 開放給所有 Google 帳號登入。如果使用了敏感權限（Scopes），還需要通過 Google 的人工驗證。</li>
</ul>



<p class="wp-block-paragraph"><strong>如果你只用一組：</strong></p>



<p class="wp-block-paragraph">當你的專案為了正式環境切換成「生產模式」並送交審查時，如果你的網址白名單裡還夾帶了 <code>project-name.test.example.com.tw</code>（而且通常測試環境在外網無法被 Google 審查官順利連上），<strong>這可能會導致你的 Google 審查被拒絕 (Rejected)</strong>，因為 Google 要求生產模式下的網址必須是公開、真實且符合規範的。</p>



<h3 class="wp-block-heading">最佳實作做法 (Best Practice)</h3>



<p class="wp-block-paragraph">為了架構清晰與安全，你可以選擇以下兩種配置方式：</p>



<h4 class="wp-block-heading">方案 A：在同一個 Google Cloud 專案下，建立 2 個 Client ID（推薦，最方便）</h4>



<p class="wp-block-paragraph">在同一個專案的「憑證」頁面中，點擊兩次「建立憑證 &gt; OAuth 用戶端 ID」：</p>



<ul class="wp-block-list">
<li><strong>第一組 ID（命名：Project Name &#8211; Test）：</strong>
<ul class="wp-block-list">
<li>重新導向 URI 填：<code>https://projectname.test.example.com.tw/oauth2/callback</code></li>
</ul>
</li>



<li><strong>第二組 ID（命名：Project Name &#8211; Prod）：</strong>
<ul class="wp-block-list">
<li>重新導向 URI 填：<code>https://projectname.example.com.tw/oauth2/callback</code></li>
</ul>
</li>
</ul>



<p class="wp-block-paragraph"><em>這樣你在程式碼的環境變數（<code>.env</code>）中，測試機就讀取測試的 ID/Secret，正式機就讀取正式的 ID/Secret，彼此互不干擾。</em></p>



<h4 class="wp-block-heading">方案 B：建立 2 個獨立的 Google Cloud 專案（最嚴謹）</h4>



<ul class="wp-block-list">
<li>專案一：<code>PorjectName-Test</code>（專案狀態保持在 Testing，方便開發隨時測試）</li>



<li>專案二：<code><code>PorjectName</code>-Prod</code>（專案狀態切換為 Production，專門用來跑正式上線與 Google 審查流程）</li>
</ul>



<p class="wp-block-paragraph"><strong>總結：</strong> 為了維護系統的安全防線與後續維護的便利性，請務必為測試與正式環境分開申請獨立的憑證！</p>



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



<p class="wp-block-paragraph">應用程式是哪種類型, Vue 3 + Vite</p>



<p class="wp-block-paragraph">既然你的前端技術棧是 <strong>Vue 3 + Vite</strong>，在架構設計上你首先需要釐清一個關鍵問題：<strong>你的應用程式有沒有後端（Backend，如 Node.js, Python, Go）？</strong></p>



<p class="wp-block-paragraph">這會直接決定你如何實作 Google OAuth。以下為你說明這兩種情境與實作方式：</p>



<h3 class="wp-block-heading">情境一：有後端（推薦，最安全）</h3>



<p class="wp-block-paragraph">這是最正統的做法。Vue 3 只負責顯示「登入按鈕」，使用者點擊後會引導到 Google 登入，登入成功後 Google 會把驗證碼（Authorization Code）傳給你的<strong>後端</strong>，由後端去跟 Google 交換 Token，並簽發你網站自己的 JWT 給 Vue 3。</p>



<p class="wp-block-paragraph">在這種模式下，你的 <strong>OAuth 2.0 用戶端 ID 類型</strong>要選擇：<strong>「網頁應用程式」 (Web Application)</strong>。</p>



<h4 class="wp-block-heading">Vite / Vue 3 前端實作步驟：</h4>



<p class="wp-block-paragraph">目前社群上最推崇、封裝最完整的套件是 <code>vue3-google-signin</code>。</p>



<p class="wp-block-paragraph"><strong>安裝套件：</strong>Bash</p>



<pre class="wp-block-code"><code><code>npm install vue3-google-signin</code></code></pre>



<p class="wp-block-paragraph"><strong>在 <code>main.js</code> 或 <code>main.ts</code> 中初始化：</strong></p>



<pre class="wp-block-code"><code>import { createApp } from 'vue'
import App from './App.vue'
import GoogleSignInPlugin from 'vue3-google-signin'

const app = createApp(App)

app.use(GoogleSignInPlugin, {
  // Vite 的環境變數必須以 VITE_ 開頭
  clientId: import.meta.env.VITE_GOOGLE_CLIENT_ID,
})

app.mount('#app')</code></pre>



<p class="wp-block-paragraph"><strong>在畫面上建立登入按鈕 (<code>Login.vue</code>)：</strong></p>



<pre class="wp-block-code"><code>&lt;script setup>
import { GoogleLogin } from 'vue3-google-signin'

const handleLoginSuccess = (response) => {
  // 這裡會拿到 Google 回傳的 code 或 credential
  console.log("Google 登入成功:", response);

  // 【關鍵】將這個 response (含 code) 用 axios 傳送給你的後端
  // axios.post('https://projectname.example.come.tw/api/auth/google', { code: response.code })
}

const handleLoginError = () => {
  console.error("Google 登入失敗")
}
&lt;/script>

&lt;template>
  &lt;div class="login-container">
    &lt;h2>入口網登入&lt;/h2>
    &lt;GoogleLogin :callback="handleLoginSuccess" :popup-type="'CODE'" @error="handleLoginError" />
  &lt;/div>
&lt;/template></code></pre>



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



<h3 class="wp-block-heading">情境二：純前端（SPA 單頁應用，無後端）</h3>



<p class="wp-block-paragraph">如果你的 Vue 3 是一個完全靜態的網站，沒有任何自己的後端資料庫，單純只想確認「他是誰」或者想在前端呼叫 Google API（例如讀取他的 Google Calendar）。</p>



<p class="wp-block-paragraph">在這種模式下，你的 <strong>OAuth 2.0 用戶端 ID 類型</strong>一樣選擇：<strong>「網頁應用程式」</strong>。但流程會走「隱含授權 (Implicit Flow)」，直接在前端取得 <code>access_token</code>。</p>



<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/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <strong>安全警告：</strong> 因為純前端沒有秘密可言，你的 <code>Client Secret</code> 絕對不能寫在 Vue 3 的原始碼或 <code>.env</code> 裡（因為打包後任何人都能看光）。在 Google Console 建立憑證時，這種模式通常不需要用到 Client Secret。</p>
</blockquote>



<h4 class="wp-block-heading">前端設定差異：</h4>



<p class="wp-block-paragraph">如果你是用上面提到的 <code>vue3-google-signin</code>，在按鈕上就不要加 <code>:popup-type="'CODE'"</code>，它預設會直接在前端回傳一串 JWT（身分憑證），你可以直接解開它來取得使用者的 Email 和姓名：</p>



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



<pre class="wp-block-code"><code>import { decodeCredential } from 'vue3-google-signin'

const handleLoginSuccess = (response) =&gt; {
  // 直接在前端解密 Google 回傳的使用者資訊
  const userData = decodeCredential(response.credential)
  console.log("使用者資料:", userData) // 包含 email, name, picture
}
</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;" /> 搭配你上一題的測試/正式環境，Vite 該如何設定？</h3>



<p class="wp-block-paragraph">因為你有兩個環境，請在 Vue 3 專案根目錄建立兩個環境變數檔案：</p>



<ol start="1" class="wp-block-list">
<li><strong><code>.env.development</code></strong> (測試環境用)程式碼片段<code>VITE_GOOGLE_CLIENT_ID=你的測試環境_CLIENT_ID.apps.googleusercontent.com</code></li>



<li><strong><code>.env.production</code></strong> (正式環境用)程式碼片段<code>VITE_GOOGLE_CLIENT_ID=你的正式環境_CLIENT_ID.apps.googleusercontent.com</code></li>
</ol>



<p class="wp-block-paragraph">當你執行 <code>vite preview</code> 或 <code>vite build</code> 時，Vite 就會自動根據環境抓取正確的 Client ID，完美對應到正式環境與測試環境了！</p>
]]></content:encoded>
					
					<wfw:commentRss>https://stackoverflow.max-everyday.com/2026/06/apply-google-oauth/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>預覽 PlantUML 的 .puml 檔案</title>
		<link>https://stackoverflow.max-everyday.com/2026/06/preview-plant-uml-puml/</link>
					<comments>https://stackoverflow.max-everyday.com/2026/06/preview-plant-uml-puml/#respond</comments>
		
		<dc:creator><![CDATA[max-stackoverflow]]></dc:creator>
		<pubDate>Thu, 25 Jun 2026 09:20:48 +0000</pubDate>
				<category><![CDATA[電腦相關應用]]></category>
		<guid isPermaLink="false">https://stackoverflow.max-everyday.com/?p=8596</guid>

					<description><![CDATA[這裡幫大家整理了 4 個超實用的方法，不管是想要...]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="572" src="https://stackoverflow.max-everyday.com/wp-content/uploads/2026/06/preview-plant-uml-puml_clean-1024x572.jpg?v=1782379243" alt="" class="wp-image-8599" srcset="https://stackoverflow.max-everyday.com/wp-content/uploads/2026/06/preview-plant-uml-puml_clean-1024x572.jpg?v=1782379243 1024w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/06/preview-plant-uml-puml_clean-600x335.jpg?v=1782379243 600w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/06/preview-plant-uml-puml_clean-768x429.jpg?v=1782379243 768w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/06/preview-plant-uml-puml_clean.jpg?v=1782379243 1376w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">這裡幫大家整理了 4 個超實用的方法，不管是想要神級的操作體驗，還是懶得安裝任何軟體的速成法，這篇通通有。</p>



<h2 class="wp-block-heading">方法 1 ： VS Code 神級流暢體驗（強烈推薦）</h2>



<p class="wp-block-paragraph">如果你平常就在用 Visual Studio Code 寫程式，這絕對是最頂的選擇，可以享受一邊打字、旁邊畫面一邊即時更新的快感。</p>



<ol start="1" class="wp-block-list">
<li>打開 VS Code ，到擴充功能市場搜尋並安裝 PlantUML 這個套件。</li>



<li>注意，這裡有一個重要的小跟班需要安裝。因為 PlantUML 畫圖需要 Graphviz 的協助，請打開命令提示字元輸入 winget install Graphviz 來快速搞定它。</li>



<li>如果真的懶得在電腦安裝 Graphviz 怎麼辦？也可以直接到 VS Code 的設定裡搜尋 plantuml.server ，把它改成連到官方的線上伺服器來幫你畫圖。</li>



<li>萬事俱備後，打開 .puml 檔案，按下 Alt + D ，右邊就會跳出即時預覽畫面。</li>
</ol>



<h2 class="wp-block-heading">方法 2 ： JetBrains 宇宙（ IntelliJ 、 PyCharm 專屬）</h2>



<p class="wp-block-paragraph">如果你是 JetBrains 系列 IDE 的忠實粉絲，根本不用離開視窗，裡面就自帶強大功能。</p>



<ol start="1" class="wp-block-list">
<li>點選 File 進入 Settings ，接著找到 Plugins 區塊。</li>



<li>搜尋 PlantUML Integration 並點擊安裝。</li>



<li>把 IDE 重新啟動。</li>



<li>接下來只要打開任何 .puml 檔案，右邊就會自動長出專屬的預覽視窗，完全不用操心。</li>
</ol>



<h2 class="wp-block-heading">方法 3 ： 獨立 Java 檔案（免安裝開發工具）</h2>



<p class="wp-block-paragraph">如果不想為了看張圖就開啟笨重的開發工具，也可以用官方提供的輕量級 Java 小工具。</p>



<ol start="1" class="wp-block-list">
<li>請先確保電腦裡有安裝 Java 執行環境。</li>



<li>到 <a href="https://plantuml.com/" target="_blank" rel="noreferrer noopener">PlantUML 官方網站</a> 下載 plantuml.jar 檔案。</li>



<li>打開命令提示字元，切換到下載的資料夾，輸入 java -jar plantuml.jar -gui 這一行指令。</li>



<li>畫面上就會跳出一個小巧的視窗，只要選好放 .puml 檔案的資料夾，每次只要存檔，它就會自動幫你刷新圖片。</li>
</ol>



<h2 class="wp-block-heading">方法 4 ： 線上免安裝（終極懶人法）</h2>



<p class="wp-block-paragraph">如果只是臨時要看一下檔案，連一秒鐘都不想浪費在安裝上，那就直接交給瀏覽器吧。</p>



<ul class="wp-block-list">
<li>官方線上伺服器：直接把程式碼複製貼上到 <a href="https://gemini.google.com/www.plantuml.com/plantuml" target="_blank" rel="noreferrer noopener">PlantUML Web Server</a> 就能立刻看到結果。</li>



<li>網頁編輯器： <a href="https://gemini.google.com/planttext.com" target="_blank" rel="noreferrer noopener">PlantText</a> 是一個非常受歡迎的線上即時編輯器，畫面好看而且專為 PlantUML 設計，非常適合臨時救急。</li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://stackoverflow.max-everyday.com/2026/06/preview-plant-uml-puml/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>在使用 Windows 系統 ssh: UNPROTECTED PRIVATE KEY FILE!</title>
		<link>https://stackoverflow.max-everyday.com/2026/06/%e5%9c%a8%e4%bd%bf%e7%94%a8-windows-%e7%b3%bb%e7%b5%b1-ssh-unprotected-private-key-file/</link>
					<comments>https://stackoverflow.max-everyday.com/2026/06/%e5%9c%a8%e4%bd%bf%e7%94%a8-windows-%e7%b3%bb%e7%b5%b1-ssh-unprotected-private-key-file/#respond</comments>
		
		<dc:creator><![CDATA[max-stackoverflow]]></dc:creator>
		<pubDate>Wed, 24 Jun 2026 09:25:29 +0000</pubDate>
				<category><![CDATA[電腦相關應用]]></category>
		<category><![CDATA[ssh]]></category>
		<category><![CDATA[Windows]]></category>
		<guid isPermaLink="false">https://stackoverflow.max-everyday.com/?p=8593</guid>

					<description><![CDATA[在 Windows 執行 ssh 顯示錯誤訊息 ...]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1024" height="572" src="https://stackoverflow.max-everyday.com/wp-content/uploads/2026/06/16307345641785880220.jpg?v=1782293092" alt="" class="wp-image-8594" srcset="https://stackoverflow.max-everyday.com/wp-content/uploads/2026/06/16307345641785880220.jpg?v=1782293092 1024w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/06/16307345641785880220-600x335.jpg?v=1782293092 600w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/06/16307345641785880220-768x429.jpg?v=1782293092 768w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">在 Windows 執行 ssh  顯示錯誤訊息</p>



<pre class="wp-block-preformatted">C:\Users\max&gt;ssh 4.216.213.123<br>Bad permissions. Try removing permissions for user: BUILTIN\\Users (S-1-5-32-545) on file C:/Users/max/.ssh/vm-max-pc-key.pem.<br>@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@<br>@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @<br>@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@<br>Permissions for 'C:\\Users\\max/.ssh/vm-max-pc-key.pem' are too open.<br>It is required that your private key files are NOT accessible by others.<br>This private key will be ignored.<br>Load key "C:\\Users\\max/.ssh/vm-max-pc-key.pem": bad permissions<br>azureuser@4.216.213.123: Permission denied (publickey).</pre>



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



<p class="wp-block-paragraph">在使用 Windows 系統連線到遠端伺服器的時候，是不是常常遇到 SSH 跟你鬧脾氣？</p>



<p class="wp-block-paragraph">畫面跳出一大串警告，寫著 WARNING UNPROTECTED PRIVATE KEY FILE ，然後無情地拒絕連線。這其實不是你的伺服器壞掉，而是 SSH 的安全機制太過傲嬌。它覺得你的金鑰檔案太過公開，像是把家裡鑰匙直接貼在大門口一樣危險，所以故意裝作不認識你。</p>



<p class="wp-block-paragraph">這個問題通常是因為金鑰檔案的權限開太大，導致系統內的其他使用者也能讀取。要解決這個尷尬的狀況，有兩種快速的方法可以馴服它。</p>



<p class="wp-block-paragraph">第一種方法是使用命令提示字元。</p>



<p class="wp-block-paragraph">請開啟命令提示字元，並依序輸入以下指令。記得將路徑換成自己的金鑰檔案路徑。</p>



<p class="wp-block-paragraph">第一步是取消繼承權限，指令為 </p>



<pre class="wp-block-code"><code>icacls C:\Users\your_username\.ssh\my_key.pem /inheritance:r</code></pre>



<p class="wp-block-paragraph">第二步是重新給予自己完整的控制權限，指令為 </p>



<pre class="wp-block-code"><code>icacls C:\Users\your_username\.ssh\my_key.pem /grant:r your_username:F </code></pre>



<p class="wp-block-paragraph">第二種方法是使用圖形介面，適合喜歡用滑鼠點擊的人。</p>



<p class="wp-block-paragraph">請打開檔案總管，找到金鑰檔案。在檔案上按右鍵選擇內容，切換到安全性標籤，接著點擊進階。</p>



<p class="wp-block-paragraph">在進階安全性設定視窗中，點擊停用繼承，並選擇將繼承的權限轉換為此物件的明確權限。</p>



<p class="wp-block-paragraph">最後在權限項目清單中，找到 Users 這個群組並將它移除，只留下自己的使用者帳號擁有存取權限。點擊套用並確定就完成了。</p>



<p class="wp-block-paragraph">設定完成之後，再次嘗試原本的連線指令，應該就能順利連上伺服器。如果還是失敗，可以嘗試在指令中明確加上減 i 參數，例如 </p>



<pre class="wp-block-code"><code>ssh -i C:\Users\your_username.ssh\my_key.pem user@1.2.3.4 </code></pre>



<p class="wp-block-paragraph">這樣就能成功登入了。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://stackoverflow.max-everyday.com/2026/06/%e5%9c%a8%e4%bd%bf%e7%94%a8-windows-%e7%b3%bb%e7%b5%b1-ssh-unprotected-private-key-file/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>把 unsafe-inline 從你的 CSP 裡面拿掉？ 醒醒吧，你的前端元件會直接罷工！</title>
		<link>https://stackoverflow.max-everyday.com/2026/06/%e6%8a%8a-unsafe-inline-%e5%be%9e%e4%bd%a0%e7%9a%84-csp-%e8%a3%a1%e9%9d%a2%e6%8b%bf%e6%8e%89%ef%bc%9f-%e9%86%92%e9%86%92%e5%90%a7%ef%bc%8c%e4%bd%a0%e7%9a%84%e5%89%8d%e7%ab%af%e5%85%83%e4%bb%b6/</link>
					<comments>https://stackoverflow.max-everyday.com/2026/06/%e6%8a%8a-unsafe-inline-%e5%be%9e%e4%bd%a0%e7%9a%84-csp-%e8%a3%a1%e9%9d%a2%e6%8b%bf%e6%8e%89%ef%bc%9f-%e9%86%92%e9%86%92%e5%90%a7%ef%bc%8c%e4%bd%a0%e7%9a%84%e5%89%8d%e7%ab%af%e5%85%83%e4%bb%b6/#respond</comments>
		
		<dc:creator><![CDATA[max-stackoverflow]]></dc:creator>
		<pubDate>Mon, 22 Jun 2026 00:51:02 +0000</pubDate>
				<category><![CDATA[電腦相關應用]]></category>
		<guid isPermaLink="false">https://stackoverflow.max-everyday.com/?p=8587</guid>

					<description><![CDATA[在網頁資安的攻防戰中，很多工程師在被資安掃描器（...]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">在網頁資安的攻防戰中，很多工程師在被資安掃描器（ 例如 ZAP ）洗臉之後，看到報告上寫著大大的「 Medium 風險： style-src 包含 unsafe-inline 」，第一個直覺通常是：「 噢，那我就在 Content-Security-Policy 裡面把 unsafe-inline 拿掉不就得了？」</p>



<p class="wp-block-paragraph">如果你現在用的是 Vue 3 搭配 Element Plus，而你在拿掉的瞬間，你的網頁基本上就半身不遂了。</p>



<ul class="wp-block-list">
<li>短期（建議）： 維持 Element Plus，接受 unsafe-inline Medium 風險，專注業務功能。</li>



<li>中期： 若資安掃描壓力大，評估 Naive UI 替換（相同 Vue 生態、學習成本低）。</li>



<li>長期： 新專案直接選 React + shadcn/ui 或 React + Mantine，避免此問題。</li>
</ul>



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



<h3 class="wp-block-heading">兩大資安大哉問： 到底能不能直接拔掉？</h3>



<p class="wp-block-paragraph">我們先把問題拆成兩個層面來看。</p>



<h4 class="wp-block-heading">1. 在 FastAPI 設定 CSP 跟在 Nginx 設定，有差嗎？</h4>



<p class="wp-block-paragraph">答案是： 完全沒有差別。</p>



<p class="wp-block-paragraph">瀏覽器是很單純的，它只看最後收到的 HTTP response header。 不管這個資安政策是後端框架 FastAPI 吐出來的，還是前端大門 Nginx 塞給它的，對瀏覽器來說都長得一樣。</p>



<p class="wp-block-paragraph">目前專案只有在 FastAPI 設定，那就繼續留在那邊就好，不需要特地搬家。</p>



<h4 class="wp-block-heading">2. 移除 unsafe-inline 之後，Element Plus 還能動嗎？</h4>



<p class="wp-block-paragraph">答案是： 絕對會壞掉，而且壞得很難看。</p>



<p class="wp-block-paragraph">如果你的 CSP 政策直接移除了 unsafe-inline，下面這些畫面上最亮眼的主角會集體罷工：</p>



<ul class="wp-block-list">
<li><strong>el-select / el-dropdown</strong>： 下拉選單直接迷路，位置飛到九霄雲外或是乾脆隱形。</li>



<li><strong>el-tooltip / el-popover</strong>： 滑鼠移過去原本該跳出的提示，現在比你的前任還要冷淡，完全沒反應。</li>



<li><strong>el-dialog</strong>： 彈出視窗直接彈歪，跟你的預期完全對不上。</li>



<li><strong>el-table 固定列</strong>： 說好要固定的欄位，現在放飛自我跟著一起滾動。</li>
</ul>



<p class="wp-block-paragraph">為什麼會這樣？ 因為這些元件在運作時，JavaScript 會在幕後瘋狂計算畫面的座標，然後直接把 <code>style="top: 200px; left: 150px;"</code> 這種類型的行內樣式塞進 HTML 標籤裡。</p>



<p class="wp-block-paragraph">當你把 unsafe-inline 拿掉，瀏覽器就會化身鐵面判官，只要看到這種行內樣式，一律當成非法入侵直接封鎖。 結果就是你的 CSP 報告看起來滿分，但使用者的畫面看起來像一場災難。</p>



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



<h3 class="wp-block-heading">那難道無解了嗎？ 現代資安的標準解法</h3>



<p class="wp-block-paragraph">好消息是，我們不需要為了資安把整個 Element Plus 換掉（ 畢竟換框架是會出人命的 ）。 在 CSP Level 3 的現代標準中，資安政策已經被細分得更聰明了。</p>



<p class="wp-block-paragraph">以前的 <code>style-src</code> 是一刀切，但現在我們可以把「 標籤 」和「 屬性 」分開管理。</p>



<p class="wp-block-paragraph">你可以試試看這套完美的資安配置：</p>



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



<pre class="wp-block-code"><code>Content-Security-Policy: style-src-elem 'self' https://cdnjs.cloudflare.com; style-src-attr 'unsafe-inline';
</code></pre>



<p class="wp-block-paragraph">這段設定的意思其實就是跟瀏覽器講悄悄話：</p>



<ul class="wp-block-list">
<li><strong>style-src-elem &#8216;self&#8217;</strong>： 只要有人想用 <code>&lt;style&gt;</code> 標籤或外掛惡意 CSS 檔案來劫持網頁，一律給我擋掉！ 這招直接封鎖了最危險的 CSS 注入攻擊。</li>



<li><strong>style-src-attr &#8216;unsafe-inline&#8217;</strong>： 至於 HTML 標籤裡面的 <code>style="..."</code> 屬性，我們就開個特權給它過吧。</li>
</ul>



<h4 class="wp-block-heading">改前 vs 改後 戰力分析</h4>



<p class="wp-block-paragraph">這樣改到底差在哪裡？ 我們直接看對比：</p>



<ul class="wp-block-list">
<li><strong><code>&lt;style&gt;</code> 注入攻擊</strong>： 改前是允許的（ 超危險 ），改後直接封鎖（ 安全 ）。</li>



<li><strong>外掛惡意 CSS 檔案</strong>： 改前是允許的（ 超危險 ），改後直接封鎖（ 安全 ）。</li>



<li><strong>Element Plus 動態定位</strong>： 改前正常，改後依然正常運作。</li>



<li><strong>資安掃描器的警告</strong>： 改前會跳出黃牌警告，改後警告直接消失。</li>
</ul>



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



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



<p class="wp-block-paragraph">想兼顧資安跟漂亮的 UI，不需要直接把 unsafe-inline 趕盡殺絕。</p>



<p class="wp-block-paragraph">透過 <code>style-src-elem</code> 和 <code>style-src-attr</code> 的分工合作，你既能把大門關緊防範黑客，又能留個小窗讓 Element Plus 的元件繼續正常跳舞。 這才是現代工程師優雅的解決之道。</p>



<p class="wp-block-paragraph">結論上來說，改用 </p>



<p class="wp-block-paragraph"></p>
]]></content:encoded>
					
					<wfw:commentRss>https://stackoverflow.max-everyday.com/2026/06/%e6%8a%8a-unsafe-inline-%e5%be%9e%e4%bd%a0%e7%9a%84-csp-%e8%a3%a1%e9%9d%a2%e6%8b%bf%e6%8e%89%ef%bc%9f-%e9%86%92%e9%86%92%e5%90%a7%ef%bc%8c%e4%bd%a0%e7%9a%84%e5%89%8d%e7%ab%af%e5%85%83%e4%bb%b6/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>介面設計的靈魂考驗：切換分頁（Toggle）還是全部攤開（No-toggle）？</title>
		<link>https://stackoverflow.max-everyday.com/2026/06/ux-toggle-reply-extend/</link>
					<comments>https://stackoverflow.max-everyday.com/2026/06/ux-toggle-reply-extend/#respond</comments>
		
		<dc:creator><![CDATA[max-stackoverflow]]></dc:creator>
		<pubDate>Wed, 17 Jun 2026 06:21:38 +0000</pubDate>
				<category><![CDATA[電腦相關應用]]></category>
		<guid isPermaLink="false">https://stackoverflow.max-everyday.com/?p=8557</guid>

					<description><![CDATA[在 ＵＸ 的設計討論中，我們常常會遇到一個經典的...]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="572" src="https://stackoverflow.max-everyday.com/wp-content/uploads/2026/06/ux-toggle-reply-extend_clean-1024x572.jpg?v=1781677292" alt="" class="wp-image-8563" srcset="https://stackoverflow.max-everyday.com/wp-content/uploads/2026/06/ux-toggle-reply-extend_clean-1024x572.jpg?v=1781677292 1024w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/06/ux-toggle-reply-extend_clean-600x335.jpg?v=1781677292 600w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/06/ux-toggle-reply-extend_clean-768x429.jpg?v=1781677292 768w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/06/ux-toggle-reply-extend_clean.jpg?v=1781677292 1376w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">在 ＵＸ 的設計討論中，我們常常會遇到一個經典的靈魂考驗：到底要用切換分頁（Toggle）還是全部攤開（No-toggle）？</p>



<p class="wp-block-paragraph">最近我們團隊為了「回覆功能（Reply）」與「延伸請求（Extend）」這兩個操作，展開了一場尊嚴與智慧的拉鋸戰。</p>



<p class="wp-block-paragraph">原本的設計是分成兩個分頁切換，但經過一番激烈的腦力激盪後，我們決定給 Toggle 一張好人卡，全面改成 No-toggle 的直接攤開設計。結果，代誌不是憨人想得那麼簡單，我們很快就被現實給打臉了。</p>



<h2 class="wp-block-heading">為什麼有些地方適合全部攤開</h2>



<p class="wp-block-paragraph">當初我們會決定把功能全部攤開，是因為回覆功能是每一次都要用的核心主角，而延伸請求是極少使用的附屬配角。</p>



<p class="wp-block-paragraph">我們以為把兩者同時顯示在畫面上，可以減少使用者的點擊次數，達到直覺的效果。</p>



<h2 class="wp-block-heading">理想很豐滿，現實很骨感：同時顯示的災難</h2>



<p class="wp-block-paragraph">當我們把回覆框和延伸請求同時大剌剌地擺在畫面上時，原本預期的貼心設計，卻變成了使用者的認知混亂。</p>



<p class="wp-block-paragraph">這兩個功能本質上其實是互斥操作。當使用者同時看到這兩個輸入區塊，大腦就會開始打結，誤以為這兩個動作是可以同時進行的，或者搞不清楚自己現在到底是在回覆，還是在發出延伸請求。</p>



<p class="wp-block-paragraph">這種畫蛇添足的設計，不但沒有降低負擔，反而讓畫面變得複雜，讓使用者產生了我是誰、我在哪、我要填哪裡的哲學思考。</p>



<h2 class="wp-block-heading">世紀大和解：還原回覆與展延切換按鈕</h2>



<p class="wp-block-paragraph">經過一場深刻的反省，我們決定痛改前非，正式宣布：還原回覆與展延切換按鈕！</p>



<p class="wp-block-paragraph">我們發現，互斥操作就應該保持獨立顯示。不要為了自以為是的體貼，就把所有東西都塞進同一個畫面裡。</p>



<p class="wp-block-paragraph">不過，這次重回 Toggle 的懷抱，我們要做得更精緻，而不是單純退回原點：</p>



<ul class="wp-block-list">
<li><strong>讓主要操作隨時待命</strong>：確保最核心的回覆功能在視覺上依然是第一優先。</li>



<li><strong>清晰的模式切換</strong>：透過更明確的切換按鈕設計，讓使用者一秒看懂現在點下去會發生什麼事。</li>



<li><strong>維持界面的乾淨俐落</strong>：把不常使用的延伸請求好好的收納起來，只有在使用者明確需要的時候才召喚它出來。</li>
</ul>



<h2 class="wp-block-heading">最終結論</h2>



<p class="wp-block-paragraph">經過這次的瘋狂甩尾調整，我們再次驗證了一個道理：世界上沒有絕對完美的 ＵＸ 設計，只有最適合當下情境的選擇。</p>



<p class="wp-block-paragraph">當兩個操作具有互斥性質時，勇敢地使用切換按鈕吧！把互斥的操作獨立開來，這種不讓使用者誤會、乾淨俐落的設計，才是真正能讓使用者用得順心、給出五星好評的體貼設計。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://stackoverflow.max-everyday.com/2026/06/ux-toggle-reply-extend/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>在 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>



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



<h2 class="wp-block-heading">預防帳號切換錯誤方法</h2>



<p class="wp-block-paragraph">max32002@example.com (小帳) 這個 email 被登記在 GitHub 的 max-little-account 帳號底下，所以即使 commit 不是 max-little-account 做的，GitHub 也會把該 author 連結到那個帳號的頭像。會發生即使是使用大帳進行 commit, 但是在history 上會看到是小帳進行 commit.</p>



<p class="wp-block-paragraph"><strong>修正步驟（事後參考）</strong></p>



<pre class="wp-block-code"><code># 1. 設定這個 repo 的 git 身份
git config user.email "max32002@gmail.com"
git config user.name "Max"

# 2. 重寫最近 N 個 commit 的 author
git rebase HEAD~4 --exec "git commit --amend --reset-author --no-edit"

# 3. Force push（因為 commit hash 改變了）
git push origin main --force</code></pre>



<p class="wp-block-paragraph"><strong>預防方法</strong></p>



<p class="wp-block-paragraph">在這個 repo 目錄下執行一次，之後每個新 commit 都會用個人信箱：</p>



<p class="wp-block-paragraph">git config user.email &#8220;max32002@gmail.com&#8221;</p>



<p class="wp-block-paragraph">電腦的 global git config（~/.gitconfig）若設定的是公司信箱，建議也在每個私人 repo 單獨覆蓋，避免日後再出現同樣問題。</p>



<p class="wp-block-paragraph"></p>
]]></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>
	</channel>
</rss>
