

<?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, 12 Aug 2026 08:04:50 +0000</lastBuildDate>
	<language>zh-TW</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0.4</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>Fortify 掃描耗盡了記憶體</title>
		<link>https://stackoverflow.max-everyday.com/2026/08/fortify-gc-overhead-limit-exceeded/</link>
					<comments>https://stackoverflow.max-everyday.com/2026/08/fortify-gc-overhead-limit-exceeded/#respond</comments>
		
		<dc:creator><![CDATA[max-stackoverflow]]></dc:creator>
		<pubDate>Wed, 12 Aug 2026 04:59:44 +0000</pubDate>
				<category><![CDATA[電腦相關應用]]></category>
		<guid isPermaLink="false">https://stackoverflow.max-everyday.com/?p=8663</guid>

					<description><![CDATA[Fortify 掃描發生 java.lang.O...]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Fortify 掃描發生 <code>java.lang.OutOfMemoryError: GC overhead limit exceeded</code>，代表 JVM 記憶體 Heap 空間不足，且垃圾回收（GC）耗費超過 98% 的時間卻只能回收不到 2% 的記憶體。堆疊訊息顯示 Fortify 在解析 PHP 的 <code>hereDoc</code> (Heredoc語法) 時耗盡了記憶體。</p>



<p class="wp-block-paragraph">請依序嘗試以下解決方案：</p>



<h2 class="wp-block-heading">1. 增加 Fortify 掃描的記憶體上限</h2>



<p class="wp-block-paragraph">預設的記憶體設定可能不足以處理大型專案或複雜的 PHP 檔案。可以在執行 <code>sourceanalyzer</code> 命令行中加入 <code>-Xmx</code> 參數來提高記憶體配額：</p>



<p class="wp-block-paragraph"><strong>命令列執行 (CLI)：</strong></p>



<pre class="wp-block-code"><code><code>sourceanalyzer -b &lt;build_id> -Xmx16G -scan -f result.fpr </code></code></pre>



<p class="wp-block-paragraph"><em>(可依你的伺服器硬體規格調整，例如 <code>-Xmx12G</code> 或 <code>-Xmx24G</code>)</em></p>



<p class="wp-block-paragraph"><strong>若使用 GUI (Audit Workbench / ScanWizard)：</strong></p>



<p class="wp-block-paragraph">開啟 Fortify Audit Workbench。</p>



<p class="wp-block-paragraph">進入 <strong>Options</strong> > <strong>Global Settings</strong> > <strong>Memory Options</strong>。</p>



<p class="wp-block-paragraph">將 <strong>Maximum Allocation (-Xmx)</strong> 調大（如 <code>16384</code> MB）。</p>



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



<p class="wp-block-paragraph"><strong>修改全域設定檔 (fortify-sca.properties)：</strong></p>



<p class="wp-block-paragraph">找到 Fortify 安裝目錄或使用者目錄下的設定檔（例如 <code>&lt;Fortify_Home>/Core/config/fortify-sca.properties</code>），修改或加入以下參數：</p>



<pre class="wp-block-code"><code><code>com.fortify.sca.ProjectScanMemoryMB=16384</code></code></pre>



<h2 class="wp-block-heading">2. 排除不必要的檔案或大型自動生成檔</h2>



<p class="wp-block-paragraph">從錯誤堆疊可看出問題出在解析 PHP 的 <code>hereDoc</code> 語法（可能是巨大的模板檔、自動生成的 SQL/Data 檔、或是包含大字串陣列的檔案）。</p>



<p class="wp-block-paragraph">如果增加記憶體後仍失敗，建議排除非必要的第三方套件與靜態檔：</p>



<p class="wp-block-paragraph"><strong>在翻譯（Translation）階段使用 <code>-exclude</code> 排除特定目錄或檔案：</strong></p>



<pre class="wp-block-code"><code>sourceanalyzer -b &lt;build_id> -exclude "/vendor/" -exclude "/node_modules/" -exclude "/*.min.js" src/</code></pre>



<p class="wp-block-paragraph"><strong>過濾大檔案：</strong></p>



<p class="wp-block-paragraph">可以在 <code>fortify-sca.properties</code> 中限制 Fortify 解析單一檔案的大小上限：</p>



<pre class="wp-block-code"><code><code>com.fortify.sca.limit.file.size=10240 </code></code></pre>



<p class="wp-block-paragraph"><em>(單位為 KB，例如設定 <code>10240</code> 會跳過大於 10MB 的單一原始碼檔案)</em></p>



<h2 class="wp-block-heading">3. 採用「雙階段掃描」分離記憶體開銷</h2>



<p class="wp-block-paragraph">若原本是單一指令執行，請改為將翻譯 (Translation)<strong>與</strong>掃描 (Scan)拆為兩個獨立步驟，並只在掃描階段調大記憶體：</p>



<pre class="wp-block-code"><code># 第一步：翻譯階段
sourceanalyzer -b myproject -clean
sourceanalyzer -b myproject ./src

# 第二步：分析掃描階段 (在此處給予最大記憶體)
sourceanalyzer -b myproject -Xmx16G -scan -f result.fpr
</code></pre>



<h3 class="wp-block-heading">建議處理順序</h3>



<ol start="1" class="wp-block-list">
<li><strong>直接將記憶體調大至 16G (<code>-Xmx16G</code>)</strong> 重試一次。</li>



<li>若依然爆記憶體，檢查專案中是否有包含大量文字資料的 <code>.php</code> 檔案（如大陣列檔、DB dump 檔、巨型 Heredoc 模板），並使用 <code>-exclude</code> 將其排除。</li>
</ol>



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



<p class="wp-block-paragraph"><strong>detail error message:</strong></p>



<pre class="wp-block-preformatted">[error]: There is not enough memory available to complete analysis.  For details on making more memory available, please consult the user manual.<br>java.lang.OutOfMemoryError: GC overhead limit exceeded<br>	at com.fortify.frontend.php.parser.PHPLexerBase.nextToken(PHPLexerBase.java:95) ~[?:?]<br>	at org.antlr.v4.runtime.BufferedTokenStream.fetch(BufferedTokenStream.java:169) ~[antlr4-runtime-4.13.1.jar:4.13.1]<br>	at org.antlr.v4.runtime.BufferedTokenStream.sync(BufferedTokenStream.java:152) ~[antlr4-runtime-4.13.1.jar:4.13.1]<br>	at org.antlr.v4.runtime.BufferedTokenStream.nextTokenOnChannel(BufferedTokenStream.java:325) ~[antlr4-runtime-4.13.1.jar:4.13.1]<br>	at org.antlr.v4.runtime.CommonTokenStream.adjustSeekIndex(CommonTokenStream.java:70) ~[antlr4-runtime-4.13.1.jar:4.13.1]<br>	at org.antlr.v4.runtime.BufferedTokenStream.consume(BufferedTokenStream.java:137) ~[antlr4-runtime-4.13.1.jar:4.13.1]<br>	at org.antlr.v4.runtime.Parser.consume(Parser.java:571) ~[antlr4-runtime-4.13.1.jar:4.13.1]<br>	at org.antlr.v4.runtime.Parser.match(Parser.java:205) ~[antlr4-runtime-4.13.1.jar:4.13.1]<br>	at com.fortify.frontend.php.parser.PHPParser.hereDocPart(PHPParser.java:9032) ~[?:?]<br>	at com.fortify.frontend.php.parser.PHPParser.hereDocExpr(PHPParser.java:8947) ~[?:?]<br>	at com.fortify.frontend.php.parser.PHPParser.primaryExpr(PHPParser.java:9230) ~[?:?]<br>	at com.fortify.frontend.php.parser.PHPParser.exponentExpr(PHPParser.java:8627) ~[?:?]<br>	at com.fortify.frontend.php.parser.PHPParser.unaryExpr(PHPParser.java:8571) ~[?:?]<br>	at com.fortify.frontend.php.parser.PHPParser.instanceofExpr(PHPParser.java:8470) ~[?:?]<br>	at com.fortify.frontend.php.parser.PHPParser.notExpr(PHPParser.java:8412) ~[?:?]<br>	at com.fortify.frontend.php.parser.PHPParser.productExpr(PHPParser.java:8321) ~[?:?]<br>	at com.fortify.frontend.php.parser.PHPParser.sumExpr(PHPParser.java:8222) ~[?:?]<br>	at com.fortify.frontend.php.parser.PHPParser.shiftExpr(PHPParser.java:8123) ~[?:?]<br>	at com.fortify.frontend.php.parser.PHPParser.comparisonExpr(PHPParser.java:8037) ~[?:?]<br>	at com.fortify.frontend.php.parser.PHPParser.equalityExpr(PHPParser.java:7960) ~[?:?]<br>	at com.fortify.frontend.php.parser.PHPParser.bitwiseAndExpr(PHPParser.java:7883) ~[?:?]<br>	at com.fortify.frontend.php.parser.PHPParser.bitwiseXorExpr(PHPParser.java:7805) ~[?:?]<br>	at com.fortify.frontend.php.parser.PHPParser.bitwiseOrExpr(PHPParser.java:7727) ~[?:?]<br>	at com.fortify.frontend.php.parser.PHPParser.booleanAndExpr(PHPParser.java:7649) ~[?:?]<br>	at com.fortify.frontend.php.parser.PHPParser.booleanOrExpr(PHPParser.java:7571) ~[?:?]<br>	at com.fortify.frontend.php.parser.PHPParser.nullCoalescingExpr(PHPParser.java:7501) ~[?:?]<br>	at com.fortify.frontend.php.parser.PHPParser.ternaryExpr(PHPParser.java:7426) ~[?:?]<br>	at com.fortify.frontend.php.parser.PHPParser.assignExpr(PHPParser.java:9557) ~[?:?]<br>	at com.fortify.frontend.php.parser.PHPParser.primaryExpr(PHPParser.java:9276) ~[?:?]<br>	at com.fortify.frontend.php.parser.PHPParser.exponentExpr(PHPParser.java:8627) ~[?:?]<br>	at com.fortify.frontend.php.parser.PHPParser.unaryExpr(PHPParser.java:8571) ~[?:?]<br>	at com.fortify.frontend.php.parser.PHPParser.instanceofExpr(PHPParser.java:8470) ~[?:?]<br></pre>



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



<p class="wp-block-paragraph">這兩個問題解答如下：</p>



<h3 class="wp-block-heading">第一題：Bash 命令列上的 <code>myproject</code> 存在哪裡？</h3>



<p class="wp-block-paragraph">在 Fortify 命令列中：</p>



<pre class="wp-block-code"><code>sourceanalyzer -b myproject -clean
sourceanalyzer -b myproject ./src
sourceanalyzer -b myproject -scan -f result.fpr
</code></pre>



<p class="wp-block-paragraph"><code>-b myproject</code> 中的 <strong><code>myproject</code></strong> 稱為 <strong>Build ID（建置識別碼）</strong>。</p>



<p class="wp-block-paragraph">它<strong>不是</strong>一個真實的專案資料夾名稱，而是 Fortify 在系統內部用來記錄「翻譯（Translation）階段抽取的原始碼 AST 語法樹與中間檔」的<strong>暫存標籤</strong>。</p>



<h4 class="wp-block-heading">1. 實際檔案存在哪裡？</h4>



<p class="wp-block-paragraph">Fortify 會將 <code>myproject</code> 的中間檔案儲存在<strong>使用者家目錄下的 Fortify SCA 暫存區</strong>：</p>



<ul class="wp-block-list">
<li><strong>Linux / macOS:</strong><br><code>~/.fortify/sca&lt;版本號>/build/myproject/</code><br></li>



<li><strong>Windows (PowerShell / CMD):</strong><br><code>C:\Users\&lt;帳號>\.fortify\sca&lt;版本號>\build\myproject\</code></li>
</ul>



<h4 class="wp-block-heading">2. 注意事項</h4>



<ul class="wp-block-list">
<li>執行 <code>-clean</code> 時（如 <code>sourceanalyzer -b myproject -clean</code>），Fortify 就會<strong>刪除</strong>這個路徑下名為 <code>myproject</code> 的暫存資料夾。</li>



<li>在同一次掃描任務中，Translation（翻譯）和 Scan（分析）必須使用<strong>完全相同的 Build ID</strong>。</li>
</ul>



<h3 class="wp-block-heading">第二題：如何匯出 DeveloperWorkbook PDF 報告？</h3>



<p class="wp-block-paragraph">Fortify 提供了一個專門的命令行報表工具 <strong><code>ReportGenerator</code></strong>，可以直接讀取掃描結果檔（<code>.fpr</code>）並套用 <code>DeveloperWorkbook</code> 範本產生 PDF 報告。<sup></sup></p>



<h4 class="wp-block-heading">1. 匯出命令（Command-line）</h4>



<p class="wp-block-paragraph">請在 Terminal / Command Prompt 執行：</p>



<pre class="wp-block-code"><code>ReportGenerator -format pdf -f DeveloperWorkbook.pdf -source result.fpr -template DeveloperWorkbook.xml
</code></pre>



<h4 class="wp-block-heading">2. 參數說明</h4>



<ul class="wp-block-list">
<li><strong><code>-format pdf</code></strong>：指定輸出格式為 PDF（亦支援 <code>rtf</code>）。</li>



<li><strong><code>-f DeveloperWorkbook.pdf</code></strong>：輸出的 PDF 檔案名稱。</li>



<li><strong><code>-source result.fpr</code></strong>：你前面掃描完成所產生的 <code>.fpr</code> 結果檔。</li>



<li><strong><code>-template DeveloperWorkbook.xml</code></strong>：指定使用研發團隊常用的 <strong>Developer Workbook</strong> 報表範本。</li>
</ul>



<h4 class="wp-block-heading">3. 補充技巧 (進階)</h4>



<p class="wp-block-paragraph"><strong>如果是系統找不到 <code>DeveloperWorkbook.xml</code>：</strong>請加上完整的範本路徑，預設位在 Fortify 安裝目錄下：</p>



<pre class="wp-block-code"><code># Linux / macOS
ReportGenerator -format pdf -f DeveloperWorkbook.pdf -source result.fpr -template /opt/Fortify/Core/config/reports/DeveloperWorkbook.xml

# Windows
ReportGenerator -format pdf -f DeveloperWorkbook.pdf -source result.fpr -template "C:\Program Files\Fortify\Core\config\reports\DeveloperWorkbook.xml"</code></pre>



<p class="wp-block-paragraph"><strong>如果報告顯示的弱點數量被限制（例如預設只印前 5 個）：</strong>可以將 <code>DeveloperWorkbook.xml</code> 複製一份出來，用文字編輯器開啟，搜尋 <code>limit="5"</code> 並將其修改為 <code>limit="-1"</code>（代表不限數量，印出全部），再將修改後的 XML 作為 <code>-template</code> 帶入即可。</p>



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



<h2 class="wp-block-heading">翻譯（Translation）階段需要限制 memory usage?</h2>



<p class="wp-block-paragraph">答案是需要。</p>



<p class="wp-block-paragraph">雖然 Fortify 官方文件常強調在「分析（Scan）」階段給予大記憶體，但<strong>翻譯（Translation）階段如果記憶體不足，同樣會直接發生 <code>OutOfMemoryError</code> 或導致解析中斷（Crash）。</strong></p>



<p class="wp-block-paragraph">特別是你的案例中有大型 PHP 檔案（帶有巨型 Heredoc 語法），Fortify 在 Translation 階段進行語法解析（Lexing/Parsing）並建構 AST（抽象語法樹）時，就會在記憶體中吃掉大量空間。</p>



<h2 class="wp-block-heading">1. 為什麼 Translation 階段也需要限制/調大記憶體？</h2>



<ol start="1" class="wp-block-list">
<li><strong>語法分析（AST 建構）：</strong> 翻譯階段並非只是「複製檔案」，而是將原始碼編譯成 Fortify 的內部中間語言（NST/AST）。遇到複雜的 PHP 樣板、巨型 JSON/SQL 字串或第三方套件時，記憶體開銷會瞬間衝高。</li>



<li><strong>預設記憶體通常太小：</strong> 若未手動指定，<code>-b</code> 翻譯階段會使用 Fortify 的預設配額（通常僅 1GB~2GB），極易觸發 <code>java.lang.OutOfMemoryError: GC overhead limit exceeded</code>。</li>
</ol>



<h2 class="wp-block-heading">2. 如何在 Translation 階段設定記憶體？</h2>



<p class="wp-block-paragraph">語法與 Scan 階段完全相同，直接在 <code>sourceanalyzer</code> 命令列加上 <strong><code>-Xmx</code></strong> 參數：</p>



<pre class="wp-block-code"><code># 1. 先清除舊的 Build ID 暫存
sourceanalyzer -b myproject -clean

# 2. 【Translation 階段】給予足夠的記憶體（例如 16G）
sourceanalyzer -b myproject -Xmx16G ./src

# 3. 【Scan 階段】同樣給予足夠的記憶體
sourceanalyzer -b myproject -Xmx16G -scan -f result.fpr
</code></pre>



<h2 class="wp-block-heading">3. Translation 階段記憶體優化的最佳做法</h2>



<p class="wp-block-paragraph">如果給了 <code>-Xmx16G</code> 在 Translation 階段依然記憶體溢位，請搭配以下優化策略：</p>



<p class="wp-block-paragraph"><strong>主動過濾不需翻譯的目錄（最有效）：</strong>不要將非業務邏輯的套件帶入 Translation 階段：</p>



<pre class="wp-block-code"><code>sourceanalyzer -b myproject -Xmx16G \ -exclude "/vendor/" \ -exclude "/node_modules/" \ -exclude "/*.min.js" \ ./src</code></pre>



<p class="wp-block-paragraph"><strong>設定單一檔案大小上限（全域設定）：</strong>在 <code>fortify-sca.properties</code> 設定檔中加上 limit，防止 Translation 階段去解析幾十 MB 的巨型檔案：</p>



<pre class="wp-block-code"><code>com.fortify.sca.limit.file.size=10240</code></pre>



<p class="wp-block-paragraph"><strong>全域預設記憶體配置：</strong>若不想每次命令列都打 <code>-Xmx</code>，可在 <code>fortify-sca.properties</code> 中調整全域預設值，這會<strong>同時作用於 Translation 與 Scan 階段</strong>：</p>



<pre class="wp-block-code"><code>com.fortify.sca.ProjectTranslationMemoryMB=16384
com.fortify.sca.ProjectScanMemoryMB=16384</code></pre>



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



<p class="wp-block-paragraph">要匯出符合 <strong>OWASP Top 10</strong> 安全標準的 PDF 報告，選取的範本（Template）檔案說明如下：</p>



<h3 class="wp-block-heading">1. 建議選擇的 Template 檔案</h3>



<p class="wp-block-paragraph">Fortify 官方內建了不同年份版本的 OWASP Top 10 報本 XML 檔，位於 Fortify 報表目錄中：</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><td><strong>範本檔名 (Template File)</strong></td><td><strong>適用 OWASP 版本</strong></td><td><strong>說明 / 適用場景</strong></td></tr></thead><tbody><tr><td><strong><code>OWASP Top 10 2021.xml</code></strong></td><td><strong>OWASP Top 10 (2021)</strong></td><td><strong>【最推薦】</strong> 目前最主流的官方標準版本，建議優先選用。</td></tr><tr><td><strong><code>OWASP Top 10 2017.xml</code></strong></td><td>OWASP Top 10 (2017)</td><td>適用於客戶或公司稽核規範明確指定 2017 年版的專案。</td></tr><tr><td><strong><code>OWASP Top 10.xml</code></strong></td><td>通用/預設連結版</td><td>部分 Fortify 舊版本的預設檔名（會指向該版本的預設 OWASP）。</td></tr></tbody></table></figure>



<h3 class="wp-block-heading">2. 命令行 (ReportGenerator) 執行指令</h3>



<p class="wp-block-paragraph">預設範本檔案存放在 Fortify 安裝目錄下的 <code>Core/config/reports/</code> 資料夾中。</p>



<h4 class="wp-block-heading"><strong>Linux / macOS:</strong></h4>



<pre class="wp-block-code"><code>ReportGenerator -format pdf \
  -f OWASP_Top10_Report.pdf \
  -source result.fpr \
  -template "/opt/Fortify/Core/config/reports/OWASP Top 10 2021.xml"
</code></pre>



<h4 class="wp-block-heading"><strong>Windows:</strong></h4>



<pre class="wp-block-code"><code>ReportGenerator -format pdf ^
  -f OWASP_Top10_Report.pdf ^
  -source result.fpr ^
  -template "C:\Program Files\Fortify\Core\config\reports\OWASP Top 10 2021.xml"
</code></pre>



<p class="wp-block-paragraph"><em>(注意：路徑中包含空白字元，必須使用雙引號 <code>"..."</code> 包裹)</em></p>



<h3 class="wp-block-heading">3. 在 Audit Workbench (GUI) 中選擇</h3>



<p class="wp-block-paragraph">若使用圖形化介面匯出：</p>



<ol start="1" class="wp-block-list">
<li>開啟 <code>.fpr</code> 結果檔。</li>



<li>點擊選單 <strong>Tools</strong> > <strong>Generate Report</strong>。</li>



<li>在 <strong>Report Template</strong> 下拉選單中選擇 <strong><code>OWASP Top 10 2021</code></strong> (或 <code>OWASP Top 10</code>)。</li>



<li>將 <strong>Format</strong> 設為 <strong>PDF</strong>，點擊 <strong>Save Report</strong> 即可。</li>
</ol>



<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;" /> 關鍵技巧：印出「所有」弱點細節 (解除預設 5 筆限制)</h3>



<p class="wp-block-paragraph">Fortify 官方預設的 OWASP 範本為了控制 PDF 頁數，<strong>預設每個漏洞分類只會列出前 5 筆弱點細節 (<code>limit="5"</code>)</strong>。</p>



<p class="wp-block-paragraph">若你的報告需要列出全部弱點：</p>



<ol start="1" class="wp-block-list">
<li>將 <code>OWASP Top 10 2021.xml</code> 複製到你的工作目錄，改名為 <code>OWASP_Custom.xml</code>。</li>



<li>用文字編輯器打開它，將裡面的 <strong><code>limit="5"</code></strong> 全部覆蓋替換為 <strong><code>limit="-1"</code></strong>（<code>-1</code> 代表不限制數量）。</li>



<li>執行指令時帶入 <code>-template OWASP_Custom.xml</code> 即可印出完整清單。</li>
</ol>



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



<h2 class="wp-block-heading">command line manual:</h2>



<pre class="wp-block-code"><code>sourceanalyzer --help
OpenText SAST (Fortify) CE 25.2.0.0116
Copyright (c) 2003-2025 Open Text

Usage:

  Clean:
     sourceanalyzer.exe -b &lt;build-id> -clean
  Build:
     sourceanalyzer.exe -b &lt;build-id> &lt;sca-build-opts>
  Scan:
     sourceanalyzer.exe -b &lt;build-id> -scan &lt;sca-scan-opts>

Detailed invocation:

  Build:
     sourceanalyzer.exe -b &lt;build-id>
          &#91; &lt;sca-build-options> ]
          &lt;file-specifier>
     sourceanalyzer.exe -b &lt;build-id>
          &#91; &lt;sca-build-options> ]
          &lt;compiler> &lt;compiler-options>
     sourceanalyzer.exe -b &lt;build-id>
          &#91; &lt;sca-build-options> ]
          touchless &lt;build-tool> &#91; &lt;build-tool-options> ]
     sourceanalyzer.exe -b &lt;build-id>
          &#91; &lt;sca-build-options> ]
          devenv &lt;solution-file> /REBUILD
     sourceanalyzer.exe -b &lt;build-id>
          &#91; &lt;sca-build-options> ]
          msbuild /t:rebuild &lt;solution-or-project-file>
     sourceanalyzer.exe -b &lt;build-id>
          &#91; &lt;sca-build-options> ]
          xcodebuild -project &lt;xcodeproj-file>
     sourceanalyzer.exe -b mybuild
          -source-base-dir &lt;webapp-root> &lt;cfm-file-specifier>
  Scan:
     sourceanalyzer.exe -b &lt;build-id> -scan
          &#91; -f &lt;output-file> ]
          &#91; -scan-precision &lt;level> ]
          &#91; -rules &lt;rules.xml> &#91; -no-default-rules ] ]
          &#91; -filter &lt;filter-file> ]
  Clean:
     sourceanalyzer.exe -b &lt;build-id> -clean
  Query:
     sourceanalyzer.exe -b &lt;build-id> { -show-build-warnings | -show-files }
     sourceanalyzer.exe { -version | -show-build-ids }
     sourceanalyzer.exe { -h | -? | -help }



Options


General Options
These options are applicable to all sourceanalyzer.exe invocations.

  @&lt;file>                     Reads command line options from the specified
                              file.  Note that there is no space before the
                              file argument.

  -debug                      Causes the build step to write additional
                              troubleshooting information to the log file.
                              Use if instructed by Fortify Customer Support.
                              Also see "-logfile".

  -logfile &lt;file>             Specifies a destination for the log file.

  -verbose                    Outputs verbose messages to the console.

  -Xmx&lt;num>M                  Specifies the maximum Java heap size.
                              Default is -Xmx1800M.

  -autoheap                   Instructs SCA to set the maximum Java heap size
                              based on available physical memory. Use instead
                              of -Xmx.  Enabled by default.

  -fcontainer                 When run in a Docker container, instructs SCA
                              to detect and use only the memory allocated to
                              the container.

  -version                    Shows the sourceanalyzer.exe version.


Command Options
Note: Only one "command" option is allowed per invocation.


  -h                          Displays this help text.
  -help
  -?

  -clean                      Deletes all intermediate files and build records.
                              When a build ID is also specified with -b, only
                              files and build records related to that build ID
                              are deleted.

  -show-binaries              See the user guide.
  -show-build-tree            See the user guide.

  -show-build-ids             Lists all the Fortify build IDs (analysis models).

  -show-build-warnings        Displays all the actionable warnings that
                              occurred during the translation phase of the build
                              ID specified by "-b".

  -show-files                 Displays all the source files built into the model
                              specified by "-b".

  -show-loc                   Displays lines of code processed for files built
                              into the model specified by "-b".

  -scan                       Causes sourceanalyzer.exe to run an analysis.

  (none)                      If no command option is present, a build step
                              is assumed.


Build Options
"Build" options translate source code into a Fortify analysis model.


  -b &lt;build-id>               Specifies a unique name that identifies the
                              Fortify analysis model to be built. Also see
                              "-scan".

  -build-label &lt;label>        Specifies an optional, arbitrary string value to
                              the Fortify analysis model. Will be included in
                              the output file.

  -build-project &lt;project>    Specifies an optional, arbitrary string value to
                              the Fortify analysis model. Will be included in
                              the output file.

  -build-version &lt;version>    Specifies an optional, arbitrary string value to
                              the Fortify analysis model. Will be included in
                              the output file.

  -encoding &lt;encoding-name>   Specifies the source file encoding.
                              Default value is the platform default.

Compiler Integration Build Options
These options are used when integrating OpenText SAST (Fortify) with a compiler.

  &lt;compiler> &lt;compiler-opts>  Specifies the compiler command line. The file
                              being compiled will be added to the analysis
                              model, and the compiler will be invoked.

  touchless &lt;build-tool>      Specifies a build tool command. The build tool
    &#91; &lt;build-tool-options> ]  will be invoked, and any file being compiled
                              will be added to the analysis model.

  -nc                         When specified, the compiler is not invoked.


File Specification Build Options
These options are used to pass source files directly to OpenText SAST (Fortify).

  &lt;file-specifier>            Expression denoting a file or a group of files,
                              optionally matching a pattern:
                              file1.java - a file
                              file*.java - files matching expression
                              "path/**/*.java" - recursive expression matches.
                              Note: Always escape ** expressions in quotes.

  -exclude &lt;file-specifier>   Excludes any files matched by &lt;file-specifier>
                              from the set of files to translate


Java-specific Build Options
These options should be used in conjunction with file specification options.

  -classpath &lt;classpath>      Uses the specified classpath value for Java
  -cp &lt;classpath>             builds.

  -extdirs                    Accepts a colon or semicolon separated list
                              of directories.  Any jar files found in
                              these directories are included on the
                              classpath. Equivalent to the -extdirs option
                              to javac.

  -sourcepath                 Specifies the location of source files which will
                              not be included in the scan but will be used for
                              name resolution. Equivalent to the -sourcepath
                              option to javac.
                              The sourcepath is like classpath, except it uses
                              source files rather than class files for
                              resolution.

  -source &lt;value>             Indicates which version of the Java language the Java
  -jdk &lt;value>                code adheres to.  Valid values are 1.8, 8, 11, 17, 21.
                              Default is "11".

  -java-build-dir &lt;dir>       Used to specify one or more directories to which
                              Java sources are being compiled. May also be
                              specified at scan time.

Other Language-Specific Build Options

  -source-base-dir &lt;root>     The base directory for a ColdFusion application.

  -python-path                Add an import directory for a Python application.

  -apex                       Set ".cls" file extension to Apex language.
                              (detected based on file content by default). Equivalent to
                              -Dcom.fortify.sca.fileextensions.cls=APEX

  -apex-sobject-path          Add file to load SObject types in Apex application.

Scan Options

  -b &lt;build-id>               Specifies the build ID.  The build ID is used
                              to track which files are compiled and linked
                              as part of a build, to later scan those files.
                              This option may be specified more than once to
                              include multiple build IDs in the same scan.

  -bin &lt;binary>               All source files compiled and linked into the
                              specified binary are scanned.  Multiple binaries
                              may be specified.

  -disable-default-rule-type  See the user guide.

  -f &lt;file>                   The file to which analysis results are written.
                              Default is stdout.

  -filter &lt;file>              Specifies a filter file.  For more information,
                              see the user guide.

  -scan-policy &lt;policy>       Specifies a scan policy for vulnerability prioritization.
                              Valid values are classic, security, devops. Default is security.
                              For more information, see the user guide.

  -java-build-dir &lt;dir>       Used to specify one or more directories to which
                              Java sources have been compiled.  May also be
                              specified at build time.

  -no-default-issue-rules     See the user guide.
  -no-default-sink-rules      See the user guide.
  -no-default-source-rules    See the user guide.

  -no-default-rules           Indicates that OpenText SAST (Fortify) should not use its
                              default rules.  Must be used in conjunction with
                              "-rules"

  -rules &lt;specifier>          Specifies custom rules file or directory.  If a
                              directory is specified, all files ending in ".bin"
                              or ".xml" are included.
                              This option may be used multiple times.

  -quick                      Runs a quick scan. Quick scans complete faster at
                              the cost of reduced accuracy.

  -scan-precision &lt;level>     Configures the depth, precision and speed of the scan
  -p &lt;level>                  with configuration properties specific for the level.
                              The valid values are 1, 2, 3, and 4.

  -quiet                      Disables the command line progress bar.

  -scan                       Causes OpenText SAST (Fortify) to perform analysis against a
                              model.  The model must be specified with "-b".


Build Sessions

  -export-build-session &lt;file.mbs>

                              Store the translated model specified by -b to the
                              specified file.

  -import-build-session &lt;file.mbs>

                              Load the specified file into a build model.  If
                              the build ID of the model already exists in the
                              model registry, the import fails with the message
                              that a build already exists with that ID.


License Directives

  -store-license-pool-credentials "&lt;lim_url>|&lt;lim_pool_name>|&lt;lim_pool_pwd>|&lt;proxy_url>|&lt;proxy_user>|&lt;proxy_pwd>"

                              Stores your LIM license pool credentials to
                              allow OpenText SAST (Fortify) to use the
                              LIM for licensing. Proxy information is optional.

  -clear-license-pool-credentials

                              Removes the LIM license pool credentials from
                              the fortify-sca.properties file.

  -request-detached-lease &lt;duration>

                              Requests a detached lease from the LIM license
                              pool for exclusive use on this system for the
                              specified duration (in minutes).

  -release-detached-lease

                              Releases a detached lease back to the license
                              pool.


EXAMPLES


Build examples:
  Generic (Java, configuration, PHP, JavaScript, ASP/VBScript, VB6):
     sourceanalyzer.exe -b mybuild .
     sourceanalyzer.exe -b mybuild file1.java file2.java
     sourceanalyzer.exe -b mybuild *.bas *.cls *.frm
     sourceanalyzer.exe -b mybuild "site/**/*.php"

  ColdFusion translation:
     sourceanalyzer.exe -b mybuild -source-base-dir /www/app "/www/app/**/*.cfm"

  SQL translation:
     sourceanalyzer.exe -b mybuild -Dcom.fortify.sca.fileextensions.sql=PLSQL *.sql
     sourceanalyzer.exe -b mybuild -Dcom.fortify.sca.fileextensions.sql=TSQL *.sql

  C/C++ builds:
     sourceanalyzer.exe -b mybuild gcc -c test.c
     sourceanalyzer.exe -b mybuild CL.EXE /o HelloWorld HelloWorld.c
     sourceanalyzer.exe -b mybuild make
     sourceanalyzer.exe -b mybuild devenv myproject.msproj /REBUILD

  Objective-C/C++ builds:
     sourceanalyzer.exe -b mybuild clang -ObjC HelloWorld.m
     sourceanalyzer.exe -b mybuild xcodebuild -project myproject.xcodeproj

  .NET builds:
     sourceanalyzer.exe -b mybuild devenv myproj.sln /REBUILD
     sourceanalyzer.exe -b mybuild msbuild /t:rebuild myproj.csproj

  Java specific builds:
     sourceanalyzer.exe -b mybuild -cp lib/dependency.jar "src/**/*.java"
     sourceanalyzer.exe -b mybuild -cp mytaglibs.jar webapp/*.jsp
     sourceanalyzer.exe -b mybuild touchless ant

  J2EE specific builds:
     sourceanalyzer.exe -b mybuild -cp "app/WEB-INF/lib/*.jar" app/*.jsp

Scan step:
     sourceanalyzer.exe -b mybuild -scan -f results.fpr


See OpenText(TM) Static Application Security Testing (Fortify) User Guide for a complete explanation of each option.


You can open a support case for Fortify products online using
our customer support system. This streamlined procedure is designed to
provide easier access and improved customer satisfaction.

Access your account at https://softwaresupport.softwaregrp.com/.</code></pre>



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



<p class="wp-block-paragraph">這代表即使給了 32G 記憶體，ANTLR 在解析 PHP 語法時仍陷入了死迴圈或極度消耗記憶體的狀態（問題依然卡在 <code>PHPParser.hereDocPart</code> / <code>PHPLexerBase</code>）。</p>



<p class="wp-block-paragraph">通常這有兩個主因：</p>



<ol start="1" class="wp-block-list">
<li><strong>Windows 通配符問題</strong>：<code>-exclude "/vendor/"</code> 在 CMD/PowerShell 根本沒有生效，Fortify 依然把 <code>vendor</code> 進去了。</li>



<li><strong>存在「超大檔」或「極長 Heredoc 檔」</strong>：例如大型 SQL dump、Base64 圖片檔、自動生成的測試資料或超大樣板檔，導致 ANTLR Parser 記憶體暴增。</li>
</ol>



<p class="wp-block-paragraph">請依序透過以下方法徹底解決：</p>



<h3 class="wp-block-heading">1. 修正 Windows 的 <code>-exclude</code> 語法（最常踩坑）</h3>



<p class="wp-block-paragraph">在 Windows 命令列，<code>-exclude</code><strong>必須使用雙引號，且建議使用 <code>**</code> (Ant 語法) 與 Windows 反斜線</strong>，否則過濾會無效：</p>



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



<pre class="wp-block-code"><code>sourceanalyzer -b portal_project -clean

sourceanalyzer -b portal_project -Xmx32G -exclude "**/vendor/**" -exclude "**/node_modules/**" -exclude "**/*.min.js" backend/
</code></pre>



<h3 class="wp-block-heading">2. 開啟弱點檔大小限制 (Limit File Size)</h3>



<p class="wp-block-paragraph">這是解決 <code>hereDoc</code> 爆記憶體最有效的武器。直接限制 Fortify 跳過單檔超過指定大小的檔案（例如 1MB 或 2MB）：</p>



<h4 class="wp-block-heading">做法 A：命令列加上 <code>-D</code> 參數</h4>



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



<pre class="wp-block-code"><code>sourceanalyzer -b portal_project -Xmx32G -Dcom.fortify.sca.limit.file.size=2048 -exclude "**/vendor/**" backend/
</code></pre>



<p class="wp-block-paragraph"><em>( <code>2048</code> 代表超過 2MB 的原始碼檔案就跳過不安裝/解析，可有效避免吃到包含巨大字串或 Heredoc 的 PHP 檔案)</em></p>



<h4 class="wp-block-heading">做法 B：修改 <code>fortify-sca.properties</code></h4>



<p class="wp-block-paragraph">在 <code>C:\Users\&lt;你的帳號&gt;\.fortify\fortify-sca.properties</code> 或 Fortify 安裝目錄下的 <code>Core\config\fortify-sca.properties</code> 加入：</p>



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



<pre class="wp-block-code"><code>com.fortify.sca.limit.file.size=2048
</code></pre>



<h3 class="wp-block-heading">3. 找出到底是哪個「元凶檔案」卡住，單獨排除它</h3>



<p class="wp-block-paragraph">如果是業務邏輯資料夾內有一個幾十 MB 的 PHP 檔案（例如包含超大字串陣列或字典）：</p>



<p class="wp-block-paragraph">請加上 <strong><code>-debug</code></strong> 或 <strong><code>-verbose</code></strong> 參數重新執行一次，並觀察 log 印到哪一個 <code>.php</code> 檔案時卡死：</p>



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



<pre class="wp-block-code"><code>sourceanalyzer -b portal_project -Xmx32G -verbose backend/ &gt; scan_log.txt
</code></pre>



<p class="wp-block-paragraph">打開 <code>scan_log.txt</code> 翻到最底端，查看崩潰前最後進行解析（Parsing/Lexing）的是哪一個 <code>.php</code> 檔案，接著直接將該檔案加入排除：</p>



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



<pre class="wp-block-code"><code>sourceanalyzer -b portal_project -Xmx32G -exclude "**/ProblematicFile.php" backend/
</code></pre>



<h3 class="wp-block-heading">4. （終極方案）調整 ANTLR / PHP 語法分析設定</h3>



<p class="wp-block-paragraph">如果特定 PHP 檔案無法排除，但包含極長的 Heredoc，可以在 <code>fortify-sca.properties</code> 加入以下參數，限制語法樹深度或停用部分 ANTLR 耗效能的檢查：</p>



<pre class="wp-block-code"><code># 限制 Fortify 對單一檔案最大解析時間（單位：秒，預設無限制，可設為 300 秒）
com.fortify.sca.PhaseTimeout=300

# 關閉部分過度深度的 AST 解析
com.fortify.sca.DisablePHP2MethodCallDataflow=true
</code></pre>



<h3 class="wp-block-heading">建議嘗試步驟：</h3>



<ol start="1" class="wp-block-list">
<li>先執行 <code>sourceanalyzer -b portal_project -clean</code> 清除快取。</li>



<li>加上限制檔案大小參數 <code>-Dcom.fortify.sca.limit.file.size=2048</code> 並修正過濾語法 <code>-exclude "**/vendor/**"</code> 重新執行。</li>
</ol>



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



<p class="wp-block-paragraph">從你提供的完整 log 可以精準定位出問題的根源所在：</p>



<p class="wp-block-paragraph">Log 在處理到 <code>SendForgotPasswordTotpApi.php</code>（或緊隨其後的下一個 PHP 檔）時，Fortify 的 <strong>PHP 語法解析器 (PHPFrontEnd)</strong> 因為遇到極長或結構極度複雜的 Heredoc / String，導致 ANTLR 語法分析器陷入計算迴圈並爆記憶體崩潰，進而拋出 <code>NullPointerException</code>。</p>



<p class="wp-block-paragraph">請採用以下 <strong>4 步驟解決方案</strong> 來繞過這個解析器的死區：</p>



<h3 class="wp-block-heading">步驟 1：強制限制單檔大小 (File Size Limit)</h3>



<p class="wp-block-paragraph">這是最快且最有效的方法。加載此參數能直接讓 Fortify <strong>跳過過大或包含巨大字串 (Heredoc/Blob) 的單一原始碼檔案</strong>，避免 ANTLR 解析器卡死。</p>



<p class="wp-block-paragraph">在 command 加入 <code>-Dcom.fortify.sca.limit.file.size=2048</code>（單位為 KB，即 2MB）：</p>



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



<pre class="wp-block-code"><code>sourceanalyzer -b portal_backend -clean

sourceanalyzer -b portal_backend -Xmx32G -Dcom.fortify.sca.limit.file.size=2048 backend/
</code></pre>



<h3 class="wp-block-heading">步驟 2：明確排除 <code>TestTools</code> 或測試/資料庫備份檔案</h3>



<p class="wp-block-paragraph">從 Log 中可以看到你的 <code>backend/</code> 下包含了 <code>TestTools</code> 與 <code>db/migrations</code>。通常測試工具與 Migration 檔中會含有大量假資料、巨型 SQL 字串或 Heredoc 模板。</p>



<p class="wp-block-paragraph">請使用 <strong>Windows 專用 Ant 通配符</strong> 將它們排除：</p>



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



<pre class="wp-block-code"><code>sourceanalyzer -b portal_backend -clean

sourceanalyzer -b portal_backend -Xmx32G -Dcom.fortify.sca.limit.file.size=2048 -exclude "**/TestTools/**" -exclude "**/db/**" -exclude "**/vendor/**" backend/
</code></pre>



<h3 class="wp-block-heading">步驟 3：定位「致命檔案」並直接單獨排除</h3>



<p class="wp-block-paragraph">如果前兩步執行後依然在 <code>SendForgotPasswordTotpApi.php</code> 附近崩潰，代表問題出在業務邏輯程式碼本身的某個特定檔案。</p>



<ol start="1" class="wp-block-list">
<li>打開 <code>SendForgotPasswordTotpApi.php</code> 以及與它在同一目錄下的前後檔案。</li>



<li>檢查程式碼中是否有使用 <code>&lt;&lt;&lt;EOD</code> &#8220;<strong>/SendForgotPasswordTotpApi.php&#8221; &#8220;</strong>/TestTools/<strong>&#8221; &#8220;</strong>/db/<strong>&#8221; &#8220;</strong>/vendor/&#8221; # ### (2048 (5分鐘)，防止 <strong>Heredoc &#8212; -Dcom.fortify.sca.limit.file.size=&#8221;2048&#8243; -Xmx32G -b -clean -exclude -f -scan / 2MB 3. 300 4：寫入 ANTLR Fortify HTML KB) Nowdoc PHP Phase Timeout，讓 <code>-exclude</code> <code>&lt;&lt;&lt;HTML</code> <code>C:\Users\max\.fortify\fortify-sca.properties</code> cmd &#8220;`properties <code>fortify-sca.properties</code> backend/ com.fortify.sca.PhaseTimeout=&#8221;300&#8243; com.fortify.sca.limit.file.size=&#8221;2048&#8243; portal_backend portal_backend_result.fpr sourceanalyzer 之類的 在檔案末端寫入以下設定： 完成上述設定後，執行以下完整的標準清洗與翻譯流程： 將它單獨排除： 建議的標準執行指令 或 找到該檔案後，直接使用 檔案也發生 步驟 無限迴圈 秒 若要避免以後其他 解析單一檔案逾時自動跳過，而不是直接崩潰： 設定全域超時（終極防護） 設定單一階段解析超時為 語法</strong>，且裡面放了極長的 語法卡死，直接開啟 請開啟以下檔案（若沒有請自行建立）： 資料或密碼學金鑰/雜湊值。 郵件模板、JSON 限制單一檔案解析上限></li>
</ol>



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



<p class="wp-block-paragraph">這個檔案 (<code>SendForgotPasswordTotpApi.php</code>) <strong>正是導致 Fortify ANTLR 語法分析器崩潰爆記憶體的元凶</strong>。</p>



<h3 class="wp-block-heading">為什麼是這個檔案？</h3>



<ol start="1" class="wp-block-list">
<li><strong>使用了巨大的 <code>Heredoc</code> (<code>$htmlBody = &lt;&lt;&lt;EOD ### #### $htmlBody="str_replace('{$totpCode}'," $htmlTemplate="file_get_contents($templatePath);" $htmlTemplate); $templatePath="__DIR__" $totpCode, '/../../templates/emails/forgot_password_totp.html'; (Inline) (圖案樣式)、HTML **ANTLR **修改後的 --- . ... / // 2. 25.2 &lt;&lt;&lt;EOD A：重構此 Base64 CSS、內嵌 Data EOD; EOD;</code>)</strong>： Fortify GC HTML Heredoc PHP SVG URI <code>$htmlBody</code><code>$textBody</code><code>.blade.php</code><code>.html</code><code>Heredoc</code><code>PHPLexerBase</code><code>PHPParser.hereDocPart</code><code>\</code>、雙引號、SVG php <code>java.lang.OutOfMemoryError: exceeded</code>。 limit overhead 使用的 使用簡單的字串替換填入動態變數 在處理包含複雜字元（如反斜線 字串。 將 將原本巨大的 抽離至獨立的 方案 時，內部的詞法狀態轉換會陷入計算遞迴，進而導致 替換為讀取外部模板檔案： 標籤的巨型 模板抽離，這同時也能讓你的程式碼結構更乾淨。 模板檔案中，改用檔案讀取方式載入： 檔案（最推薦，一勞永逸） 的 的內聯 程式碼： 與 解析器缺陷： 解決方案：重構此檔案（推薦）或針對性排除 語法）的長 這個檔案裡包含了一整段包含 這有兩種解決方式，<strong>最根本的方法是重構程式碼</strong>，將> <strong>優勢</strong>：抽離後 Fortify 解析這個 <code>.php</code> 時就不會觸發 Heredoc 的 ANTLR 解析 Bug，掃描能順利通過，且不會遺漏該 API 的安全弱點分析！</li>
</ol>



<h4 class="wp-block-heading">方案 B：單獨排除此檔案（最快）</h4>



<p class="wp-block-paragraph">如果你目前不想改動原始碼，可以在執行命令時，直接將該檔案單獨排除掉：</p>



<pre class="wp-block-code"><code>sourceanalyzer -b portal_backend -clean

sourceanalyzer -b portal_backend -Xmx16G -Dcom.fortify.sca.limit.file.size=2048 -exclude "**/SendForgotPasswordTotpApi.php" -exclude "**/TestTools/**" -exclude "**/db/**" -exclude "**/vendor/**" backend/
</code></pre>



<h4 class="wp-block-heading">方案 C：將檔案大小限制調低</h4>



<p class="wp-block-paragraph">因為這個 <code>.php</code> 檔案因為包含巨型 HTML，檔案大小可能較大。你可以嘗試將檔案限制從 <code>2048</code> (2MB) 調小到 <code>100</code> (100KB)：</p>



<pre class="wp-block-code"><code>sourceanalyzer -b portal_backend -clean

sourceanalyzer -b portal_backend -Xmx16G -Dcom.fortify.sca.limit.file.size=100 -exclude "**/vendor/**" backend/
</code></pre>



<p class="wp-block-paragraph"><em>(這樣 Fortify 會自動跳過此類包含巨型模板的過大 PHP 檔)</em></p>
]]></content:encoded>
					
					<wfw:commentRss>https://stackoverflow.max-everyday.com/2026/08/fortify-gc-overhead-limit-exceeded/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>搞定 Ubuntu 管理員大小事：清單、新增與刪除帳號</title>
		<link>https://stackoverflow.max-everyday.com/2026/08/ubuntu-admin-mangage/</link>
					<comments>https://stackoverflow.max-everyday.com/2026/08/ubuntu-admin-mangage/#respond</comments>
		
		<dc:creator><![CDATA[max-stackoverflow]]></dc:creator>
		<pubDate>Tue, 11 Aug 2026 01:59:43 +0000</pubDate>
				<category><![CDATA[電腦相關應用]]></category>
		<category><![CDATA[Ubuntu]]></category>
		<guid isPermaLink="false">https://stackoverflow.max-everyday.com/?p=8656</guid>

					<description><![CDATA[想在 Ubuntu 系統裡當個有實權的大老，或是...]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><img fetchpriority="high" decoding="async" width="1024" height="572" src="https://stackoverflow.max-everyday.com/wp-content/uploads/2026/08/ubuntu-admin-mangage3_clean-1024x572.jpg" alt="" class="wp-image-8661" srcset="https://stackoverflow.max-everyday.com/wp-content/uploads/2026/08/ubuntu-admin-mangage3_clean-1024x572.jpg?v=1786413620 1024w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/08/ubuntu-admin-mangage3_clean-600x335.jpg?v=1786413620 600w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/08/ubuntu-admin-mangage3_clean-768x429.jpg?v=1786413620 768w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/08/ubuntu-admin-mangage3_clean.jpg?v=1786413620 1376w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">想在 Ubuntu 系統裡當個有實權的大老，或是想把不安份的帳號給踢出去嗎？這篇教學帶你輕鬆掌握管理者權限的召喚與封印術！</p>



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



<h3 class="wp-block-heading">一、 尋找幕後黑手：查看誰有最高權限</h3>



<p class="wp-block-paragraph">想知道系統裡面到底有誰偷偷開了外掛、擁有 sudo 權限嗎？直接輸入下面這行指令，就能讓所有管理員現形：</p>



<p class="wp-block-paragraph">getent group sudo | cut -d: -f4</p>



<p class="wp-block-paragraph">覺得還不夠清楚嗎？這裡還有兩招進階招術：</p>



<p class="wp-block-paragraph">把系統的最高神明 root 一併召喚出來：</p>



<p class="wp-block-paragraph">echo &#8220;root&#8221;; getent group sudo | cut -d: -f4 | tr &#8216;,&#8217; &#8216;\n&#8217;</p>



<p class="wp-block-paragraph">連他們的登入 Shell 一起抓出來看個仔細：</p>



<p class="wp-block-paragraph">grep -E &#8220;$(getent group sudo | cut -d: -f4 | tr &#8216;,&#8217; &#8216;|&#8217;)&#8221; /etc/passwd</p>



<p class="wp-block-paragraph">小知識補充： Ubuntu 預設是用 sudo 群組來發放管理者權限，而不是單獨叫 admin 群組！</p>



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



<h3 class="wp-block-heading">二、 召喚新夥伴：新增帳號並給予管理權限</h3>



<p class="wp-block-paragraph">想給好朋友開個權限嗎？標準流程是先建帳號，再把他拉進 sudo 俱樂部：</p>



<p class="wp-block-paragraph">sudo adduser username</p>



<p class="wp-block-paragraph">sudo usermod -aG sudo username</p>



<p class="wp-block-paragraph">別忘了把 username 換成你朋友的帳號名稱！</p>



<p class="wp-block-paragraph">如果你趕時間，想要一鍵搞定，可以使用這套組合拳：</p>



<p class="wp-block-paragraph">sudo useradd -m -s /bin/bash -G sudo username</p>



<p class="wp-block-paragraph">sudo passwd username</p>



<p class="wp-block-paragraph">驗證身分：</p>



<p class="wp-block-paragraph">想確認他有沒有成功拿到權限，可以執行這行命令檢查：</p>



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



<p class="wp-block-paragraph">只要看到輸出裡面出現 sudo 這幾個字，就代表他已經順利晉升為管理員啦！</p>



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



<h3 class="wp-block-heading">三、 提防豬隊友：刪除使用者帳號</h3>



<p class="wp-block-paragraph">當某些帳號不再需要，或是對方惹你生氣時，你可以根據想留下的東西選一種方式處理：</p>



<ol start="1" class="wp-block-list">
<li>純粹把人踢掉（保留他的家目錄與檔案）：</li>
</ol>



<p class="wp-block-paragraph">sudo deluser username</p>



<p class="wp-block-paragraph">或者使用 sudo userdel username 。</p>



<ol start="2" class="wp-block-list">
<li>連同他的家目錄與郵件資料一併蒸發（乾淨俐落）：</li>
</ol>



<p class="wp-block-paragraph">sudo deluser &#8211;remove-home username</p>



<p class="wp-block-paragraph">或者使用 sudo userdel -r username 。</p>



<ol start="3" class="wp-block-list">
<li>地毯式搜捕（刪除他在整個系統留下的所有檔案）：</li>
</ol>



<p class="wp-block-paragraph">sudo deluser &#8211;remove-all-files username</p>



<p class="wp-block-paragraph">動手前請注意：</p>



<p class="wp-block-paragraph">刪除前請先確定 username 已經替換成目標帳號。</p>



<p class="wp-block-paragraph">如果對方還在線上頑強抵抗，請先強制幫他登出：</p>



<p class="wp-block-paragraph">sudo killall -u username</p>



<p class="wp-block-paragraph">如果只是想拔掉他的權限，讓他變回普通百姓，不需要直接刪帳號，輸入這行命令即可：</p>



<p class="wp-block-paragraph">sudo deluser username sudo</p>
]]></content:encoded>
					
					<wfw:commentRss>https://stackoverflow.max-everyday.com/2026/08/ubuntu-admin-mangage/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Windows Server 密碼最長使用期限</title>
		<link>https://stackoverflow.max-everyday.com/2026/08/windows-server-maxpwage/</link>
					<comments>https://stackoverflow.max-everyday.com/2026/08/windows-server-maxpwage/#respond</comments>
		
		<dc:creator><![CDATA[max-stackoverflow]]></dc:creator>
		<pubDate>Mon, 10 Aug 2026 05:34:05 +0000</pubDate>
				<category><![CDATA[電腦相關應用]]></category>
		<category><![CDATA[Windows]]></category>
		<guid isPermaLink="false">https://stackoverflow.max-everyday.com/?p=8652</guid>

					<description><![CDATA[資安規範與稽核標準建議將 「密碼最長使用期限」 ...]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-full"><img decoding="async" width="638" height="240" src="https://stackoverflow.max-everyday.com/wp-content/uploads/2026/08/image-1.png?v=1786340016" alt="" class="wp-image-8654" srcset="https://stackoverflow.max-everyday.com/wp-content/uploads/2026/08/image-1.png?v=1786340016 638w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/08/image-1-600x226.png?v=1786340016 600w" sizes="(max-width: 638px) 100vw, 638px" /></figure>



<p class="wp-block-paragraph">資安規範與稽核標準建議將 <strong>「密碼最長使用期限」</strong> 設定為 <strong><code>90</code> 天</strong>（約 3 個月換一次密碼）。</p>



<p class="wp-block-paragraph">在《行政院資通安全防護基準》及 ISO 27001 實務中，一般機關系統的密碼更換週期標準為 <strong>90 天～180 天</strong>（也就是 3 到 6 個月）。目前你的系統設定是 <code>120</code> 天（約 4 個月），雖然也符合規範，但修改為 <strong><code>90</code> 天</strong> 是各大稽核單位最喜愛的標準黃金值。</p>



<h3 class="wp-block-heading">如何在 PowerShell (管理員) 修改？</h3>



<p class="wp-block-paragraph">請開啟 <strong>PowerShell (以系統管理員身分執行)</strong>，執行以下指令：</p>



<h4 class="wp-block-heading">1. 設定為 90 天（推薦）：</h4>



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



<pre class="wp-block-code"><code>net accounts /MAXPWAGE:90
</code></pre>



<h4 class="wp-block-heading">2. 驗證修改結果：</h4>



<p class="wp-block-paragraph">執行以下指令確認是否生效：</p>



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



<pre class="wp-block-code"><code>net accounts
</code></pre>



<p class="wp-block-paragraph">觀察輸出中的這行：</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph"><strong>密碼最長使用期限 (天): 90</strong></p>
</blockquote>



<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;" /> 補充說明（完整密碼原則組合建議）</h3>



<p class="wp-block-paragraph">修改完成後，你的 Windows Server 2019 密碼原則組合將會非常完美且完全符合資安稽核：</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><td><strong>項目</strong></td><td><strong>你的設定值</strong></td><td><strong>稽核標準與備註</strong></td></tr></thead><tbody><tr><td><strong>密碼長度下限</strong></td><td><strong>13</strong> 字元</td><td>符合 $\ge 12$ 或 $13$ 字元標準</td></tr><tr><td><strong>密碼最長使用期限</strong></td><td><strong>90</strong> 天</td><td>符合 90~180 天標準，每 3 個月更換</td></tr><tr><td><strong>歷程記錄長度</strong></td><td><strong>3</strong> 次</td><td>符合「不可與前 3 次相同」</td></tr><tr><td><strong>帳戶鎖定閾值</strong></td><td><strong>5</strong> 次</td><td>失敗 5 次即鎖定</td></tr><tr><td><strong>鎖定持續期間</strong></td><td><strong>15</strong> 分鐘</td><td>鎖定 15 分鐘（防暴力破解）</td></tr></tbody></table></figure>
]]></content:encoded>
					
					<wfw:commentRss>https://stackoverflow.max-everyday.com/2026/08/windows-server-maxpwage/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Windows Server 密碼變更時，至少不可以與前3次使用過之密碼相同</title>
		<link>https://stackoverflow.max-everyday.com/2026/08/windows-server-uniquepw/</link>
					<comments>https://stackoverflow.max-everyday.com/2026/08/windows-server-uniquepw/#respond</comments>
		
		<dc:creator><![CDATA[max-stackoverflow]]></dc:creator>
		<pubDate>Mon, 10 Aug 2026 05:28:55 +0000</pubDate>
				<category><![CDATA[電腦相關應用]]></category>
		<category><![CDATA[Windows]]></category>
		<guid isPermaLink="false">https://stackoverflow.max-everyday.com/?p=8649</guid>

					<description><![CDATA[這是因為繁體中文版 Windows 的 net ...]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-full"><img decoding="async" width="641" height="238" src="https://stackoverflow.max-everyday.com/wp-content/uploads/2026/08/image.png?v=1786339647" alt="" class="wp-image-8650" srcset="https://stackoverflow.max-everyday.com/wp-content/uploads/2026/08/image.png?v=1786339647 641w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/08/image-600x223.png?v=1786339647 600w" sizes="(max-width: 641px) 100vw, 641px" /></figure>



<p class="wp-block-paragraph">這是因為繁體中文版 Windows 的 <code>net accounts</code> 指令參數名稱是 <strong>/UNIQUEPW:3</strong>（英文版才是 <code>/UNIQUEPW</code> 或 <code>/UNIQUENESS</code>）。</p>



<p class="wp-block-paragraph">請在 <strong>PowerShell (系統管理員)</strong> 中直接執行以下這行指令：</p>



<pre class="wp-block-code"><code>net accounts /UNIQUEPW:3
</code></pre>



<h3 class="wp-block-heading">執行後驗證</h3>



<p class="wp-block-paragraph">執行完畢後，再次輸入：</p>



<pre class="wp-block-code"><code>net accounts
</code></pre>



<p class="wp-block-paragraph">確認結果顯示為：</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph"><strong>密碼維護的歷程記錄長度： 3</strong></p>
</blockquote>



<p class="wp-block-paragraph">這樣就順利修改完成，可以直接在表單的「密碼變更時，至少不可以與前3次使用過之密碼相同」勾選 <strong>「是」</strong> 了！</p>



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



<h3 class="wp-block-heading">如何在 Windows Server 設定與確認？</h3>



<p class="wp-block-paragraph">如果你需要確保系統確實設定為「不能與前 3 次相同」，請依照以下步驟調整：</p>



<p class="wp-block-paragraph"><strong>1.開啟本機資安原則：</strong></p>



<p class="wp-block-paragraph">按下 <code>Win + R</code> 開啟「執行」視窗，輸入 <code>secpol.msc</code> 並按下 <strong>Enter</strong>。</p>



<p class="wp-block-paragraph"><strong>2.找到密碼歷史紀錄設定：</strong></p>



<p class="wp-block-paragraph">在左側選單點擊：<strong>帳戶原則</strong>（<code>Account Policies</code>） ➔ <strong>密碼原則</strong>（<code>Password Policy</code>）。</p>



<p class="wp-block-paragraph"><strong>3.修改強制保留密碼歷史記錄：</strong></p>



<p class="wp-block-paragraph">雙擊右側的 <strong>「強制保留密碼歷史記錄」</strong>（<code>Enforce password history</code>），將數值改為 <strong><code>3</code></strong>（或更大，例如標準常設為 <code>3</code> 或 <code>5</code>），點擊 <strong>確定</strong>。</p>



<p class="wp-block-paragraph"><strong>4.強制更新資安原則：</strong></p>



<p class="wp-block-paragraph">開啟 PowerShell（管理員身分），輸入 <code>gpupdate /force</code> 讓設定立即生效。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://stackoverflow.max-everyday.com/2026/08/windows-server-uniquepw/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>更改 Windows Server 密碼長度至少 N 個字元</title>
		<link>https://stackoverflow.max-everyday.com/2026/08/windows-server-min-pwd-length/</link>
					<comments>https://stackoverflow.max-everyday.com/2026/08/windows-server-min-pwd-length/#respond</comments>
		
		<dc:creator><![CDATA[max-stackoverflow]]></dc:creator>
		<pubDate>Mon, 10 Aug 2026 05:20:12 +0000</pubDate>
				<category><![CDATA[電腦相關應用]]></category>
		<category><![CDATA[Windows]]></category>
		<guid isPermaLink="false">https://stackoverflow.max-everyday.com/?p=8645</guid>

					<description><![CDATA[說明, 使用 net accounts 看到, ...]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="881" height="609" src="https://stackoverflow.max-everyday.com/wp-content/uploads/2026/08/mstsc_2026-08-10-13-16-hc.jpg?v=1786339126" alt="" class="wp-image-8647" srcset="https://stackoverflow.max-everyday.com/wp-content/uploads/2026/08/mstsc_2026-08-10-13-16-hc.jpg?v=1786339126 881w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/08/mstsc_2026-08-10-13-16-hc-600x415.jpg?v=1786339126 600w, https://stackoverflow.max-everyday.com/wp-content/uploads/2026/08/mstsc_2026-08-10-13-16-hc-768x531.jpg?v=1786339126 768w" sizes="auto, (max-width: 881px) 100vw, 881px" /></figure>



<p class="wp-block-paragraph">說明, 使用 net accounts 看到, 修改前是最少10碼, 修改之後最少 13碼。</p>



<p class="wp-block-paragraph">要在 Windows Server 2019 設定<strong>密碼長度至少 13 個字元</strong>，你需要修改群組原則中的「密碼最短長度」。</p>



<p class="wp-block-paragraph">依照以下步驟調整即可：</p>



<h3 class="wp-block-heading">方法一：使用圖形介面 (GUI) 修改</h3>



<p class="wp-block-paragraph"><strong>1.開啟本機資安原則：</strong></p>



<p class="wp-block-paragraph">按下快捷鍵 <code>Win + R</code> 開起「執行」視窗，輸入 <code>secpol.msc</code> 並按下 <strong>Enter</strong>。</p>



<p class="wp-block-paragraph"><strong>2.找到密碼原則：</strong></p>



<p class="wp-block-paragraph">在左側選單依序展開：</p>



<p class="wp-block-paragraph"><strong>機關資安設定</strong>（或 <code>安全性設定</code>） ➔ <strong>帳戶原則</strong>（<code>Account Policies</code>） ➔ <strong>密碼原則</strong>（<code>Password Policy</code>）。</p>



<p class="wp-block-paragraph"><strong>3.修改密碼最短長度：</strong></p>



<p class="wp-block-paragraph">在右側視窗點擊兩下開啟 <strong>「密碼最短長度」</strong>（<code>Minimum password length</code>）。</p>



<p class="wp-block-paragraph">將原本的 <code>10</code> 改為 <strong><code>13</code></strong>（或更多字元），然後點擊 <strong>確定</strong>。</p>



<p class="wp-block-paragraph"><strong>4.強制更新原則：</strong></p>



<p class="wp-block-paragraph">開啟 PowerShell 或 CMD（管理員權限），輸入 <code>gpupdate /force</code> 讓新原則立即生效。</p>



<h3 class="wp-block-heading">方法二：使用 PowerShell 快速修改</h3>



<p class="wp-block-paragraph">如果你習慣用 command line 操作，可以開啟 <strong>PowerShell (以系統管理員身分執行)</strong>，複製並執行以下指令：</p>



<pre class="wp-block-code"><code># 1. 將目前的安全性原則匯出至暫存檔
secedit /export /cfg C:\secpol.cfg

# 2. 將密碼最短長度從原本的數值改為 13
(Get-Content C:\secpol.cfg) -replace 'MinimumPasswordLength = \d+', 'MinimumPasswordLength = 13' | Set-Content C:\secpol.cfg

# 3. 重新套用設定檔
secedit /configure /db $env:windir\security\local.sdb /cfg C:\secpol.cfg /areas SECURITYPOLICY

# 4. 清除暫存檔
Remove-Item C:\secpol.cfg
</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;" /> 驗證是否修改成功</h3>



<p class="wp-block-paragraph">執行以下 PowerShell 指令確認設定是否成功生效：</p>



<pre class="wp-block-code"><code>net accounts
</code></pre>



<p class="wp-block-paragraph">觀察輸出結果中的 <strong>「密碼最短長度」 (Minimum password length)</strong> 是否已經變更為 <strong><code>13</code></strong>。</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph"><strong>補充說明（AD 網域環境）：</strong></p>



<p class="wp-block-paragraph">如果你的 Windows Server 有加入 <strong>Active Directory (AD) 網域</strong>，且密碼原則是由網域控制站 (DC) 統一管理的，請前往網域控制站開啟 <code>gpmc.msc</code> (群組原則管理)，並在 <strong>Default Domain Policy</strong> 中修改相同的項目。</p>
</blockquote>
]]></content:encoded>
					
					<wfw:commentRss>https://stackoverflow.max-everyday.com/2026/08/windows-server-min-pwd-length/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>PHP 8.3 報錯排查：無法載入動態函式庫 php_xmlrpc.dll / php_gd2.dll 解決方案</title>
		<link>https://stackoverflow.max-everyday.com/2026/08/php_xmlrpc-php_gd2/</link>
					<comments>https://stackoverflow.max-everyday.com/2026/08/php_xmlrpc-php_gd2/#respond</comments>
		
		<dc:creator><![CDATA[max-stackoverflow]]></dc:creator>
		<pubDate>Mon, 03 Aug 2026 07:41:00 +0000</pubDate>
				<category><![CDATA[電腦相關應用]]></category>
		<category><![CDATA[php]]></category>
		<guid isPermaLink="false">https://stackoverflow.max-everyday.com/?p=8642</guid>

					<description><![CDATA[將 PHP 升級至 8.0 以上版本（例如 PH...]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">將 PHP 升級至 8.0 以上版本（例如 PHP 8.3）後，執行或啟動伺服器時可能會遇到類似以下的警告訊息：</p>



<pre class="wp-block-code"><code>PHP Warning: PHP Startup: Unable to load dynamic library 'php_xmlrpc.dll' (tried: C:\Program Files\PHP\v8.3\ext\php_xmlrpc.dll (找不到指定的模組。), C:\Program Files\PHP\v8.3\ext\php_php_xmlrpc.dll.dll (找不到指定的模組。)) in Unknown on line 0</code></pre>



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



<h3 class="wp-block-heading">原因分析</h3>



<p class="wp-block-paragraph">此錯誤通常源自以下兩個主要原因：</p>



<ol start="1" class="wp-block-list">
<li><strong>擴充套件（Extension）命名規則變更</strong>在舊版 PHP（PHP 7.x 及更早版本）中，設定檔常寫為 <code>extension=php_gd2.dll</code> 或帶有 <code>php_</code> 前綴。從 <strong>PHP 8.0</strong> 開始，官方簡化了指定方式，只需填寫擴充套件簡稱（例如 <code>extension=gd</code>）。若仍使用舊式檔名，PHP 在自動補充路徑時會產生如 <code>php_php_...dll.dll</code> 的重複路徑而找不到檔案。</li>



<li><strong>部分舊版擴充套件已被移除（以 XMLRPC 為例）</strong><code>xmlrpc</code> 擴充套件已於 PHP 8.0 起從核心移除並移至 PECL。因此 PHP 8.3 預設的 <code>ext/</code> 目錄下已不再提供 <code>php_xmlrpc.dll</code>。</li>
</ol>



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



<h3 class="wp-block-heading">解決步驟</h3>



<h4 class="wp-block-heading">步驟 1：開啟 <code>php.ini</code> 設定檔</h4>



<p class="wp-block-paragraph">找到目前 PHP 8.3 環境所使用的 <code>php.ini</code> 檔案（例如：<code>C:\Program Files\PHP\v8.3\php.ini</code>）。</p>



<h4 class="wp-block-heading">步驟 2：修正或停用問題擴充套件</h4>



<p class="wp-block-paragraph">以系統管理員權限開啟 <code>php.ini</code>：</p>



<p class="wp-block-paragraph"><strong>若為舊版命名格式問題（如 GD 繪圖庫）：</strong>搜尋 <code>gd</code>，將舊式的設定修正為新版標準格式：</p>



<p class="wp-block-paragraph"><code>舊寫法：</code></p>



<pre class="wp-block-code"><code><code>extension=php_gd2.dll</code></code></pre>



<p class="wp-block-paragraph"><code>請改為： </code></p>



<pre class="wp-block-code"><code><code>extension=gd</code></code></pre>



<p class="wp-block-paragraph"><strong>若為已移出核心的擴充套件（如 XMLRPC）：</strong></p>



<p class="wp-block-paragraph">搜尋 <code>xmlrpc</code>，若無特殊需要，直接在行首加上分號 <code>;</code> 將其註解停用：</p>



<pre class="wp-block-code"><code>;extension=php_xmlrpc.dll 
;extension=xmlrpc</code></pre>



<h4 class="wp-block-heading">步驟 3：確認擴充套件目錄 (<code>extension_dir</code>)</h4>



<p class="wp-block-paragraph">確認 <code>php.ini</code> 中的 <code>extension_dir</code> 指令已正確啟用並指向正確路徑：</p>



<pre class="wp-block-code"><code>extension_dir = "ext"
</code></pre>



<p class="wp-block-paragraph"><em>(或使用絕對路徑：<code>extension_dir = "C:\Program Files\PHP\v8.3\ext"</code>)</em></p>



<h4 class="wp-block-heading">步骤 4：重啟 Web 伺服器 / PHP 服務</h4>



<p class="wp-block-paragraph">儲存 <code>php.ini</code> 後，重啟 Apache、Nginx、IIS 或重開 PHP CLI 環境，以使新的設定生效。</p>



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



<p class="wp-block-paragraph">The PHP startup warnings require &nbsp;php.ini&nbsp; cleanup:</p>



<pre class="wp-block-code"><code>date.timezone = Asia/Taipei<br>extension=gd</code></pre>



<p class="wp-block-paragraph">Remove duplicate entries for &nbsp;curl&nbsp;, &nbsp;mysqli&nbsp;, &nbsp;mbstring&nbsp;, &nbsp;openssl&nbsp;, &nbsp;ldap&nbsp;, and &nbsp;pdo_mysql&nbsp;.</p>



<p class="wp-block-paragraph">Also remove or install matching extensions:</p>



<ul class="wp-block-list">
<li> xmlrpc : unavailable in standard PHP 8.3; comment it out unless separately installed.</li>



<li> pdo_sqlsrv_82_nts_x64 : replace with the PHP 8.3 NTS x64 driver, or remove it if unused.</li>
</ul>



<p class="wp-block-paragraph">Do not suppress these with &nbsp;error_reporting(0)&nbsp;; correcting &nbsp;php.ini&nbsp; will eliminate the startup log noise</p>



<p class="wp-block-paragraph"></p>
]]></content:encoded>
					
					<wfw:commentRss>https://stackoverflow.max-everyday.com/2026/08/php_xmlrpc-php_gd2/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<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 loading="lazy" 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="auto, (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 loading="lazy" 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="auto, (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 loading="lazy" 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="auto, (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>
	</channel>
</rss>
